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

Proposed by Adam Gandelman on 2013-02-25
Status: Merged
Merged at revision: 39
Proposed branch: lp:~gandelman-a/charms/precise/cinder/https_endpoint
Merge into: lp:~openstack-charmers/charms/precise/cinder/ha-support
Diff against target: 511 lines (+292/-34)
5 files modified
config.yaml (+11/-0)
hooks/cinder-common (+34/-0)
hooks/cinder-hooks (+27/-15)
hooks/lib/openstack-common (+219/-18)
revision (+1/-1)
To merge this branch: bzr merge lp:~gandelman-a/charms/precise/cinder/https_endpoint
Reviewer Review Type Date Requested Status
James Page 2013-02-25 Approve on 2013-02-27
Review via email: mp+150383@code.launchpad.net

Description of the change

Required cinder changes for HTTPS support.

To post a comment you must log in.
James Page (james-page) wrote :

cinder-hooks:ha_changed

145 - local port=$(config-get api-listening-port)
146 - port=$(($port + 10000))
147 - local url="http://$(config-get vip):$port/v1/\$(tenant_id)s"
148 + https && local scheme="https" || local scheme="http"
149 + local url="$scheme://$(config-get vip):$(config-get api-listening-port)/v1"
150 + local r_id=""

v1/\$(tenant_id)s is dropped which breaks the endpoint entry.

James Page (james-page) :
review: Needs Fixing
43. By Adam Gandelman on 2013-02-26

Fix missing tenant_id in endpoint URL.

44. By Adam Gandelman on 2013-02-26

Bump revision.

Adam Gandelman (gandelman-a) wrote :

Should be fixed now @ rev. 43

James Page (james-page) :
review: Approve
45. By Adam Gandelman on 2013-03-08

Rebase against current ha-support branch.

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:40:06 +0000
3+++ config.yaml 2013-03-08 21:36:22 +0000
4@@ -86,3 +86,14 @@
5 description: |
6 Default multicast port number that will be used to communicate between
7 HA Cluster nodes.
8+ # Per-service HTTPS configuration.
9+ ssl_cert:
10+ type: string
11+ description: |
12+ SSL certificate to install and use for API ports. Setting this value
13+ and ssl_key will enable reverse proxying, point Glance's entry in the
14+ Keystone catalog to use https, and override any certficiate and key
15+ issued by Keystone (if it is configured to do so).
16+ ssl_key:
17+ type: string
18+ description: SSL key to use with certificate specified as ssl_cert.
19
20=== modified file 'hooks/cinder-common'
21--- hooks/cinder-common 2013-01-08 15:54:18 +0000
22+++ hooks/cinder-common 2013-03-08 21:36:22 +0000
23@@ -228,3 +228,37 @@
24 error_out "Could not create volume group: $vol_group"
25 return 0
26 }
27+
28+configure_https() {
29+ # request openstack-common setup reverse proxy mapping for API and registry
30+ # servers
31+ service_enabled "api" || return 0
32+ local cfg_api_port=$(config-get api-listening-port)
33+ service_ctl cinder-api stop
34+ if [[ -n "$(peer_units)" ]] || is_clustered ; then
35+ # haproxy may already be configured. need to push it back in the request
36+ # pipeline in preparation for a change from:
37+ # from: haproxy (8776) -> cinder-api (8766)
38+ # to: ssl (8776) -> haproxy (8766) -> cinder-api (8756)
39+ local next_server=$(determine_haproxy_port $cfg_api_port)
40+ local api_port=$(determine_api_port $cfg_api_port)
41+ configure_haproxy "cinder_api:$next_server:$api_port"
42+ else
43+ # if not clustered, the cinder-api is next in the pipeline.
44+ local api_port=$(determine_api_port $cfg_api_port)
45+ local next_server=$api_port
46+ fi
47+
48+ # setup https to point to either haproxy or directly to api server, depending.
49+ setup_https $cfg_api_port:$next_server
50+
51+ # configure servers to listen on new ports accordingly.
52+ set_or_update osapi_volume_listen_port "$api_port"
53+ service_ctl cinder-api start
54+
55+ local r_id=""
56+ # (re)configure ks endpoint accordingly in ks and nova.
57+ for r_id in "$(relation-ids identity-service)" ; do
58+ keystone_joined "$r_id"
59+ done
60+}
61
62=== modified file 'hooks/cinder-hooks'
63--- hooks/cinder-hooks 2013-03-04 17:42:42 +0000
64+++ hooks/cinder-hooks 2013-03-08 21:36:22 +0000
65@@ -35,6 +35,7 @@
66 cinder_ctl cinder-volume restart
67 fi
68 fi
69+ configure_https
70 }
71
72 db_joined() {
73@@ -95,13 +96,13 @@
74 keystone_joined() {
75 # Exit hook execution if unit is not leader of cluster/service
76 eligible_leader 'res_cinder_vip' || return 0
77- port=$(config-get api-listening-port)
78- if is_clustered; then
79- port=$(($port + 10000))
80- url="http://$(config-get vip):$port/v1/\$(tenant_id)s"
81- elif ! is_clustered; then
82- url="http://$(unit-get private-address):$port/v1/\$(tenant_id)s"
83- fi
84+
85+ # determine correct endpoint URL
86+ https && scheme="https" || scheme="http"
87+ is_clustered && local host=$(config-get vip) ||
88+ local host=$(unit-get private-address)
89+
90+ local url="$scheme://$host:$(config-get api-listening-port)/v1/\$(tenant_id)s"
91 relation-set service="cinder" \
92 region="$(config-get region)" public_url="$url" admin_url="$url" internal_url="$url"
93 }
94@@ -133,6 +134,7 @@
95 set_or_update "auth_strategy" "keystone" "$CINDER_CONF"
96
97 cinder_ctl all restart
98+ configure_https
99 }
100
101 function ceph_joined {
102@@ -191,7 +193,16 @@
103 }
104
105 function cluster_changed() {
106- configure_haproxy "cinder_api:$(config-get api-listening-port)"
107+ service_enabled "api" || return 0
108+ [[ -z "$(peer_units)" ]] &&
109+ juju-log "cluster_changed() with no peers." && exit 0
110+ local cfg_api_port="$(config-get api-listening-port)"
111+ local haproxy_port="$(determine_haproxy_port $cfg_api_port)"
112+ local backend_port="$(determine_api_port $cfg_api_port)"
113+ service cinder-api stop
114+ configure_haproxy "cinder_api:$haproxy_port:$backend_port"
115+ set_or_update osapi_volume_listen_port "$backend_port"
116+ service cinder-api start
117 }
118
119 function upgrade_charm() {
120@@ -220,26 +231,26 @@
121 init_services="{
122 'res_cinder_haproxy':'haproxy'
123 }"
124- groups="{
125-'grp_cinder_haproxy':'res_cinder_vip res_cinder_haproxy'
126+ clones="{
127+'cl_cinder_haproxy': 'res_cinder_haproxy'
128 }"
129 relation-set corosync_bindiface=$corosync_bindiface \
130 corosync_mcastport=$corosync_mcastport \
131 resources="$resources" resource_params="$resource_params" \
132- init_services="$init_services" groups="$groups"
133+ init_services="$init_services" clones="$clones"
134 else
135 juju-log "Insufficient configuration data to configure hacluster"
136 exit 1
137- fi
138+ fi
139 }
140
141 function ha_relation_changed() {
142 local clustered=`relation-get clustered`
143 if [ -n "$clustered" ] && is_leader 'res_cinder_vip'; then
144 juju-log "Cluster leader, reconfiguring keystone endpoint"
145- local port=$(config-get api-listening-port)
146- port=$(($port + 10000))
147- local url="http://$(config-get vip):$port/v1/\$(tenant_id)s"
148+ https && local scheme="https" || local scheme="http"
149+ local url="$scheme://$(config-get vip):$(config-get api-listening-port)/v1/\$(tenant_id)s"
150+ local r_id=""
151 for r_id in `relation-ids identity-service`; do
152 relation-set -r $r_id service="cinder" \
153 region="$(config-get region)" \
154@@ -249,6 +260,7 @@
155 }
156
157 function config_changed() {
158+ configure_https
159 # Save our scriptrc env variables for health checks
160 declare -a env_vars=(
161 "OPENSTACK_PORT_MCASTPORT=$(config-get ha-mcastport)"
162
163=== modified file 'hooks/lib/openstack-common'
164--- hooks/lib/openstack-common 2013-03-08 21:08:07 +0000
165+++ hooks/lib/openstack-common 2013-03-08 21:36:22 +0000
166@@ -321,7 +321,6 @@
167
168 HAPROXY_CFG=/etc/haproxy/haproxy.cfg
169 HAPROXY_DEFAULT=/etc/default/haproxy
170-
171 ##########################################################################
172 # Description: Configures HAProxy services for Openstack API's
173 # Parameters:
174@@ -330,9 +329,8 @@
175 # assumes the name of the peer relation is 'cluster' and that every
176 # service unit in the peer relation is running the same services.
177 #
178-# The HAProxy service will listen on port + 10000.
179-# Example:
180-# configure_haproxy cinder_api:12345 nova_api:9999
181+# Example
182+# configure_haproxy cinder_api:8776:8756i nova_api:8774:8764
183 ##########################################################################
184 configure_haproxy() {
185 local address=`unit-get private-address`
186@@ -368,14 +366,18 @@
187 EOF
188 for service in $@; do
189 local service_name=$(echo $service | cut -d : -f 1)
190- local api_listen_port=$(echo $service | cut -d : -f 2)
191- local haproxy_listen_port=$(($api_listen_port + 10000))
192+ local haproxy_listen_port=$(echo $service | cut -d : -f 2)
193+ local api_listen_port=$(echo $service | cut -d : -f 3)
194+ juju-log "Adding haproxy configuration entry for $service "\
195+ "($haproxy_listen_port -> $api_listen_port)"
196 cat >> $HAPROXY_CFG << EOF
197 listen $service_name 0.0.0.0:$haproxy_listen_port
198 balance roundrobin
199 option tcplog
200 server $name $address:$api_listen_port check
201 EOF
202+ local r_id=""
203+ local unit=""
204 for r_id in `relation-ids cluster`; do
205 for unit in `relation-list -r $r_id`; do
206 local unit_name=${unit////-}
207@@ -388,6 +390,7 @@
208 done
209 done
210 echo "ENABLED=1" > $HAPROXY_DEFAULT
211+ service haproxy restart
212 }
213
214 ##########################################################################
215@@ -395,18 +398,20 @@
216 # Returns: 0 if configured, 1 if not configured
217 ##########################################################################
218 is_clustered() {
219+ local r_id=""
220+ local unit=""
221 for r_id in $(relation-ids ha); do
222 if [ -n "$r_id" ]; then
223 for unit in $(relation-list -r $r_id); do
224 clustered=$(relation-get -r $r_id clustered $unit)
225 if [ -n "$clustered" ]; then
226- echo "Unit is clustered"
227+ juju-log "Unit is haclustered"
228 return 0
229 fi
230 done
231 fi
232 done
233- echo "Unit is not clustered"
234+ juju-log "Unit is not haclustered"
235 return 1
236 }
237
238@@ -415,6 +420,7 @@
239 ##########################################################################
240 peer_units() {
241 local peers=""
242+ local r_id=""
243 for r_id in $(relation-ids cluster); do
244 peers="$peers $(relation-list -r $r_id)"
245 done
246@@ -433,11 +439,11 @@
247 echo "Comparing $JUJU_UNIT_NAME with peers: $peers"
248 local r_unit_no=$(echo $peer | cut -d / -f 2)
249 if (($r_unit_no<$l_unit_no)); then
250- echo "Not oldest peer; deferring"
251+ juju-log "Not oldest peer; deferring"
252 return 1
253 fi
254 done
255- echo "Oldest peer; might take charge?"
256+ juju-log "Oldest peer; might take charge?"
257 return 0
258 }
259
260@@ -451,13 +457,13 @@
261 eligible_leader() {
262 if is_clustered; then
263 if ! is_leader $1; then
264- echo 'Deferring action to CRM leader'
265+ juju-log 'Deferring action to CRM leader'
266 return 1
267 fi
268 else
269 peers=$(peer_units)
270 if [ -n "$peers" ] && ! oldest_peer "$peers"; then
271- echo 'Deferring action to oldest service unit.'
272+ juju-log 'Deferring action to oldest service unit.'
273 return 1
274 fi
275 fi
276@@ -469,14 +475,14 @@
277 # Returns: 0 if peered, 1 if not peered
278 ##########################################################################
279 is_peered() {
280- r_id=$(relation-ids cluster)
281+ local r_id=$(relation-ids cluster)
282 if [ -n "$r_id" ]; then
283 if [ -n "$(relation-list -r $r_id)" ]; then
284- echo "Unit peered"
285+ juju-log "Unit peered"
286 return 0
287 fi
288 fi
289- echo "Unit not peered"
290+ juju-log "Unit not peered"
291 return 1
292 }
293
294@@ -489,12 +495,207 @@
295 hostname=`hostname`
296 if [ -x /usr/sbin/crm ]; then
297 if crm resource show $1 | grep -q $hostname; then
298- echo "$hostname is cluster leader"
299+ juju-log "$hostname is cluster leader."
300 return 0
301 fi
302 fi
303- echo "$hostname is not cluster leader"
304- return 1
305+ juju-log "$hostname is not cluster leader."
306+ return 1
307+}
308+
309+##########################################################################
310+# Description: Determines whether enough data has been provided in
311+# configuration or relation data to configure HTTPS.
312+# Parameters: None
313+# Returns: 0 if HTTPS can be configured, 1 if not.
314+##########################################################################
315+https() {
316+ local r_id=""
317+ if [[ -n "$(config-get ssl_cert)" ]] &&
318+ [[ -n "$(config-get ssl_key)" ]] ; then
319+ return 0
320+ fi
321+ for r_id in $(relation-ids identity-service) ; do
322+ for unit in $(relation-list -r $r_id) ; do
323+ if [[ "$(relation-get -r $r_id https_keystone $unit)" == "True" ]] &&
324+ [[ -n "$(relation-get -r $r_id ssl_cert $unit)" ]] &&
325+ [[ -n "$(relation-get -r $r_id ssl_key $unit)" ]] &&
326+ [[ -n "$(relation-get -r $r_id ca_cert $unit)" ]] ; then
327+ return 0
328+ fi
329+ done
330+ done
331+ return 1
332+}
333+
334+##########################################################################
335+# Description: For a given number of port mappings, configures apache2
336+# HTTPs local reverse proxying using certficates and keys provided in
337+# either configuration data (preferred) or relation data. Assumes ports
338+# are not in use (calling charm should ensure that).
339+# Parameters: Variable number of proxy port mappings as
340+# $internal:$external.
341+# Returns: 0 if reverse proxy(s) have been configured, 0 if not.
342+##########################################################################
343+enable_https() {
344+ local port_maps="$@"
345+ local http_restart=""
346+ juju-log "Enabling HTTPS for port mappings: $port_maps."
347+
348+ # allow overriding of keystone provided certs with those set manually
349+ # in config.
350+ local cert=$(config-get ssl_cert)
351+ local key=$(config-get ssl_key)
352+ local ca_cert=""
353+ if [[ -z "$cert" ]] || [[ -z "$key" ]] ; then
354+ juju-log "Inspecting identity-service relations for SSL certificate."
355+ local r_id=""
356+ cert=""
357+ key=""
358+ ca_cert=""
359+ for r_id in $(relation-ids identity-service) ; do
360+ for unit in $(relation-list -r $r_id) ; do
361+ [[ -z "$cert" ]] && cert="$(relation-get -r $r_id ssl_cert $unit)"
362+ [[ -z "$key" ]] && key="$(relation-get -r $r_id ssl_key $unit)"
363+ [[ -z "$ca_cert" ]] && ca_cert="$(relation-get -r $r_id ca_cert $unit)"
364+ done
365+ done
366+ [[ -n "$cert" ]] && cert=$(echo $cert | base64 -di)
367+ [[ -n "$key" ]] && key=$(echo $key | base64 -di)
368+ [[ -n "$ca_cert" ]] && ca_cert=$(echo $ca_cert | base64 -di)
369+ else
370+ juju-log "Using SSL certificate provided in service config."
371+ fi
372+
373+ [[ -z "$cert" ]] || [[ -z "$key" ]] &&
374+ juju-log "Expected but could not find SSL certificate data, not "\
375+ "configuring HTTPS!" && return 1
376+
377+ apt-get -y install apache2
378+ a2enmod ssl proxy proxy_http | grep -v "To activate the new configuration" &&
379+ http_restart=1
380+
381+ mkdir -p /etc/apache2/ssl/$CHARM
382+ echo "$cert" >/etc/apache2/ssl/$CHARM/cert
383+ echo "$key" >/etc/apache2/ssl/$CHARM/key
384+ if [[ -n "$ca_cert" ]] ; then
385+ juju-log "Installing Keystone supplied CA cert."
386+ echo "$ca_cert" >/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt
387+ update-ca-certificates --fresh
388+
389+ # XXX TODO: Find a better way of exporting this?
390+ if [[ "$CHARM" == "nova-cloud-controller" ]] ; then
391+ [[ -e /var/www/keystone_juju_ca_cert.crt ]] &&
392+ rm -rf /var/www/keystone_juju_ca_cert.crt
393+ ln -s /usr/local/share/ca-certificates/keystone_juju_ca_cert.crt \
394+ /var/www/keystone_juju_ca_cert.crt
395+ fi
396+
397+ fi
398+ for port_map in $port_maps ; do
399+ local ext_port=$(echo $port_map | cut -d: -f1)
400+ local int_port=$(echo $port_map | cut -d: -f2)
401+ juju-log "Creating apache2 reverse proxy vhost for $port_map."
402+ cat >/etc/apache2/sites-available/${CHARM}_${ext_port} <<END
403+Listen $ext_port
404+NameVirtualHost *:$ext_port
405+<VirtualHost *:$ext_port>
406+ ServerName $(unit-get private-address)
407+ SSLEngine on
408+ SSLCertificateFile /etc/apache2/ssl/$CHARM/cert
409+ SSLCertificateKeyFile /etc/apache2/ssl/$CHARM/key
410+ ProxyPass / http://localhost:$int_port/
411+ ProxyPassReverse / http://localhost:$int_port/
412+ ProxyPreserveHost on
413+</VirtualHost>
414+<Proxy *>
415+ Order deny,allow
416+ Allow from all
417+</Proxy>
418+<Location />
419+ Order allow,deny
420+ Allow from all
421+</Location>
422+END
423+ a2ensite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" &&
424+ http_restart=1
425+ done
426+ if [[ -n "$http_restart" ]] ; then
427+ service apache2 restart
428+ fi
429+}
430+
431+##########################################################################
432+# Description: Ensure HTTPS reverse proxying is disabled for given port
433+# mappings.
434+# Parameters: Variable number of proxy port mappings as
435+# $internal:$external.
436+# Returns: 0 if reverse proxy is not active for all portmaps, 1 on error.
437+##########################################################################
438+disable_https() {
439+ local port_maps="$@"
440+ local http_restart=""
441+ juju-log "Ensuring HTTPS disabled for $port_maps."
442+ ( [[ ! -d /etc/apache2 ]] || [[ ! -d /etc/apache2/ssl/$CHARM ]] ) && return 0
443+ for port_map in $port_maps ; do
444+ local ext_port=$(echo $port_map | cut -d: -f1)
445+ local int_port=$(echo $port_map | cut -d: -f2)
446+ if [[ -e /etc/apache2/sites-available/${CHARM}_${ext_port} ]] ; then
447+ juju-log "Disabling HTTPS reverse proxy for $CHARM $port_map."
448+ a2dissite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" &&
449+ http_restart=1
450+ fi
451+ done
452+ if [[ -n "$http_restart" ]] ; then
453+ service apache2 restart
454+ fi
455+}
456+
457+
458+##########################################################################
459+# Description: Ensures HTTPS is either enabled or disabled for given port
460+# mapping.
461+# Parameters: Variable number of proxy port mappings as
462+# $internal:$external.
463+# Returns: 0 if HTTPS reverse proxy is in place, 1 if it is not.
464+##########################################################################
465+setup_https() {
466+ # configure https via apache reverse proxying either
467+ # using certs provided by config or keystone.
468+ [[ -z "$CHARM" ]] &&
469+ error_out "setup_https(): CHARM not set."
470+ if ! https ; then
471+ disable_https $@
472+ else
473+ enable_https $@
474+ fi
475+}
476+
477+##########################################################################
478+# Description: Determine correct API server listening port based on
479+# existence of HTTPS reverse proxy and/or haproxy.
480+# Paremeters: The standard public port for given service.
481+# Returns: The correct listening port for API service.
482+##########################################################################
483+determine_api_port() {
484+ local public_port="$1"
485+ local i=0
486+ ( [[ -n "$(peer_units)" ]] || is_clustered >/dev/null 2>&1 ) && i=$[$i + 1]
487+ https >/dev/null 2>&1 && i=$[$i + 1]
488+ echo $[$public_port - $[$i * 10]]
489+}
490+
491+##########################################################################
492+# Description: Determine correct proxy listening port based on public IP +
493+# existence of HTTPS reverse proxy.
494+# Paremeters: The standard public port for given service.
495+# Returns: The correct listening port for haproxy service public address.
496+##########################################################################
497+determine_haproxy_port() {
498+ local public_port="$1"
499+ local i=0
500+ https >/dev/null 2>&1 && i=$[$i + 1]
501+ echo $[$public_port - $[$i * 10]]
502 }
503
504 ##########################################################################
505
506=== modified file 'revision'
507--- revision 2013-03-08 21:08:07 +0000
508+++ revision 2013-03-08 21:36:22 +0000
509@@ -1,1 +1,1 @@
510-15
511+20

Subscribers

People subscribed via source and target branches