Merge lp:~gandelman-a/charms/precise/nova-cloud-controller/https_endpoint into lp:~openstack-charmers/charms/precise/nova-cloud-controller/ha-support

Proposed by Adam Gandelman
Status: Merged
Merged at revision: 64
Proposed branch: lp:~gandelman-a/charms/precise/nova-cloud-controller/https_endpoint
Merge into: lp:~openstack-charmers/charms/precise/nova-cloud-controller/ha-support
Diff against target: 903 lines (+467/-102)
5 files modified
config.yaml (+10/-0)
hooks/lib/openstack-common (+219/-18)
hooks/nova-cloud-controller-common (+71/-0)
hooks/nova-cloud-controller-relations (+166/-83)
revision (+1/-1)
To merge this branch: bzr merge lp:~gandelman-a/charms/precise/nova-cloud-controller/https_endpoint
Reviewer Review Type Date Requested Status
James Page Needs Fixing
Review via email: mp+150387@code.launchpad.net

Description of the change

nova-c-c HTTPS API support. These changes (and also those applied to the other chnages in similar merge proposals) allows the charm to dynamically manage the API listening port for each server depending on the current deployment. The canonical port in the Keystone catalog will always be the default (eg 8443) but the request pipeline on the API server differs depending on how it is deployed:

- When deployed in a single, non-https unit, the API server(s) will listen on their defualt port (eg, 8773)
- When new peers join, haproxy will be configured on every node to listen on the default port, with the local API server listening on $DEFAULT-10 (8773 -> 8763).
- When HTTPS is enabled and peers have joined, Apache is configured to terminate SSL on the default port and route requests to the local haproxy, then to the API server (8773 apache -> 8763 haproxy -> 8752 nova api).
- When HTTPS is enabled but no peers have joined, Apache terminates SSL on default port and routes requeusts directly to the API server (8773 -> 8763)

The same approach is used in the other HTTPS charms.

SSL certs are created and signed on the keystone side (when it is configured to do so) along with standard endpoint creation. An SSL cert, key and CA cert are returned to the unit along with its service credentials. Currently, nova-c-c will make a copy of the CA cert accessible to outside users at its web root.

This also adds a lot of general HA support that was committed to other charms but not to the nova-c-c (eligible_leader, etc).

To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

A few bits and pieces:

nova-cloud-controller-relations:ha_joined

Clones should be set to clones, not groups

775 - init_services="$init_services" groups="$groups"
776 + init_services="$init_services" clones="$groups"

nova-cloud-controller-relations:quantum_joined

I think the CA cert should be passed to quantum as well so it can talk back to the https server.

Revision history for this message
James Page (james-page) wrote :
Download full text (6.3 KiB)

I was able to get most of the https stuff working; two issues

1) Setting the config on keystone for https after building the environment configured endpoints in most places; however nova-cloud-controller did not reconfigure.

2) nova image-list post remove/add to fix the above resulted in:

2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack Traceback (most recent call last):
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/nova/api/openstack/__init__.py", line 81, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return req.get_response(self.application)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/request.py", line 1296, in send
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack application, catch_exc_info=False)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/request.py", line 1260, in call_application
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack app_iter = application(self.environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 144, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return resp(environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/keystoneclient/middleware/auth_token.py", line 328, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return self.app(env, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 144, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return resp(environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 144, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return resp(environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 144, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return resp(environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/routes/middleware.py", line 131, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack response = self.app(environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 144, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return resp(environ, start_response)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 130, in __call__
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack resp = self.call_func(req, *args, **self.kwargs)
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack File "/usr/lib/python2.7/dist-packages/webob/dec.py", line 195, in call_func
2013-02-26 07:50:41.481 1056 TRACE nova.api.openstack return self.func(req, *ar...

Read more...

Revision history for this message
James Page (james-page) :
review: Needs Fixing
75. By Adam Gandelman

Actually send clone config to hacluster.

76. By Adam Gandelman

Send CA cert to quantum via quantum_joined, if it exists then.

77. By Adam Gandelman

Retrigger quantum_joined post-SSL.

78. By Adam Gandelman

Bump revision.

Revision history for this message
Adam Gandelman (gandelman-a) wrote :
Download full text (3.4 KiB)

I'm having a helluva time reproducing this issue. Can you describe how you initial built your environment before enabling HTTPS? Was nova-c-c peered and/or clustered? Are you sure you were deploying the most recent charm revision /w newest branch changes? bzr revs 71 and 72 dealt with an issue of the endpoint not reconfiguring after adding clustering, since the original reconfig hooks were not sending all required settings. Late-enabling HTTPS should be limited to identity-changed, though.

I've just tested again by enabling HTTPS after the entire catalog has been populated by haclustererd services (all endpoints pointing to http://$VIP/etc/). After nova-c-c has reconfigured its reverse proxying, it flushes the following settings back to KS, compute and quantum:

2013-02-27 15:09:31,482: hook.output@DEBUG: Flushed values for hook 'identity-service-relation-changed' on 'identity-service:27'
    Setting changed: 'ec2_admin_url'=u'https://192.168.77.2:8773/services/Cloud' (was 'http://192.168.77.2:8773/services/Cloud')
    Setting changed: 'ec2_internal_url'=u'https://192.168.77.2:8773/services/Cloud' (was 'http://192.168.77.2:8773/services/Cloud')
    Setting changed: 'ec2_public_url'=u'https://192.168.77.2:8773/services/Cloud' (was 'http://192.168.77.2:8773/services/Cloud')
    Setting changed: 'nova_admin_url'=u'https://192.168.77.2:8774/v1.1/$(tenant_id)s' (was 'http://192.168.77.2:8774/v1.1/$(tenant_id)s')
    Setting changed: 'nova_internal_url'=u'https://192.168.77.2:8774/v1.1/$(tenant_id)s' (was 'http://192.168.77.2:8774/v1.1/$(tenant_id)s')
    Setting changed: 'nova_public_url'=u'https://192.168.77.2:8774/v1.1/$(tenant_id)s' (was 'http://192.168.77.2:8774/v1.1/$(tenant_id)s')
    Setting changed: 'quantum_admin_url'=u'https://192.168.77.2:9696' (was 'http://192.168.77.2:9696')
    Setting changed: 'quantum_internal_url'=u'https://192.168.77.2:9696' (was 'http://192.168.77.2:9696')
    Setting changed: 'quantum_public_url'=u'https://192.168.77.2:9696' (was 'http://192.168.77.2:9696')
    Setting changed: 's3_admin_url'=u'https://192.168.77.2:3333' (was 'http://192.168.77.2:3333')
    Setting changed: 's3_internal_url'=u'https://192.168.77.2:3333' (was 'http://192.168.77.2:3333')
    Setting changed: 's3_public_url'=u'https://192.168.77.2:3333' (was 'http://192.168.77.2:3333')
    Setting changed: u'ca_cert'=u'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvekNDQWd5Z0F3SUJBZ0lCQVRBTkJna3Fo\na2lHOXcwQkFRVUZBREJy (was unset) on 'cloud-compute:47'
    Setting changed: 'quantum_url'=u'https://192.168.77.2:9696' (was 'http://192.168.77.2:9696') on 'cloud-compute:47'
    Setting changed: u'ca_cert'=u'LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNvekNDQWd5Z0F3SUJBZ0lCQVRBTkJna3Fo\na2lHOXcwQkFRVUZBREJy (was unset) on 'quantum-network-service:40'
    Setting changed: 'quantum_url'=u'https://192.168.77.2:9696' (was 'http://192.168.77.2:9696') on 'quantum-network-service:40'
2013-02-27 15:09:31,483: hook.executor@DEBUG: Hook complete: /var/lib/juju/units/nova-cloud-controller-
2/charm/hooks/identity-service-relation-changed

If you can test once again, and possibly keep an eye on the nova-c-c leader's charm log, to see what settings change? The r...

Read more...

79. By Adam Gandelman

Rebase against current ha-support branch.

80. By Adam Gandelman

Block configure_qunatum_networking if no amqp relation exists.

81. By Adam Gandelman

Avoid race between https + quantum network setup.

using https() in keystone_joined() is not reliable with multiple
KS peers. Only inspect local config and count on https() only from
_changed() hooks.

82. By Adam Gandelman

Bump rev.

83. By Adam Gandelman

Only configurate quantum net. from keystone-changed when safe.

They ks catalog may be in a state of flux when these hooks fire.

If firing for the first time, configure quantum networking before
https frontend is setup, and before KS endpoint is reconfigured to
point to https.

If firing as the result of HA reconfiguration, configure quantum
after HTTPS has been updated to include updated certificate (for VIP
address).

84. By Adam Gandelman

keystone_changed: Protect late quantum config by an eligible_leader check.

85. By Adam Gandelman

Also protect early call to quantum config.

86. By Adam Gandelman

keystone_changed: Also determine HTTPS based on actual hook being fired.

87. By Adam Gandelman

Be careful of 'set -e'.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'config.yaml'
2--- config.yaml 2013-01-22 16:43:49 +0000
3+++ config.yaml 2013-03-09 04:30:28 +0000
4@@ -128,3 +128,13 @@
5 description: |
6 Default multicast port number that will be used to communicate between
7 HA Cluster nodes.
8+ ssl_cert:
9+ type: string
10+ description: |
11+ SSL certificate to install and use for API ports. Setting this value
12+ and ssl_key will enable reverse proxying, point Glance's entry in the
13+ Keystone catalog to use https, and override any certficiate and key
14+ issued by Keystone (if it is configured to do so).
15+ ssl_key:
16+ type: string
17+ description: SSL key to use with certificate specified as ssl_cert.
18
19=== added symlink 'hooks/cluster-relation-changed'
20=== target is u'nova-cloud-controller-relations'
21=== added symlink 'hooks/cluster-relation-departed'
22=== target is u'nova-cloud-controller-relations'
23=== added symlink 'hooks/ha-relation-changed'
24=== target is u'nova-cloud-controller-relations'
25=== added symlink 'hooks/ha-relation-joined'
26=== target is u'nova-cloud-controller-relations'
27=== modified file 'hooks/lib/openstack-common'
28--- hooks/lib/openstack-common 2013-03-08 21:18:29 +0000
29+++ hooks/lib/openstack-common 2013-03-09 04:30:28 +0000
30@@ -321,7 +321,6 @@
31
32 HAPROXY_CFG=/etc/haproxy/haproxy.cfg
33 HAPROXY_DEFAULT=/etc/default/haproxy
34-
35 ##########################################################################
36 # Description: Configures HAProxy services for Openstack API's
37 # Parameters:
38@@ -330,9 +329,8 @@
39 # assumes the name of the peer relation is 'cluster' and that every
40 # service unit in the peer relation is running the same services.
41 #
42-# The HAProxy service will listen on port + 10000.
43-# Example:
44-# configure_haproxy cinder_api:12345 nova_api:9999
45+# Example
46+# configure_haproxy cinder_api:8776:8756i nova_api:8774:8764
47 ##########################################################################
48 configure_haproxy() {
49 local address=`unit-get private-address`
50@@ -368,14 +366,18 @@
51 EOF
52 for service in $@; do
53 local service_name=$(echo $service | cut -d : -f 1)
54- local api_listen_port=$(echo $service | cut -d : -f 2)
55- local haproxy_listen_port=$(($api_listen_port + 10000))
56+ local haproxy_listen_port=$(echo $service | cut -d : -f 2)
57+ local api_listen_port=$(echo $service | cut -d : -f 3)
58+ juju-log "Adding haproxy configuration entry for $service "\
59+ "($haproxy_listen_port -> $api_listen_port)"
60 cat >> $HAPROXY_CFG << EOF
61 listen $service_name 0.0.0.0:$haproxy_listen_port
62 balance roundrobin
63 option tcplog
64 server $name $address:$api_listen_port check
65 EOF
66+ local r_id=""
67+ local unit=""
68 for r_id in `relation-ids cluster`; do
69 for unit in `relation-list -r $r_id`; do
70 local unit_name=${unit////-}
71@@ -388,6 +390,7 @@
72 done
73 done
74 echo "ENABLED=1" > $HAPROXY_DEFAULT
75+ service haproxy restart
76 }
77
78 ##########################################################################
79@@ -395,18 +398,20 @@
80 # Returns: 0 if configured, 1 if not configured
81 ##########################################################################
82 is_clustered() {
83+ local r_id=""
84+ local unit=""
85 for r_id in $(relation-ids ha); do
86 if [ -n "$r_id" ]; then
87 for unit in $(relation-list -r $r_id); do
88 clustered=$(relation-get -r $r_id clustered $unit)
89 if [ -n "$clustered" ]; then
90- echo "Unit is clustered"
91+ juju-log "Unit is haclustered"
92 return 0
93 fi
94 done
95 fi
96 done
97- echo "Unit is not clustered"
98+ juju-log "Unit is not haclustered"
99 return 1
100 }
101
102@@ -415,6 +420,7 @@
103 ##########################################################################
104 peer_units() {
105 local peers=""
106+ local r_id=""
107 for r_id in $(relation-ids cluster); do
108 peers="$peers $(relation-list -r $r_id)"
109 done
110@@ -433,11 +439,11 @@
111 echo "Comparing $JUJU_UNIT_NAME with peers: $peers"
112 local r_unit_no=$(echo $peer | cut -d / -f 2)
113 if (($r_unit_no<$l_unit_no)); then
114- echo "Not oldest peer; deferring"
115+ juju-log "Not oldest peer; deferring"
116 return 1
117 fi
118 done
119- echo "Oldest peer; might take charge?"
120+ juju-log "Oldest peer; might take charge?"
121 return 0
122 }
123
124@@ -451,13 +457,13 @@
125 eligible_leader() {
126 if is_clustered; then
127 if ! is_leader $1; then
128- echo 'Deferring action to CRM leader'
129+ juju-log 'Deferring action to CRM leader'
130 return 1
131 fi
132 else
133 peers=$(peer_units)
134 if [ -n "$peers" ] && ! oldest_peer "$peers"; then
135- echo 'Deferring action to oldest service unit.'
136+ juju-log 'Deferring action to oldest service unit.'
137 return 1
138 fi
139 fi
140@@ -469,14 +475,14 @@
141 # Returns: 0 if peered, 1 if not peered
142 ##########################################################################
143 is_peered() {
144- r_id=$(relation-ids cluster)
145+ local r_id=$(relation-ids cluster)
146 if [ -n "$r_id" ]; then
147 if [ -n "$(relation-list -r $r_id)" ]; then
148- echo "Unit peered"
149+ juju-log "Unit peered"
150 return 0
151 fi
152 fi
153- echo "Unit not peered"
154+ juju-log "Unit not peered"
155 return 1
156 }
157
158@@ -489,12 +495,207 @@
159 hostname=`hostname`
160 if [ -x /usr/sbin/crm ]; then
161 if crm resource show $1 | grep -q $hostname; then
162- echo "$hostname is cluster leader"
163+ juju-log "$hostname is cluster leader."
164 return 0
165 fi
166 fi
167- echo "$hostname is not cluster leader"
168- return 1
169+ juju-log "$hostname is not cluster leader."
170+ return 1
171+}
172+
173+##########################################################################
174+# Description: Determines whether enough data has been provided in
175+# configuration or relation data to configure HTTPS.
176+# Parameters: None
177+# Returns: 0 if HTTPS can be configured, 1 if not.
178+##########################################################################
179+https() {
180+ local r_id=""
181+ if [[ -n "$(config-get ssl_cert)" ]] &&
182+ [[ -n "$(config-get ssl_key)" ]] ; then
183+ return 0
184+ fi
185+ for r_id in $(relation-ids identity-service) ; do
186+ for unit in $(relation-list -r $r_id) ; do
187+ if [[ "$(relation-get -r $r_id https_keystone $unit)" == "True" ]] &&
188+ [[ -n "$(relation-get -r $r_id ssl_cert $unit)" ]] &&
189+ [[ -n "$(relation-get -r $r_id ssl_key $unit)" ]] &&
190+ [[ -n "$(relation-get -r $r_id ca_cert $unit)" ]] ; then
191+ return 0
192+ fi
193+ done
194+ done
195+ return 1
196+}
197+
198+##########################################################################
199+# Description: For a given number of port mappings, configures apache2
200+# HTTPs local reverse proxying using certficates and keys provided in
201+# either configuration data (preferred) or relation data. Assumes ports
202+# are not in use (calling charm should ensure that).
203+# Parameters: Variable number of proxy port mappings as
204+# $internal:$external.
205+# Returns: 0 if reverse proxy(s) have been configured, 0 if not.
206+##########################################################################
207+enable_https() {
208+ local port_maps="$@"
209+ local http_restart=""
210+ juju-log "Enabling HTTPS for port mappings: $port_maps."
211+
212+ # allow overriding of keystone provided certs with those set manually
213+ # in config.
214+ local cert=$(config-get ssl_cert)
215+ local key=$(config-get ssl_key)
216+ local ca_cert=""
217+ if [[ -z "$cert" ]] || [[ -z "$key" ]] ; then
218+ juju-log "Inspecting identity-service relations for SSL certificate."
219+ local r_id=""
220+ cert=""
221+ key=""
222+ ca_cert=""
223+ for r_id in $(relation-ids identity-service) ; do
224+ for unit in $(relation-list -r $r_id) ; do
225+ [[ -z "$cert" ]] && cert="$(relation-get -r $r_id ssl_cert $unit)"
226+ [[ -z "$key" ]] && key="$(relation-get -r $r_id ssl_key $unit)"
227+ [[ -z "$ca_cert" ]] && ca_cert="$(relation-get -r $r_id ca_cert $unit)"
228+ done
229+ done
230+ [[ -n "$cert" ]] && cert=$(echo $cert | base64 -di)
231+ [[ -n "$key" ]] && key=$(echo $key | base64 -di)
232+ [[ -n "$ca_cert" ]] && ca_cert=$(echo $ca_cert | base64 -di)
233+ else
234+ juju-log "Using SSL certificate provided in service config."
235+ fi
236+
237+ [[ -z "$cert" ]] || [[ -z "$key" ]] &&
238+ juju-log "Expected but could not find SSL certificate data, not "\
239+ "configuring HTTPS!" && return 1
240+
241+ apt-get -y install apache2
242+ a2enmod ssl proxy proxy_http | grep -v "To activate the new configuration" &&
243+ http_restart=1
244+
245+ mkdir -p /etc/apache2/ssl/$CHARM
246+ echo "$cert" >/etc/apache2/ssl/$CHARM/cert
247+ echo "$key" >/etc/apache2/ssl/$CHARM/key
248+ if [[ -n "$ca_cert" ]] ; then
249+ juju-log "Installing Keystone supplied CA cert."
250+ echo "$ca_cert" >/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt
251+ update-ca-certificates --fresh
252+
253+ # XXX TODO: Find a better way of exporting this?
254+ if [[ "$CHARM" == "nova-cloud-controller" ]] ; then
255+ [[ -e /var/www/keystone_juju_ca_cert.crt ]] &&
256+ rm -rf /var/www/keystone_juju_ca_cert.crt
257+ ln -s /usr/local/share/ca-certificates/keystone_juju_ca_cert.crt \
258+ /var/www/keystone_juju_ca_cert.crt
259+ fi
260+
261+ fi
262+ for port_map in $port_maps ; do
263+ local ext_port=$(echo $port_map | cut -d: -f1)
264+ local int_port=$(echo $port_map | cut -d: -f2)
265+ juju-log "Creating apache2 reverse proxy vhost for $port_map."
266+ cat >/etc/apache2/sites-available/${CHARM}_${ext_port} <<END
267+Listen $ext_port
268+NameVirtualHost *:$ext_port
269+<VirtualHost *:$ext_port>
270+ ServerName $(unit-get private-address)
271+ SSLEngine on
272+ SSLCertificateFile /etc/apache2/ssl/$CHARM/cert
273+ SSLCertificateKeyFile /etc/apache2/ssl/$CHARM/key
274+ ProxyPass / http://localhost:$int_port/
275+ ProxyPassReverse / http://localhost:$int_port/
276+ ProxyPreserveHost on
277+</VirtualHost>
278+<Proxy *>
279+ Order deny,allow
280+ Allow from all
281+</Proxy>
282+<Location />
283+ Order allow,deny
284+ Allow from all
285+</Location>
286+END
287+ a2ensite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" &&
288+ http_restart=1
289+ done
290+ if [[ -n "$http_restart" ]] ; then
291+ service apache2 restart
292+ fi
293+}
294+
295+##########################################################################
296+# Description: Ensure HTTPS reverse proxying is disabled for given port
297+# mappings.
298+# Parameters: Variable number of proxy port mappings as
299+# $internal:$external.
300+# Returns: 0 if reverse proxy is not active for all portmaps, 1 on error.
301+##########################################################################
302+disable_https() {
303+ local port_maps="$@"
304+ local http_restart=""
305+ juju-log "Ensuring HTTPS disabled for $port_maps."
306+ ( [[ ! -d /etc/apache2 ]] || [[ ! -d /etc/apache2/ssl/$CHARM ]] ) && return 0
307+ for port_map in $port_maps ; do
308+ local ext_port=$(echo $port_map | cut -d: -f1)
309+ local int_port=$(echo $port_map | cut -d: -f2)
310+ if [[ -e /etc/apache2/sites-available/${CHARM}_${ext_port} ]] ; then
311+ juju-log "Disabling HTTPS reverse proxy for $CHARM $port_map."
312+ a2dissite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" &&
313+ http_restart=1
314+ fi
315+ done
316+ if [[ -n "$http_restart" ]] ; then
317+ service apache2 restart
318+ fi
319+}
320+
321+
322+##########################################################################
323+# Description: Ensures HTTPS is either enabled or disabled for given port
324+# mapping.
325+# Parameters: Variable number of proxy port mappings as
326+# $internal:$external.
327+# Returns: 0 if HTTPS reverse proxy is in place, 1 if it is not.
328+##########################################################################
329+setup_https() {
330+ # configure https via apache reverse proxying either
331+ # using certs provided by config or keystone.
332+ [[ -z "$CHARM" ]] &&
333+ error_out "setup_https(): CHARM not set."
334+ if ! https ; then
335+ disable_https $@
336+ else
337+ enable_https $@
338+ fi
339+}
340+
341+##########################################################################
342+# Description: Determine correct API server listening port based on
343+# existence of HTTPS reverse proxy and/or haproxy.
344+# Paremeters: The standard public port for given service.
345+# Returns: The correct listening port for API service.
346+##########################################################################
347+determine_api_port() {
348+ local public_port="$1"
349+ local i=0
350+ ( [[ -n "$(peer_units)" ]] || is_clustered >/dev/null 2>&1 ) && i=$[$i + 1]
351+ https >/dev/null 2>&1 && i=$[$i + 1]
352+ echo $[$public_port - $[$i * 10]]
353+}
354+
355+##########################################################################
356+# Description: Determine correct proxy listening port based on public IP +
357+# existence of HTTPS reverse proxy.
358+# Paremeters: The standard public port for given service.
359+# Returns: The correct listening port for haproxy service public address.
360+##########################################################################
361+determine_haproxy_port() {
362+ local public_port="$1"
363+ local i=0
364+ https >/dev/null 2>&1 && i=$[$i + 1]
365+ echo $[$public_port - $[$i * 10]]
366 }
367
368 ##########################################################################
369
370=== modified file 'hooks/nova-cloud-controller-common'
371--- hooks/nova-cloud-controller-common 2013-01-18 12:22:44 +0000
372+++ hooks/nova-cloud-controller-common 2013-03-09 04:30:28 +0000
373@@ -97,6 +97,7 @@
374 if [ "$(config-get conf-ext-net)" != "no" ] &&
375 [ "$QUANTUM_PLUGIN" == "ovs" ] &&
376 [ -f /etc/quantum/novarc ] &&
377+ [ -n "$(relation-ids amqp)" ] &&
378 [ -n "$(relation-ids shared-db)" ]; then
379 juju-log "Configuring external networking for quantum"
380 # Use helper to create external network gateway
381@@ -219,3 +220,73 @@
382 known_hosts="$(base64 /etc/nova/compute_ssh/$sunit/known_hosts)" \
383 authorized_keys="$(base64 /etc/nova/compute_ssh/$sunit/authorized_keys)"
384 }
385+
386+configure_https() {
387+ # setup https termination for all api services, depending on what is running
388+ # and topology of current deployment.
389+ local clustered=""
390+ ( [[ -n "$(peer_units)" ]] || is_clustered ) && clustered="1"
391+ local services=""
392+ local ssl_port_maps=""
393+ local haproxy_port_maps=""
394+ local next_server=""
395+ local api_port=""
396+
397+ # upstartService:defaultPort:configOption
398+ local svcs="nova-api-ec2:8773:ec2_listen_port
399+ nova-api-os-compute:8774:osapi_compute_listen_port
400+ nova-objectstore:3333:s3_listen_port"
401+ [[ "$NET_MANAGER" == "Quantum" ]] &&
402+ svcs="$svcs quantum-server:9696:bind_port"
403+
404+ for s in $svcs ; do
405+ local service=$(echo $s | cut -d: -f1)
406+ local port=$(echo $s | cut -d: -f2)
407+ local opt=$(echo $s | cut -d: -f3)
408+ if [[ -n "$clustered" ]] ; then
409+ next_server="$(determine_haproxy_port $port)"
410+ api_port="$(determine_api_port $port)"
411+ haproxy_port_maps="$haproxy_port_maps $service:$next_server:$api_port"
412+ else
413+ api_port="$(determine_api_port $port)"
414+ next_server="$api_port"
415+ fi
416+ if [[ "$service" == "quantum-server" ]] ; then
417+ set_or_update "$opt" "$api_port" "$QUANTUM_CONF"
418+ else
419+ set_or_update "$opt" "$api_port"
420+ fi
421+ ssl_port_maps="$ssl_port_maps $port:$next_server"
422+ done
423+
424+ # make sure all backend api servers are bound to new backend port
425+ # before setting up any frontends.
426+ for s in $svcs ; do
427+ local service=$(echo $s | cut -d: -f1)
428+ service_ctl $service restart
429+ done
430+
431+ [[ -n "$haproxy_port_maps" ]] && configure_haproxy $haproxy_port_maps
432+ setup_https $ssl_port_maps
433+
434+ # another restart to ensure api servers are now bound to frontend ports
435+ # that may have just been disabled.
436+ for s in $svcs ; do
437+ local service=$(echo $s | cut -d: -f1)
438+ service_ctl $service restart
439+ done
440+
441+ local r_id=""
442+ # (re)configure ks endpoint accordingly
443+ for r_id in $(relation-ids identity-service) ; do
444+ keystone_joined "$r_id"
445+ done
446+ # pass on possibly updated quantum URL + ca_cert to compute nodes.
447+ for r_id in $(relation-ids cloud-compute) ; do
448+ compute_joined "$r_id"
449+ done
450+ # update the quantum relation, as well.
451+ for r_id in $(relation-ids quantum-network-service) ; do
452+ quantum_joined "$r_id"
453+ done
454+}
455
456=== modified file 'hooks/nova-cloud-controller-relations'
457--- hooks/nova-cloud-controller-relations 2013-02-21 23:12:04 +0000
458+++ hooks/nova-cloud-controller-relations 2013-03-09 04:30:28 +0000
459@@ -44,6 +44,7 @@
460 cp files/create_tenant_net.py /usr/bin/quantum-tenant-net
461
462 service_ctl all stop
463+ configure_https
464 }
465
466 function upgrade_charm {
467@@ -70,13 +71,14 @@
468 set_config_flags
469
470 if [ "$NET_MANAGER" == "Quantum" ] && \
471- is_clustered && is_leader 'res_nova_vip' || \
472+ eligible_leader 'res_nova_vip' || \
473 ! is_clustered; then
474 configure_quantum_networking
475 fi
476
477 determine_services
478 service_ctl all restart
479+ configure_https
480 }
481
482 function amqp_joined {
483@@ -131,6 +133,12 @@
484 fi
485
486 determine_services && service_ctl all restart
487+
488+ if [ "$NET_MANAGER" == "Quantum" ] && \
489+ eligible_leader 'res_nova_vip' || \
490+ ! is_clustered; then
491+ configure_quantum_networking
492+ fi
493 }
494
495 function db_joined {
496@@ -170,11 +178,17 @@
497 fi
498 determine_services
499 service_ctl all stop
500- /usr/bin/nova-manage db sync
501+
502+ eligible_leader 'res_nova_vip' && /usr/bin/nova-manage db sync
503+
504 service_ctl all start
505- if [ "$NET_MANAGER" == "Quantum" ]; then
506+
507+ if [ "$NET_MANAGER" == "Quantum" ] && \
508+ eligible_leader 'res_nova_vip' || \
509+ ! is_clustered; then
510 configure_quantum_networking
511 fi
512+
513 trigger_remote_service_restarts
514 }
515
516@@ -191,28 +205,37 @@
517 # we need to get two entries into keystone's catalog, nova + ec2
518 # group, them by prepending $service_ to each setting. the keystone
519 # charm will assemble settings into corresponding catalog entries
520- if is_clustered && is_leader 'res_nova_vip'; then
521- address=$(config-get vip)
522- nova_port=18774
523- ec2_port=18773
524- s3_port=13333
525- quantum_port=19696
526- vol_port=18776
527- elif ! is_clustered; then
528- address=$(unit-get private-address)
529- nova_port=8774
530- ec2_port=8773
531- s3_port=3333
532- quantum_port=9696
533- vol_port=8776
534+ eligible_leader 'res_nova_vip' || return 0
535+
536+ is_clustered && local host=$(config-get vip) ||
537+ local host=$(unit-get private-address)
538+
539+ if [[ "$arg0" == "identity-service-relation-joined" ]] ; then
540+ # determine https status based only on config at this point,
541+ # insepcting KS relation is not reliable. if KS has mulitple
542+ # units, multiple relation-joineds are fired, resulting in the
543+ # endpoint being configured in catalog as https before https
544+ # is actually setup on this end. ends with failure to configure
545+ # quantum network, if its enabled.
546+ # if specified in config, https will have already been setup in
547+ # install or config-changed.
548+ if [[ -n "$(config-get ssl_cert)" ]] &&
549+ [[ -n "$(config-get ssl_key)" ]] ; then
550+ local scheme="https"
551+ else
552+ local scheme="http"
553+ fi
554 else
555- # Not the leader and clustered - no action required
556- return 0
557+ # this function is called from other hook contexts, use normal method
558+ # for determining https
559+ https && scheme="https" || scheme="http"
560 fi
561- nova_url="http://$address:$nova_port/v1.1/\$(tenant_id)s"
562- ec2_url="http://$address:$ec2_port/services/Cloud"
563- s3_url="http://$address:$s3_port"
564- region="$(config-get region)"
565+
566+ local nova_url="$scheme://$host:8774/v1.1/\$(tenant_id)s"
567+ local ec2_url="$scheme://$host:8773/services/Cloud"
568+ local s3_url="$scheme://$host:3333"
569+ local region="$(config-get region)"
570+ local quantum_url="$scheme://$host:9696"
571
572 # these are the default endpoints
573 relation-set nova_service="nova" \
574@@ -232,7 +255,6 @@
575 s3_internal_url="$s3_url"
576
577 if [ "$(config-get network-manager)" == "Quantum" ]; then
578- quantum_url="http://$address:$quantum_port"
579 relation-set quantum_service="quantum" \
580 quantum_region="$region" \
581 quantum_public_url="$quantum_url" \
582@@ -242,7 +264,7 @@
583
584 # tack on an endpoint for nova-volume a relation exists.
585 if [[ -n "$(relation-ids nova-volume-service)" ]] ; then
586- nova_vol_url="http://$address:$vol_port/v1/\$(tenant_id)s"
587+ nova_vol_url="$scheme://$host:$vol_port/v1/\$(tenant_id)s"
588 relation-set nova-volume_service="nova-volume" \
589 nova-volume_region="$region" \
590 nova-volume_public_url="$nova_vol_url" \
591@@ -281,6 +303,13 @@
592 sed -i '/--use_deprecated_auth/d' $NOVA_CONF
593 fi
594
595+ local clustered=""
596+ is_clustered && clustered="1"
597+
598+ [[ -n "$clustered" ]] && local host=$(config-get vip) ||
599+ local host=$(unit-get private-address)
600+ https && local scheme="https" || local scheme="http"
601+
602 # update keystone authtoken settings accordingly
603 set_or_update "service_host" "$service_host" "$API_CONF"
604 set_or_update "service_port" "$service_port" "$API_CONF"
605@@ -296,7 +325,7 @@
606 if [ "$NET_MANAGER" == "Quantum" ]; then
607 # Configure Nova for quantum
608 keystone_url="http://${auth_host}:${auth_port}/v2.0"
609- set_or_update "quantum_url" "http://$(unit-get private-address):9696"
610+ set_or_update "quantum_url" "$scheme://$host:9696"
611 set_or_update "quantum_admin_tenant_name" "${service_tenant}"
612 set_or_update "quantum_admin_username" "${service_username}"
613 set_or_update "quantum_admin_password" "${service_password}"
614@@ -320,11 +349,15 @@
615 determine_services && service_ctl all restart
616
617 if [ "$NET_MANAGER" == "Quantum" ]; then
618- configure_quantum_networking
619+ # if first time here, config quantum before setting up
620+ # https.
621+ if [[ -z "$clustered" ]] && eligible_leader ; then
622+ configure_quantum_networking
623+ fi
624 # ripple out changes to identity to connected services
625 # which use cloud-controller as source of information for
626 # keystone
627- r_ids="$(relation-ids cloud-compute) $(relation-ids quantum-network-service)"
628+ local r_ids="$(relation-ids cloud-compute) $(relation-ids quantum-network-service)"
629 for id in $r_ids ; do
630 relation-set -r $id \
631 keystone_host=$auth_host \
632@@ -339,6 +372,15 @@
633
634 done
635 fi
636+ configure_https
637+
638+ # if this changed event happens as a result of clustered VIP
639+ # reconfigure, configure_https needs to update VIP certificate
640+ # before quantumclient is used.
641+ if [[ "$NET_MANAGER" == "Quantum" ]] &&
642+ [[ -n "$clustered" ]] && eligible_leader 'res_nova_vip' ; then
643+ configure_quantum_networking
644+ fi
645 }
646
647 volume_joined() {
648@@ -390,19 +432,19 @@
649 }
650
651 compute_joined() {
652- if is_clustered && ! is_leader 'res_nova_vip'; then
653- # Clustered and not current leader - do nothing
654- return 0
655- fi
656-
657- relation-set network_manager=$(config-get network-manager)
658- relation-set ec2_host=$(unit-get private-address)
659+ local r_id="$1"
660+ [[ -n "$r_id" ]] && r_id="-r $r_id"
661+ eligible_leader 'res_nova_vip' || return 0
662+ relation-set $r_id network_manager=$(config-get network-manager)
663+ # XXX Should point to VIP if clustered, or this may not even be needed.
664+ relation-set $r_id ec2_host=$(unit-get private-address)
665
666 local sect="filter:authtoken"
667 keystone_host=$(local_config_get $API_CONF auth_host $sect)
668+
669 if [ "$NET_MANAGER" == "Quantum" ]; then
670- if [ -n "$keystone_host" ]; then
671- relation-set \
672+ if [[ -n "$keystone_host" ]]; then
673+ relation-set $r_id \
674 keystone_host=$keystone_host \
675 auth_port=$(local_config_get $API_CONF auth_port $sect) \
676 service_port=$(local_config_get $API_CONF service_port $sect) \
677@@ -410,19 +452,24 @@
678 service_password=$(local_config_get $API_CONF admin_password $sect) \
679 service_tenant=$(local_config_get $API_CONF admin_tenant_name $sect) \
680 auth_uri=$(local_config_get $API_CONF auth_uri $sect)
681- fi
682-
683- if is_clustered; then
684- quantum_host=$(config-get vip)
685- quantum_port=19696
686- else
687- quantum_host=$(unit-get private-address)
688- quantum_port=9696
689- fi
690-
691- relation-set quantum_host=$quantum_host \
692- quantum_port=$quantum_port \
693- quantum_plugin=$(config-get quantum-plugin)
694+
695+ fi
696+ is_clustered && local host=$(config-get vip) ||
697+ local host=$(unit-get private-address)
698+ https && local scheme="https" || local scheme="http"
699+ local quantum_url="$scheme://$host:9696"
700+
701+ relation-set $r_id quantum_url=$quantum_url \
702+ quantum_plugin=$(config-get quantum-plugin) \
703+ region=$(config-get region)
704+
705+ fi
706+
707+ # must pass on the keystone CA certficiate, if it exists.
708+ cert="/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt"
709+ if [[ -n "$keystone_host" ]] && [[ -e $cert ]] ; then
710+ cert=$(cat $cert | base64)
711+ relation-set $r_id ca_cert="$cert"
712 fi
713
714 # volume driver is dependent on os version, or presence
715@@ -434,11 +481,10 @@
716 vol_drv="nova-volume"
717 ;;
718 "folsom")
719- local r_ids=$(relation-ids cinder-volume-service)
720- [[ -z "$r_ids" ]] && vol_drv="nova-volume"
721+ [[ -z "$(relation-ids cinder-volume-service)" ]] && vol_drv="nova-volume"
722 ;;
723 esac
724- relation-set volume_service="$vol_drv"
725+ relation-set $r_id volume_service="$vol_drv"
726 }
727
728 compute_changed() {
729@@ -458,15 +504,14 @@
730
731 function quantum_joined() {
732 # Tell quantum service about keystone
733- if is_clustered && ! is_leader 'res_nova_vip'; then
734- # Clustered and not current leader - do nothing
735- return 0
736- fi
737+ eligible_leader || return 0
738+ local r_id="$1"
739+ [[ -n "$r_id" ]] && r_id="-r $r_id"
740
741 local sect="filter:authtoken"
742 keystone_host=$(local_config_get $API_CONF auth_host $sect)
743 if [ -n "$keystone_host" ]; then
744- relation-set \
745+ relation-set $r_id \
746 keystone_host=$keystone_host \
747 auth_port=$(local_config_get $API_CONF auth_port $sect) \
748 service_port=$(local_config_get $API_CONF service_port $sect) \
749@@ -476,24 +521,50 @@
750 auth_uri=$(local_config_get $API_CONF auth_uri $sect)
751 fi
752
753- if is_clustered; then
754- quantum_host=$(config-get vip)
755- quantum_port=19696
756- else
757- quantum_host=$(unit-get private-address)
758- quantum_port=9696
759+ # must pass on the keystone CA certficiate, if it exists.
760+ cert="/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt"
761+ if [[ -n "$keystone_host" ]] && [[ -e $cert ]] ; then
762+ cert=$(cat $cert | base64)
763+ relation-set $r_id ca_cert="$cert"
764 fi
765
766- relation-set quantum_host=$quantum_host \
767- quantum_port=$quantum_port \
768- quantum_plugin=$(config-get quantum-plugin) \
769- region=$(config-get region)
770+ is_clustered && local host=$(config-get vip) ||
771+ local host=$(unit-get private-address)
772+ https && local scheme="https" || local scheme="http"
773+ local quantum_url="$scheme://$host:9696"
774+
775+ relation-set $r_id quantum_url=$quantum_url \
776+ quantum_plugin=$(config-get quantum-plugin) \
777+ region=$(config-get region)
778+
779 }
780
781 function cluster_changed() {
782- configure_haproxy "quantum_api:9696" "nova_api:8774" \
783- "ec2_api:8773" "s3_api:3333" \
784- "volume_api:8776"
785+ [[ -z "$(peer_units)" ]] &&
786+ juju-log "cluster_changed() with no peers." && exit 0
787+ # upstartService:defaultPort:configOption
788+ local svcs="nova-api-ec2:8773:ec2_listen_port
789+ nova-api-os-compute:8774:osapi_compute_listen_port
790+ nova-objectstore:3333:s3_listen_port"
791+ [[ "$NET_MANAGER" == "Quantum" ]] &&
792+ svcs="$svcs quantum-server:9696:bind_port"
793+
794+ for s in $svcs ; do
795+ local service=$(echo $s | cut -d: -f1)
796+ local port=$(echo $s | cut -d: -f2)
797+ local opt=$(echo $s | cut -d: -f3)
798+ local next_server="$(determine_haproxy_port $port)"
799+ local api_port="$(determine_api_port $port)"
800+ local haproxy_port_maps="$haproxy_port_maps $service:$next_server:$api_port"
801+ if [[ "$service" == "quantum-server" ]] ; then
802+ set_or_update "$opt" "$api_port" "$QUANTUM_CONF"
803+ else
804+ set_or_update "$opt" "$api_port"
805+ fi
806+
807+ service_ctl $service restart
808+ done
809+ configure_haproxy $haproxy_port_maps
810 }
811
812 function ha_relation_joined() {
813@@ -518,13 +589,13 @@
814 init_services="{
815 'res_nova_haproxy':'haproxy'
816 }"
817- groups="{
818-'grp_nova_haproxy':'res_nova_vip res_nova_haproxy'
819+ clones="{
820+'cl_nova_haproxy':'res_nova_haproxy'
821 }"
822 relation-set corosync_bindiface=$corosync_bindiface \
823 corosync_mcastport=$corosync_mcastport \
824 resources="$resources" resource_params="$resource_params" \
825- init_services="$init_services" groups="$groups"
826+ init_services="$init_services" clones="$clones"
827 else
828 juju-log "Insufficient configuration data to configure hacluster"
829 exit 1
830@@ -534,45 +605,57 @@
831 function ha_relation_changed() {
832 local clustered=`relation-get clustered`
833 if [ -n "$clustered" ] && is_leader 'res_nova_vip'; then
834+ https && local scheme="https" || local scheme="http"
835 for r_id in `relation-ids identity-service`; do
836- address=$(config-get vip)
837- nova_url="http://$address:18774/v1.1/\$(tenant_id)s"
838- ec2_url="http://$address:18773/services/Cloud"
839- s3_url="http://$address:13333"
840+ local address=$(config-get vip)
841+ local region=$(config-get region)
842+ local nova_url="$scheme://$address:8774/v1.1/\$(tenant_id)s"
843+ local ec2_url="$scheme://$address:8773/services/Cloud"
844+ local s3_url="$scheme://$address:3333"
845+ local quantum_url="$scheme://$address:9696"
846+ local nova_vol_url="$scheme://$address:8776/v1/\$(tenant_id)s"
847+
848 relation-set -r $r_id \
849+ nova_service="nova" \
850+ nova_region="$region" \
851 nova_public_url="$nova_url" \
852 nova_admin_url="$nova_url" \
853 nova_internal_url="$nova_url" \
854+ ec2_service="ec2" \
855+ ec2_region="$region" \
856 ec2_public_url="$ec2_url" \
857 ec2_admin_url="$ec2_url" \
858 ec2_internal_url="$ec2_url" \
859+ s3_service="s3" \
860+ s3_region="$region" \
861 s3_public_url="$s3_url" \
862 s3_admin_url="$s3_url" \
863 s3_internal_url="$s3_url"
864
865 if [ "$(config-get network-manager)" == "Quantum" ]; then
866- quantum_url="http://$address:19696"
867 relation-set -r $r_id \
868+ quantum_service="quantum" \
869+ quantum_region="$region" \
870 quantum_public_url="$quantum_url" \
871 quantum_admin_url="$quantum_url" \
872 quantum_internal_url="$quantum_url"
873 fi
874
875 if [[ -n "$(relation-ids nova-volume-service)" ]] ; then
876- nova_vol_url="http://$address:18776/v1/\$(tenant_id)s"
877 relation-set -r $r_id \
878+ nova-volume_service="nova-volume" \
879+ nova-volume_region="$region" \
880 nova-volume_public_url="$nova_vol_url" \
881 nova-volume_admin_url="$nova_vol_url" \
882 nova-volume_internal_url="$nova_vol_url"
883 fi
884 done
885 if [ "$(config-get network-manager)" == "Quantum" ]; then
886- # Let gateway nodes use the new HA address for the
887+ # Let gateway nodes use the new HA address for the
888 # quantum API server
889 for r_id in `relation-ids quantum-network-service`; do
890 relation-set -r $r_id \
891- quantum_host=$address
892- quantum_port=19696
893+ quantum_url="$quantum_url" region="$region"
894 done
895 fi
896 fi
897
898=== modified file 'revision'
899--- revision 2013-03-05 01:41:05 +0000
900+++ revision 2013-03-09 04:30:28 +0000
901@@ -1,1 +1,1 @@
902-214
903+236

Subscribers

People subscribed via source and target branches