Merge lp:~chad.smith/charms/precise/openstack-dashboard/openstack-dashboard-internal-port-health-update into lp:~charmers/charms/precise/openstack-dashboard/trunk
- Precise Pangolin (12.04)
- openstack-dashboard-internal-port-health-update
- Merge into trunk
Proposed by
Chad Smith
Status: | Superseded |
---|---|
Proposed branch: | lp:~chad.smith/charms/precise/openstack-dashboard/openstack-dashboard-internal-port-health-update |
Merge into: | lp:~charmers/charms/precise/openstack-dashboard/trunk |
Diff against target: |
887 lines (+703/-22) 11 files modified
config.yaml (+55/-7) hooks/horizon-common (+49/-8) hooks/horizon-relations (+90/-3) hooks/lib/openstack-common (+456/-3) metadata.yaml (+6/-0) revision (+1/-1) scripts/add_to_cluster (+2/-0) scripts/health_checks.d/service_ports_live (+13/-0) scripts/health_checks.d/service_running (+13/-0) scripts/health_checks.d/service_url_checks (+16/-0) scripts/remove_from_cluster (+2/-0) |
To merge this branch: | bzr merge lp:~chad.smith/charms/precise/openstack-dashboard/openstack-dashboard-internal-port-health-update |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Adam Gandelman | Pending | ||
Review via email: mp+155775@code.launchpad.net |
Commit message
Description of the change
Update health script to use the new internal service port numbers 70 and 433 as they have been updated in the rest of the charm for new HA configuration.
To post a comment you must log in.
Unmerged revisions
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-11 21:59:22 +0000 |
3 | +++ config.yaml 2013-03-27 15:50:37 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | options: |
6 | - openstack-origin: |
7 | + openstack-origin: |
8 | default: distro |
9 | type: string |
10 | description: | |
11 | @@ -14,15 +14,63 @@ |
12 | Note that updating this setting to a source that is known to |
13 | provide a later version of OpenStack will trigger a software |
14 | upgrade. |
15 | - webroot: |
16 | + webroot: |
17 | default: "/horizon" |
18 | type: string |
19 | description: | |
20 | - Directory where application will be accessible, relative to |
21 | - http://$hostname/. |
22 | - default-role: |
23 | + Directory where application will be accessible, relative to |
24 | + http://$hostname/. |
25 | + default-role: |
26 | default: "Member" |
27 | type: string |
28 | description: | |
29 | - Default role for Horizon operations that will be created in |
30 | - Keystone upon introduction of an identity-service relation. |
31 | + Default role for Horizon operations that will be created in |
32 | + Keystone upon introduction of an identity-service relation. |
33 | + vip: |
34 | + type: string |
35 | + description: "Virtual IP to use to front openstack dashboard ha configuration" |
36 | + vip_iface: |
37 | + type: string |
38 | + default: eth0 |
39 | + description: "Network Interface where to place the Virtual IP" |
40 | + vip_cidr: |
41 | + type: int |
42 | + default: 24 |
43 | + description: "Netmask that will be used for the Virtual IP" |
44 | + ha-bindiface: |
45 | + type: string |
46 | + default: eth0 |
47 | + description: | |
48 | + Default network interface on which HA cluster will bind to communication |
49 | + with the other members of the HA Cluster. |
50 | + ha-mcastport: |
51 | + type: int |
52 | + default: 5410 |
53 | + description: | |
54 | + Default multicast port number that will be used to communicate between |
55 | + HA Cluster nodes. |
56 | + # User provided SSL cert and key |
57 | + ssl_cert: |
58 | + type: string |
59 | + description: | |
60 | + Base64 encoded SSL certificate to install and use for API ports. |
61 | + . |
62 | + juju set swift-proxy ssl_cert="$(cat cert | base64)" \ |
63 | + ssl_key="$(cat key | base64)" |
64 | + . |
65 | + Setting this value (and ssl_key) will enable reverse proxying, point |
66 | + Swifts's entry in the Keystone catalog to use https, and override |
67 | + any certficiate and key issued by Keystone (if it is configured to |
68 | + do so). |
69 | + ssl_key: |
70 | + type: string |
71 | + description: | |
72 | + Base64 encoded SSL key to use with certificate specified as ssl_cert. |
73 | + offline-compression: |
74 | + type: string |
75 | + default: "yes" |
76 | + description: Use pre-generated Less compiled JS and CSS. |
77 | + debug: |
78 | + type: string |
79 | + default: "no" |
80 | + description: Show Django debug messages. |
81 | |
82 | === added symlink 'hooks/cluster-relation-changed' |
83 | === target is u'horizon-relations' |
84 | === added symlink 'hooks/cluster-relation-departed' |
85 | === target is u'horizon-relations' |
86 | === added symlink 'hooks/ha-relation-changed' |
87 | === target is u'horizon-relations' |
88 | === added symlink 'hooks/ha-relation-joined' |
89 | === target is u'horizon-relations' |
90 | === modified file 'hooks/horizon-common' |
91 | --- hooks/horizon-common 2012-10-10 23:32:24 +0000 |
92 | +++ hooks/horizon-common 2013-03-27 15:50:37 +0000 |
93 | @@ -1,8 +1,9 @@ |
94 | #!/bin/bash |
95 | +# vim: set ts=2:et |
96 | |
97 | CHARM="openstack-dashboard" |
98 | |
99 | -PACKAGES="openstack-dashboard openstack-dashboard-ubuntu-theme python-keystoneclient python-memcache memcached" |
100 | +PACKAGES="openstack-dashboard openstack-dashboard-ubuntu-theme python-keystoneclient python-memcache memcached haproxy" |
101 | LOCAL_SETTINGS="/etc/openstack-dashboard/local_settings.py" |
102 | |
103 | if [[ -e "$CHARM_DIR/lib/openstack-common" ]] ; then |
104 | @@ -16,15 +17,28 @@ |
105 | local key=$1 value=$2 |
106 | [[ -z "$key" ]] || [[ -z "$value" ]] && |
107 | juju-log "$CHARM set_or_update: ERROR - missing parameters" && return 1 |
108 | - grep -q "^$key = \"$value\"" "$LOCAL_SETTINGS" && |
109 | - juju-log "$CHARM set_or_update: $key = $value already set" && return 0 |
110 | + if [ "$value" == "True" ] || [ "$value" == "False" ]; then |
111 | + grep -q "^$key = $value" "$LOCAL_SETTINGS" && |
112 | + juju-log "$CHARM set_or_update: $key = $value already set" && return 0 |
113 | + else |
114 | + grep -q "^$key = \"$value\"" "$LOCAL_SETTINGS" && |
115 | + juju-log "$CHARM set_or_update: $key = $value already set" && return 0 |
116 | + fi |
117 | if grep -q "^$key = " "$LOCAL_SETTINGS" ; then |
118 | juju-log "$CHARM set_or_update: Setting $key = $value" |
119 | cp "$LOCAL_SETTINGS" /etc/openstack-dashboard/local_settings.last |
120 | - sed -i "s|\(^$key = \).*|\1\"$value\"|g" "$LOCAL_SETTINGS" || return 1 |
121 | + if [ "$value" == "True" ] || [ "$value" == "False" ]; then |
122 | + sed -i "s|\(^$key = \).*|\1$value|g" "$LOCAL_SETTINGS" || return 1 |
123 | + else |
124 | + sed -i "s|\(^$key = \).*|\1\"$value\"|g" "$LOCAL_SETTINGS" || return 1 |
125 | + fi |
126 | else |
127 | juju-log "$CHARM set_or_update: Adding $key = $value" |
128 | - echo "$key = \"$value\"" >>$LOCAL_SETTINGS || return 1 |
129 | + if [ "$value" == "True" ] || [ "$value" == "False" ]; then |
130 | + echo "$key = $value" >>$LOCAL_SETTINGS || return 1 |
131 | + else |
132 | + echo "$key = \"$value\"" >>$LOCAL_SETTINGS || return 1 |
133 | + fi |
134 | fi |
135 | return 0 |
136 | } |
137 | @@ -46,10 +60,37 @@ |
138 | export JUJU_REMOTE_UNIT=$(relation-list -r $r_id | head -n1) |
139 | export JUJU_RELATION="identity-service" |
140 | export JUJU_RELATION_ID="$r_id" |
141 | - local ks_host=$(relation-get -r $r_id private-address) |
142 | - if [[ -n "$ks_host" ]] ; then |
143 | - service_url="http://$ks_host:5000/v2.0" |
144 | + local service_host=$(relation-get -r $r_id service_host) |
145 | + local service_port=$(relation-get -r $r_id service_port) |
146 | + if [[ -n "$service_host" ]] && [[ -n "$service_port" ]] ; then |
147 | + service_url="http://$service_host:$service_port/v2.0" |
148 | set_or_update OPENSTACK_KEYSTONE_URL "$service_url" |
149 | fi |
150 | fi |
151 | } |
152 | + |
153 | +configure_apache() { |
154 | + # Reconfigure to listen on provided port |
155 | + a2ensite default-ssl || : |
156 | + a2enmod ssl || : |
157 | + for ports in $@; do |
158 | + from_port=$(echo $ports | cut -d : -f 1) |
159 | + to_port=$(echo $ports | cut -d : -f 2) |
160 | + sed -i -e "s/$from_port/$to_port/g" /etc/apache2/ports.conf |
161 | + for site in $(ls -1 /etc/apache2/sites-available); do |
162 | + sed -i -e "s/$from_port/$to_port/g" \ |
163 | + /etc/apache2/sites-available/$site |
164 | + done |
165 | + done |
166 | +} |
167 | + |
168 | +configure_apache_cert() { |
169 | + cert=$1 |
170 | + key=$2 |
171 | + echo $cert | base64 -di > /etc/ssl/certs/dashboard.cert |
172 | + echo $key | base64 -di > /etc/ssl/private/dashboard.key |
173 | + chmod 0600 /etc/ssl/private/dashboard.key |
174 | + sed -i -e "s|\(.*SSLCertificateFile\).*|\1 /etc/ssl/certs/dashboard.cert|g" \ |
175 | + -e "s|\(.*SSLCertificateKeyFile\).*|\1 /etc/ssl/private/dashboard.key|g" \ |
176 | + /etc/apache2/sites-available/default-ssl |
177 | +} |
178 | |
179 | === modified file 'hooks/horizon-relations' |
180 | --- hooks/horizon-relations 2013-01-11 21:59:22 +0000 |
181 | +++ hooks/horizon-relations 2013-03-27 15:50:37 +0000 |
182 | @@ -44,7 +44,19 @@ |
183 | } |
184 | |
185 | function keystone_changed { |
186 | - service_url="http://$(relation-get private-address):5000/v2.0" |
187 | + local service_host=$(relation-get service_host) |
188 | + local service_port=$(relation-get service_port) |
189 | + if [ -z "${service_host}" ] || [ -z "${service_port}" ]; then |
190 | + juju-log "Insufficient information to configure keystone url" |
191 | + exit 0 |
192 | + fi |
193 | + local ca_cert=$(relation-get ca_cert) |
194 | + if [ -n "$ca_cert" ]; then |
195 | + juju-log "Installing Keystone supplied CA cert." |
196 | + echo $ca_cert | base64 -di > /usr/local/share/ca-certificates/keystone_juju_ca_cert.crt |
197 | + update-ca-certificates --fresh |
198 | + fi |
199 | + service_url="http://${service_host}:${service_port}/v2.0" |
200 | juju-log "$CHARM: Configuring Horizon to access keystone @ $service_url." |
201 | set_or_update OPENSTACK_KEYSTONE_URL "$service_url" |
202 | service apache2 restart |
203 | @@ -73,6 +85,15 @@ |
204 | set_or_update LOGIN_URL "$web_root/auth/login" |
205 | set_or_update LOGIN_REDIRECT_URL "$web_root" |
206 | |
207 | + # Save our scriptrc env variables for health checks |
208 | + declare -a env_vars=( |
209 | + 'OPENSTACK_URL_HORIZON="http://localhost:70'$web_root'|Login+-+OpenStack"' |
210 | + 'OPENSTACK_SERVICE_HORIZON=apache2' |
211 | + 'OPENSTACK_PORT_HORIZON_SSL=433' |
212 | + 'OPENSTACK_PORT_HORIZON=70') |
213 | + save_script_rc ${env_vars[@]} |
214 | + |
215 | + |
216 | # Set default role and trigger a identity-service relation event to |
217 | # ensure role is created in keystone. |
218 | set_or_update OPENSTACK_KEYSTONE_DEFAULT_ROLE "$(config-get default-role)" |
219 | @@ -81,8 +102,71 @@ |
220 | keystone_joined "$relid" |
221 | done |
222 | |
223 | - service apache2 reload |
224 | - |
225 | + if [ "$(config-get offline-compression)" != "yes" ]; then |
226 | + set_or_update COMPRESS_OFFLINE False |
227 | + apt-get install -y nodejs node-less |
228 | + else |
229 | + set_or_update COMPRESS_OFFLINE True |
230 | + fi |
231 | + |
232 | + # Configure default HAProxy + Apache config |
233 | + if [ -n "$(config-get ssl_cert)" ] && \ |
234 | + [ -n "$(config-get ssl_key)" ]; then |
235 | + configure_apache_cert "$(config-get ssl_cert)" "$(config-get ssl_key)" |
236 | + fi |
237 | + |
238 | + if [ "$(config-get debug)" != "yes" ]; then |
239 | + set_or_update DEBUG False |
240 | + else |
241 | + set_or_update DEBUG True |
242 | + fi |
243 | + |
244 | + # Reconfigure Apache Ports |
245 | + configure_apache "80:70" "443:433" |
246 | + service apache2 restart |
247 | + configure_haproxy "dash_insecure:80:70:http dash_secure:443:433:tcp" |
248 | + service haproxy restart |
249 | +} |
250 | + |
251 | +function cluster_changed() { |
252 | + configure_haproxy "dash_insecure:80:70:http dash_secure:443:433:tcp" |
253 | + service haproxy reload |
254 | +} |
255 | + |
256 | +function ha_relation_joined() { |
257 | + # Configure HA Cluster |
258 | + local corosync_bindiface=`config-get ha-bindiface` |
259 | + local corosync_mcastport=`config-get ha-mcastport` |
260 | + local vip=`config-get vip` |
261 | + local vip_iface=`config-get vip_iface` |
262 | + local vip_cidr=`config-get vip_cidr` |
263 | + if [ -n "$vip" ] && [ -n "$vip_iface" ] && \ |
264 | + [ -n "$vip_cidr" ] && [ -n "$corosync_bindiface" ] && \ |
265 | + [ -n "$corosync_mcastport" ]; then |
266 | + # TODO: This feels horrible but the data required by the hacluster |
267 | + # charm is quite complex and is python ast parsed. |
268 | + resources="{ |
269 | +'res_horizon_vip':'ocf:heartbeat:IPaddr2', |
270 | +'res_horizon_haproxy':'lsb:haproxy' |
271 | +}" |
272 | + resource_params="{ |
273 | +'res_horizon_vip': 'params ip=\"$vip\" cidr_netmask=\"$vip_cidr\" nic=\"$vip_iface\"', |
274 | +'res_horizon_haproxy': 'op monitor interval=\"5s\"' |
275 | +}" |
276 | + init_services="{ |
277 | +'res_horizon_haproxy':'haproxy' |
278 | +}" |
279 | + clones="{ |
280 | +'cl_horizon_haproxy':'res_horizon_haproxy' |
281 | +}" |
282 | + relation-set corosync_bindiface=$corosync_bindiface \ |
283 | + corosync_mcastport=$corosync_mcastport \ |
284 | + resources="$resources" resource_params="$resource_params" \ |
285 | + init_services="$init_services" clones="$clones" |
286 | + else |
287 | + juju-log "Insufficient configuration data to configure hacluster" |
288 | + exit 1 |
289 | + fi |
290 | } |
291 | |
292 | juju-log "$CHARM: Running hook $ARG0." |
293 | @@ -95,4 +179,7 @@ |
294 | "identity-service-relation-joined") keystone_joined;; |
295 | "identity-service-relation-changed") keystone_changed;; |
296 | "config-changed") config_changed;; |
297 | + "cluster-relation-changed") cluster_changed ;; |
298 | + "cluster-relation-departed") cluster_changed ;; |
299 | + "ha-relation-joined") ha_relation_joined ;; |
300 | esac |
301 | |
302 | === modified file 'hooks/lib/openstack-common' |
303 | --- hooks/lib/openstack-common 2013-01-11 18:30:45 +0000 |
304 | +++ hooks/lib/openstack-common 2013-03-27 15:50:37 +0000 |
305 | @@ -165,8 +165,9 @@ |
306 | fi |
307 | |
308 | # have a guess based on the deb string provided |
309 | - if [[ "${rel:0:3}" == "deb" ]]; then |
310 | - CODENAMES="diablo essex folsom grizzly" |
311 | + if [[ "${rel:0:3}" == "deb" ]] || \ |
312 | + [[ "${rel:0:3}" == "ppa" ]] ; then |
313 | + CODENAMES="diablo essex folsom grizzly havana" |
314 | for cname in $CODENAMES; do |
315 | if echo $rel | grep -q $cname; then |
316 | codename=$cname |
317 | @@ -178,11 +179,13 @@ |
318 | |
319 | get_os_codename_package() { |
320 | local pkg_vers=$(dpkg -l | grep "$1" | awk '{ print $3 }') || echo "none" |
321 | + pkg_vers=$(echo $pkg_vers | cut -d: -f2) # epochs |
322 | case "${pkg_vers:0:6}" in |
323 | "2011.2") echo "diablo" ;; |
324 | "2012.1") echo "essex" ;; |
325 | "2012.2") echo "folsom" ;; |
326 | "2013.1") echo "grizzly" ;; |
327 | + "2013.2") echo "havana" ;; |
328 | esac |
329 | } |
330 | |
331 | @@ -191,7 +194,8 @@ |
332 | "diablo") echo "2011.2" ;; |
333 | "essex") echo "2012.1" ;; |
334 | "folsom") echo "2012.2" ;; |
335 | - "grizzly") echo "2012.3" ;; |
336 | + "grizzly") echo "2013.1" ;; |
337 | + "havana") echo "2013.2" ;; |
338 | esac |
339 | } |
340 | |
341 | @@ -314,3 +318,452 @@ |
342 | echo "$found" |
343 | return 0 |
344 | } |
345 | + |
346 | +HAPROXY_CFG=/etc/haproxy/haproxy.cfg |
347 | +HAPROXY_DEFAULT=/etc/default/haproxy |
348 | +########################################################################## |
349 | +# Description: Configures HAProxy services for Openstack API's |
350 | +# Parameters: |
351 | +# Space delimited list of service:port:mode combinations for which |
352 | +# haproxy service configuration should be generated for. The function |
353 | +# assumes the name of the peer relation is 'cluster' and that every |
354 | +# service unit in the peer relation is running the same services. |
355 | +# |
356 | +# Services that do not specify :mode in parameter will default to http. |
357 | +# |
358 | +# Example |
359 | +# configure_haproxy cinder_api:8776:8756:tcp nova_api:8774:8764:http |
360 | +########################################################################## |
361 | +configure_haproxy() { |
362 | + local address=`unit-get private-address` |
363 | + local name=${JUJU_UNIT_NAME////-} |
364 | + cat > $HAPROXY_CFG << EOF |
365 | +global |
366 | + log 127.0.0.1 local0 |
367 | + log 127.0.0.1 local1 notice |
368 | + maxconn 20000 |
369 | + user haproxy |
370 | + group haproxy |
371 | + spread-checks 0 |
372 | + |
373 | +defaults |
374 | + log global |
375 | + mode http |
376 | + option httplog |
377 | + option dontlognull |
378 | + retries 3 |
379 | + timeout queue 1000 |
380 | + timeout connect 1000 |
381 | + timeout client 30000 |
382 | + timeout server 30000 |
383 | + |
384 | +listen stats :8888 |
385 | + mode http |
386 | + stats enable |
387 | + stats hide-version |
388 | + stats realm Haproxy\ Statistics |
389 | + stats uri / |
390 | + stats auth admin:password |
391 | + |
392 | +EOF |
393 | + for service in $@; do |
394 | + local service_name=$(echo $service | cut -d : -f 1) |
395 | + local haproxy_listen_port=$(echo $service | cut -d : -f 2) |
396 | + local api_listen_port=$(echo $service | cut -d : -f 3) |
397 | + local mode=$(echo $service | cut -d : -f 4) |
398 | + [[ -z "$mode" ]] && mode="http" |
399 | + juju-log "Adding haproxy configuration entry for $service "\ |
400 | + "($haproxy_listen_port -> $api_listen_port)" |
401 | + cat >> $HAPROXY_CFG << EOF |
402 | +listen $service_name 0.0.0.0:$haproxy_listen_port |
403 | + balance roundrobin |
404 | + mode $mode |
405 | + option ${mode}log |
406 | + server $name $address:$api_listen_port check |
407 | +EOF |
408 | + local r_id="" |
409 | + local unit="" |
410 | + for r_id in `relation-ids cluster`; do |
411 | + for unit in `relation-list -r $r_id`; do |
412 | + local unit_name=${unit////-} |
413 | + local unit_address=`relation-get -r $r_id private-address $unit` |
414 | + if [ -n "$unit_address" ]; then |
415 | + echo " server $unit_name $unit_address:$api_listen_port check" \ |
416 | + >> $HAPROXY_CFG |
417 | + fi |
418 | + done |
419 | + done |
420 | + done |
421 | + echo "ENABLED=1" > $HAPROXY_DEFAULT |
422 | + service haproxy restart |
423 | +} |
424 | + |
425 | +########################################################################## |
426 | +# Description: Query HA interface to determine is cluster is configured |
427 | +# Returns: 0 if configured, 1 if not configured |
428 | +########################################################################## |
429 | +is_clustered() { |
430 | + local r_id="" |
431 | + local unit="" |
432 | + for r_id in $(relation-ids ha); do |
433 | + if [ -n "$r_id" ]; then |
434 | + for unit in $(relation-list -r $r_id); do |
435 | + clustered=$(relation-get -r $r_id clustered $unit) |
436 | + if [ -n "$clustered" ]; then |
437 | + juju-log "Unit is haclustered" |
438 | + return 0 |
439 | + fi |
440 | + done |
441 | + fi |
442 | + done |
443 | + juju-log "Unit is not haclustered" |
444 | + return 1 |
445 | +} |
446 | + |
447 | +########################################################################## |
448 | +# Description: Return a list of all peers in cluster relations |
449 | +########################################################################## |
450 | +peer_units() { |
451 | + local peers="" |
452 | + local r_id="" |
453 | + for r_id in $(relation-ids cluster); do |
454 | + peers="$peers $(relation-list -r $r_id)" |
455 | + done |
456 | + echo $peers |
457 | +} |
458 | + |
459 | +########################################################################## |
460 | +# Description: Determines whether the current unit is the oldest of all |
461 | +# its peers - supports partial leader election |
462 | +# Returns: 0 if oldest, 1 if not |
463 | +########################################################################## |
464 | +oldest_peer() { |
465 | + peers=$1 |
466 | + local l_unit_no=$(echo $JUJU_UNIT_NAME | cut -d / -f 2) |
467 | + for peer in $peers; do |
468 | + echo "Comparing $JUJU_UNIT_NAME with peers: $peers" |
469 | + local r_unit_no=$(echo $peer | cut -d / -f 2) |
470 | + if (($r_unit_no<$l_unit_no)); then |
471 | + juju-log "Not oldest peer; deferring" |
472 | + return 1 |
473 | + fi |
474 | + done |
475 | + juju-log "Oldest peer; might take charge?" |
476 | + return 0 |
477 | +} |
478 | + |
479 | +########################################################################## |
480 | +# Description: Determines whether the current service units is the |
481 | +# leader within a) a cluster of its peers or b) across a |
482 | +# set of unclustered peers. |
483 | +# Parameters: CRM resource to check ownership of if clustered |
484 | +# Returns: 0 if leader, 1 if not |
485 | +########################################################################## |
486 | +eligible_leader() { |
487 | + if is_clustered; then |
488 | + if ! is_leader $1; then |
489 | + juju-log 'Deferring action to CRM leader' |
490 | + return 1 |
491 | + fi |
492 | + else |
493 | + peers=$(peer_units) |
494 | + if [ -n "$peers" ] && ! oldest_peer "$peers"; then |
495 | + juju-log 'Deferring action to oldest service unit.' |
496 | + return 1 |
497 | + fi |
498 | + fi |
499 | + return 0 |
500 | +} |
501 | + |
502 | +########################################################################## |
503 | +# Description: Query Cluster peer interface to see if peered |
504 | +# Returns: 0 if peered, 1 if not peered |
505 | +########################################################################## |
506 | +is_peered() { |
507 | + local r_id=$(relation-ids cluster) |
508 | + if [ -n "$r_id" ]; then |
509 | + if [ -n "$(relation-list -r $r_id)" ]; then |
510 | + juju-log "Unit peered" |
511 | + return 0 |
512 | + fi |
513 | + fi |
514 | + juju-log "Unit not peered" |
515 | + return 1 |
516 | +} |
517 | + |
518 | +########################################################################## |
519 | +# Description: Determines whether host is owner of clustered services |
520 | +# Parameters: Name of CRM resource to check ownership of |
521 | +# Returns: 0 if leader, 1 if not leader |
522 | +########################################################################## |
523 | +is_leader() { |
524 | + hostname=`hostname` |
525 | + if [ -x /usr/sbin/crm ]; then |
526 | + if crm resource show $1 | grep -q $hostname; then |
527 | + juju-log "$hostname is cluster leader." |
528 | + return 0 |
529 | + fi |
530 | + fi |
531 | + juju-log "$hostname is not cluster leader." |
532 | + return 1 |
533 | +} |
534 | + |
535 | +########################################################################## |
536 | +# Description: Determines whether enough data has been provided in |
537 | +# configuration or relation data to configure HTTPS. |
538 | +# Parameters: None |
539 | +# Returns: 0 if HTTPS can be configured, 1 if not. |
540 | +########################################################################## |
541 | +https() { |
542 | + local r_id="" |
543 | + if [[ -n "$(config-get ssl_cert)" ]] && |
544 | + [[ -n "$(config-get ssl_key)" ]] ; then |
545 | + return 0 |
546 | + fi |
547 | + for r_id in $(relation-ids identity-service) ; do |
548 | + for unit in $(relation-list -r $r_id) ; do |
549 | + if [[ "$(relation-get -r $r_id https_keystone $unit)" == "True" ]] && |
550 | + [[ -n "$(relation-get -r $r_id ssl_cert $unit)" ]] && |
551 | + [[ -n "$(relation-get -r $r_id ssl_key $unit)" ]] && |
552 | + [[ -n "$(relation-get -r $r_id ca_cert $unit)" ]] ; then |
553 | + return 0 |
554 | + fi |
555 | + done |
556 | + done |
557 | + return 1 |
558 | +} |
559 | + |
560 | +########################################################################## |
561 | +# Description: For a given number of port mappings, configures apache2 |
562 | +# HTTPs local reverse proxying using certficates and keys provided in |
563 | +# either configuration data (preferred) or relation data. Assumes ports |
564 | +# are not in use (calling charm should ensure that). |
565 | +# Parameters: Variable number of proxy port mappings as |
566 | +# $internal:$external. |
567 | +# Returns: 0 if reverse proxy(s) have been configured, 0 if not. |
568 | +########################################################################## |
569 | +enable_https() { |
570 | + local port_maps="$@" |
571 | + local http_restart="" |
572 | + juju-log "Enabling HTTPS for port mappings: $port_maps." |
573 | + |
574 | + # allow overriding of keystone provided certs with those set manually |
575 | + # in config. |
576 | + local cert=$(config-get ssl_cert) |
577 | + local key=$(config-get ssl_key) |
578 | + local ca_cert="" |
579 | + if [[ -z "$cert" ]] || [[ -z "$key" ]] ; then |
580 | + juju-log "Inspecting identity-service relations for SSL certificate." |
581 | + local r_id="" |
582 | + cert="" |
583 | + key="" |
584 | + ca_cert="" |
585 | + for r_id in $(relation-ids identity-service) ; do |
586 | + for unit in $(relation-list -r $r_id) ; do |
587 | + [[ -z "$cert" ]] && cert="$(relation-get -r $r_id ssl_cert $unit)" |
588 | + [[ -z "$key" ]] && key="$(relation-get -r $r_id ssl_key $unit)" |
589 | + [[ -z "$ca_cert" ]] && ca_cert="$(relation-get -r $r_id ca_cert $unit)" |
590 | + done |
591 | + done |
592 | + [[ -n "$cert" ]] && cert=$(echo $cert | base64 -di) |
593 | + [[ -n "$key" ]] && key=$(echo $key | base64 -di) |
594 | + [[ -n "$ca_cert" ]] && ca_cert=$(echo $ca_cert | base64 -di) |
595 | + else |
596 | + juju-log "Using SSL certificate provided in service config." |
597 | + fi |
598 | + |
599 | + [[ -z "$cert" ]] || [[ -z "$key" ]] && |
600 | + juju-log "Expected but could not find SSL certificate data, not "\ |
601 | + "configuring HTTPS!" && return 1 |
602 | + |
603 | + apt-get -y install apache2 |
604 | + a2enmod ssl proxy proxy_http | grep -v "To activate the new configuration" && |
605 | + http_restart=1 |
606 | + |
607 | + mkdir -p /etc/apache2/ssl/$CHARM |
608 | + echo "$cert" >/etc/apache2/ssl/$CHARM/cert |
609 | + echo "$key" >/etc/apache2/ssl/$CHARM/key |
610 | + if [[ -n "$ca_cert" ]] ; then |
611 | + juju-log "Installing Keystone supplied CA cert." |
612 | + echo "$ca_cert" >/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt |
613 | + update-ca-certificates --fresh |
614 | + |
615 | + # XXX TODO: Find a better way of exporting this? |
616 | + if [[ "$CHARM" == "nova-cloud-controller" ]] ; then |
617 | + [[ -e /var/www/keystone_juju_ca_cert.crt ]] && |
618 | + rm -rf /var/www/keystone_juju_ca_cert.crt |
619 | + ln -s /usr/local/share/ca-certificates/keystone_juju_ca_cert.crt \ |
620 | + /var/www/keystone_juju_ca_cert.crt |
621 | + fi |
622 | + |
623 | + fi |
624 | + for port_map in $port_maps ; do |
625 | + local ext_port=$(echo $port_map | cut -d: -f1) |
626 | + local int_port=$(echo $port_map | cut -d: -f2) |
627 | + juju-log "Creating apache2 reverse proxy vhost for $port_map." |
628 | + cat >/etc/apache2/sites-available/${CHARM}_${ext_port} <<END |
629 | +Listen $ext_port |
630 | +NameVirtualHost *:$ext_port |
631 | +<VirtualHost *:$ext_port> |
632 | + ServerName $(unit-get private-address) |
633 | + SSLEngine on |
634 | + SSLCertificateFile /etc/apache2/ssl/$CHARM/cert |
635 | + SSLCertificateKeyFile /etc/apache2/ssl/$CHARM/key |
636 | + ProxyPass / http://localhost:$int_port/ |
637 | + ProxyPassReverse / http://localhost:$int_port/ |
638 | + ProxyPreserveHost on |
639 | +</VirtualHost> |
640 | +<Proxy *> |
641 | + Order deny,allow |
642 | + Allow from all |
643 | +</Proxy> |
644 | +<Location /> |
645 | + Order allow,deny |
646 | + Allow from all |
647 | +</Location> |
648 | +END |
649 | + a2ensite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" && |
650 | + http_restart=1 |
651 | + done |
652 | + if [[ -n "$http_restart" ]] ; then |
653 | + service apache2 restart |
654 | + fi |
655 | +} |
656 | + |
657 | +########################################################################## |
658 | +# Description: Ensure HTTPS reverse proxying is disabled for given port |
659 | +# mappings. |
660 | +# Parameters: Variable number of proxy port mappings as |
661 | +# $internal:$external. |
662 | +# Returns: 0 if reverse proxy is not active for all portmaps, 1 on error. |
663 | +########################################################################## |
664 | +disable_https() { |
665 | + local port_maps="$@" |
666 | + local http_restart="" |
667 | + juju-log "Ensuring HTTPS disabled for $port_maps." |
668 | + ( [[ ! -d /etc/apache2 ]] || [[ ! -d /etc/apache2/ssl/$CHARM ]] ) && return 0 |
669 | + for port_map in $port_maps ; do |
670 | + local ext_port=$(echo $port_map | cut -d: -f1) |
671 | + local int_port=$(echo $port_map | cut -d: -f2) |
672 | + if [[ -e /etc/apache2/sites-available/${CHARM}_${ext_port} ]] ; then |
673 | + juju-log "Disabling HTTPS reverse proxy for $CHARM $port_map." |
674 | + a2dissite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" && |
675 | + http_restart=1 |
676 | + fi |
677 | + done |
678 | + if [[ -n "$http_restart" ]] ; then |
679 | + service apache2 restart |
680 | + fi |
681 | +} |
682 | + |
683 | + |
684 | +########################################################################## |
685 | +# Description: Ensures HTTPS is either enabled or disabled for given port |
686 | +# mapping. |
687 | +# Parameters: Variable number of proxy port mappings as |
688 | +# $internal:$external. |
689 | +# Returns: 0 if HTTPS reverse proxy is in place, 1 if it is not. |
690 | +########################################################################## |
691 | +setup_https() { |
692 | + # configure https via apache reverse proxying either |
693 | + # using certs provided by config or keystone. |
694 | + [[ -z "$CHARM" ]] && |
695 | + error_out "setup_https(): CHARM not set." |
696 | + if ! https ; then |
697 | + disable_https $@ |
698 | + else |
699 | + enable_https $@ |
700 | + fi |
701 | +} |
702 | + |
703 | +########################################################################## |
704 | +# Description: Determine correct API server listening port based on |
705 | +# existence of HTTPS reverse proxy and/or haproxy. |
706 | +# Paremeters: The standard public port for given service. |
707 | +# Returns: The correct listening port for API service. |
708 | +########################################################################## |
709 | +determine_api_port() { |
710 | + local public_port="$1" |
711 | + local i=0 |
712 | + ( [[ -n "$(peer_units)" ]] || is_clustered >/dev/null 2>&1 ) && i=$[$i + 1] |
713 | + https >/dev/null 2>&1 && i=$[$i + 1] |
714 | + echo $[$public_port - $[$i * 10]] |
715 | +} |
716 | + |
717 | +########################################################################## |
718 | +# Description: Determine correct proxy listening port based on public IP + |
719 | +# existence of HTTPS reverse proxy. |
720 | +# Paremeters: The standard public port for given service. |
721 | +# Returns: The correct listening port for haproxy service public address. |
722 | +########################################################################## |
723 | +determine_haproxy_port() { |
724 | + local public_port="$1" |
725 | + local i=0 |
726 | + https >/dev/null 2>&1 && i=$[$i + 1] |
727 | + echo $[$public_port - $[$i * 10]] |
728 | +} |
729 | + |
730 | +########################################################################## |
731 | +# Description: Print the value for a given config option in an OpenStack |
732 | +# .ini style configuration file. |
733 | +# Parameters: File path, option to retrieve, optional |
734 | +# section name (default=DEFAULT) |
735 | +# Returns: Prints value if set, prints nothing otherwise. |
736 | +########################################################################## |
737 | +local_config_get() { |
738 | + # return config values set in openstack .ini config files. |
739 | + # default placeholders starting (eg, %AUTH_HOST%) treated as |
740 | + # unset values. |
741 | + local file="$1" |
742 | + local option="$2" |
743 | + local section="$3" |
744 | + [[ -z "$section" ]] && section="DEFAULT" |
745 | + python -c " |
746 | +import ConfigParser |
747 | +config = ConfigParser.RawConfigParser() |
748 | +config.read('$file') |
749 | +try: |
750 | + value = config.get('$section', '$option') |
751 | +except: |
752 | + print '' |
753 | + exit(0) |
754 | +if value.startswith('%'): exit(0) |
755 | +print value |
756 | +" |
757 | +} |
758 | + |
759 | +########################################################################## |
760 | +# Description: Creates an rc file exporting environment variables to a |
761 | +# script_path local to the charm's installed directory. |
762 | +# Any charm scripts run outside the juju hook environment can source this |
763 | +# scriptrc to obtain updated config information necessary to perform health |
764 | +# checks or service changes |
765 | +# |
766 | +# Parameters: |
767 | +# An array of '=' delimited ENV_VAR:value combinations to export. |
768 | +# If optional script_path key is not provided in the array, script_path |
769 | +# defaults to scripts/scriptrc |
770 | +########################################################################## |
771 | +function save_script_rc { |
772 | + if [ ! -n "$JUJU_UNIT_NAME" ]; then |
773 | + echo "Error: Missing JUJU_UNIT_NAME environment variable" |
774 | + exit 1 |
775 | + fi |
776 | + # our default unit_path |
777 | + unit_path="/var/lib/juju/units/${JUJU_UNIT_NAME/\//-}/charm/scripts/scriptrc" |
778 | + echo $unit_path |
779 | + tmp_rc="/tmp/${JUJU_UNIT_NAME/\//-}rc" |
780 | + |
781 | + echo "#!/bin/bash" > $tmp_rc |
782 | + for env_var in "${@}" |
783 | + do |
784 | + if `echo $env_var | grep -q script_path`; then |
785 | + # well then we need to reset the new unit-local script path |
786 | + unit_path="/var/lib/juju/units/${JUJU_UNIT_NAME/\//-}/charm/${env_var/script_path=/}" |
787 | + else |
788 | + echo "export $env_var" >> $tmp_rc |
789 | + fi |
790 | + done |
791 | + chmod 755 $tmp_rc |
792 | + mv $tmp_rc $unit_path |
793 | +} |
794 | |
795 | === modified file 'metadata.yaml' |
796 | --- metadata.yaml 2012-08-09 20:29:51 +0000 |
797 | +++ metadata.yaml 2013-03-27 15:50:37 +0000 |
798 | @@ -8,3 +8,9 @@ |
799 | interface: mysql |
800 | identity-service: |
801 | interface: keystone |
802 | + ha: |
803 | + interface: hacluster |
804 | + scope: container |
805 | +peers: |
806 | + cluster: |
807 | + interface: openstack-dashboard-ha |
808 | |
809 | === modified file 'revision' |
810 | --- revision 2013-01-11 21:59:22 +0000 |
811 | +++ revision 2013-03-27 15:50:37 +0000 |
812 | @@ -1,1 +1,1 @@ |
813 | -22 |
814 | +27 |
815 | |
816 | === added directory 'scripts' |
817 | === added file 'scripts/add_to_cluster' |
818 | --- scripts/add_to_cluster 1970-01-01 00:00:00 +0000 |
819 | +++ scripts/add_to_cluster 2013-03-27 15:50:37 +0000 |
820 | @@ -0,0 +1,2 @@ |
821 | +#!/bin/bash |
822 | +crm node online |
823 | |
824 | === added directory 'scripts/health_checks.d' |
825 | === added file 'scripts/health_checks.d/service_ports_live' |
826 | --- scripts/health_checks.d/service_ports_live 1970-01-01 00:00:00 +0000 |
827 | +++ scripts/health_checks.d/service_ports_live 2013-03-27 15:50:37 +0000 |
828 | @@ -0,0 +1,13 @@ |
829 | +#!/bin/bash |
830 | +# Validate that service ports are active |
831 | +HEALTH_DIR=`dirname $0` |
832 | +SCRIPTS_DIR=`dirname $HEALTH_DIR` |
833 | +. $SCRIPTS_DIR/scriptrc |
834 | +set -e |
835 | + |
836 | +# Grab any OPENSTACK_PORT* environment variables |
837 | +openstack_ports=`env| awk -F '=' '(/OPENSTACK_PORT/){print $2}'` |
838 | +for port in $openstack_ports |
839 | +do |
840 | + netstat -ln | grep -q ":$port " |
841 | +done |
842 | |
843 | === added file 'scripts/health_checks.d/service_running' |
844 | --- scripts/health_checks.d/service_running 1970-01-01 00:00:00 +0000 |
845 | +++ scripts/health_checks.d/service_running 2013-03-27 15:50:37 +0000 |
846 | @@ -0,0 +1,13 @@ |
847 | +#!/bin/bash |
848 | +# Validate that service is running |
849 | +HEALTH_DIR=`dirname $0` |
850 | +SCRIPTS_DIR=`dirname $HEALTH_DIR` |
851 | +. $SCRIPTS_DIR/scriptrc |
852 | +set -e |
853 | + |
854 | +# Grab any OPENSTACK_SERVICE* environment variables |
855 | +openstack_service_names=`env| awk -F '=' '(/OPENSTACK_SERVICE/){print $2}'` |
856 | +for service_name in $openstack_service_names |
857 | +do |
858 | + service $service_name status 2>/dev/null | grep -q running |
859 | +done |
860 | |
861 | === added file 'scripts/health_checks.d/service_url_checks' |
862 | --- scripts/health_checks.d/service_url_checks 1970-01-01 00:00:00 +0000 |
863 | +++ scripts/health_checks.d/service_url_checks 2013-03-27 15:50:37 +0000 |
864 | @@ -0,0 +1,16 @@ |
865 | +#!/bin/bash |
866 | +# Validate that service urls return expected content |
867 | +HEALTH_DIR=`dirname $0` |
868 | +SCRIPTS_DIR=`dirname $HEALTH_DIR` |
869 | +. $SCRIPTS_DIR/scriptrc |
870 | +set -e |
871 | + |
872 | +# Grab any OPENSTACK_URL* environment variables and validate content response |
873 | +openstack_urls=`env| awk -F '=' '(/OPENSTACK_URL/){print $2 }'` |
874 | +for url_check in $openstack_urls |
875 | +do |
876 | + url=`echo $url_check| awk -F '|' '{print $1}'` |
877 | + expected_content=`echo $url_check| awk -F '|' '{print $2}'` |
878 | + wget -q -O - $url | grep -q "${expected_content//+/ }" |
879 | +done |
880 | + |
881 | |
882 | === added file 'scripts/remove_from_cluster' |
883 | --- scripts/remove_from_cluster 1970-01-01 00:00:00 +0000 |
884 | +++ scripts/remove_from_cluster 2013-03-27 15:50:37 +0000 |
885 | @@ -0,0 +1,2 @@ |
886 | +#!/bin/bash |
887 | +crm node standby |