Merge lp:~james-page/charms/precise/openstack-dashboard/ha-support into lp:~openstack-charmers/charms/precise/openstack-dashboard/ha-support

Proposed by James Page
Status: Merged
Merged at revision: 28
Proposed branch: lp:~james-page/charms/precise/openstack-dashboard/ha-support
Merge into: lp:~openstack-charmers/charms/precise/openstack-dashboard/ha-support
Diff against target: 596 lines (+331/-68)
4 files modified
config.yaml (+25/-0)
hooks/horizon-common (+45/-29)
hooks/horizon-relations (+36/-17)
hooks/lib/openstack-common (+225/-22)
To merge this branch: bzr merge lp:~james-page/charms/precise/openstack-dashboard/ha-support
Reviewer Review Type Date Requested Status
Adam Gandelman (community) Needs Fixing
Review via email: mp+152712@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Page (james-page) wrote :

This update adds a few features:

1) HTTPS configuration options ssl_cert and ssl_key

HTTPS is on by default using snakeoil certs; this allows a user provided cert to be used.

2) Config options to

a) enable online compression (useful for use with trunk)
b) enable debugging

3) HA + HTTPS support

A little different in that Apache listens on 70/433 and haproxy fronts apache in full, using the tcp option for the SSL connections. This provides end-to-end SSL security.

General - I made this charm a little less bumpy by configuring the haproxy instance up-front; the cluster hook simply adds new nodes to the haproxy config using reload.

Revision history for this message
Adam Gandelman (gandelman-a) wrote :

Hey James, some comments:

- Please add a note to config.yaml or docs stating ssl_cert + ssl_key are expected to be input as base64 encoded.

- Once I realized that, I did a juju set openstack-dashboard ssl_key="$(cat /tmp/key | base64)" ssl_cert="$(cat tmp/cert | base64)" but was getting base64 decode errors in config-changed, needed to update the horizon-common cert config function:

   key=$2
- echo $cert | base64 -d > /etc/ssl/certs/dashboard.cert
- echo $key | base64 -d > /etc/ssl/private/dashboard.key
+ echo $cert | base64 -di > /etc/ssl/certs/dashboard.cert
+ echo $key | base64 -di > /etc/ssl/private/dashboard.key
   chmod 0600 /etc/ssl/private/dashboard.key

- I don't think its a blocker, but one issue with putting SSL termination behind haproxy is that all service units are sharing the same certificate. When deploying with custom certificates, its the deployers responsibility to provide a certificate that will work for all dashboard hosts. When using hacluster/VIP, a cert signed for a single common name (the VIP) would work. However, if we want to use keystone-provided certificates (I hope to), when there is no VIP/hacluster, the generated certificate will only be signed for the eligible leader at the time the keystone <-> dashboard relation is made. This will work okay initially, but if that initial leader host goes away and requests start hitting another node in the service group, a certificate for an invalid host will be used and a browser warning. This is less of an issue for the dashboard since it ends with a browser warning, but more of an issue if we plan on using this configuration for the internal openstack API traffic.

- Also, can you please include the latest openstack-common helper from lp:~openstack-charmers/openstack-charm-helpers/ha-helpers and rebase your changes to that code against the latest? It'll make syncing these changes easier once this merges, and I expect we'll be using the haproxy changes elsewhere.

review: Needs Fixing
42. By James Page

Fixup base64 encoding features

43. By James Page

Rebase from target

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'config.yaml'
--- config.yaml 2013-02-13 16:00:50 +0000
+++ config.yaml 2013-03-13 11:10:27 +0000
@@ -49,3 +49,28 @@
49 description: |49 description: |
50 Default multicast port number that will be used to communicate between50 Default multicast port number that will be used to communicate between
51 HA Cluster nodes.51 HA Cluster nodes.
52 # User provided SSL cert and key
53 ssl_cert:
54 type: string
55 description: |
56 Base64 encoded SSL certificate to install and use for API ports.
57 .
58 juju set swift-proxy ssl_cert="$(cat cert | base64)" \
59 ssl_key="$(cat key | base64)"
60 .
61 Setting this value (and ssl_key) will enable reverse proxying, point
62 Swifts's entry in the Keystone catalog to use https, and override
63 any certficiate and key issued by Keystone (if it is configured to
64 do so).
65 ssl_key:
66 type: string
67 description: |
68 Base64 encoded SSL key to use with certificate specified as ssl_cert.
69 offline-compression:
70 type: string
71 default: "yes"
72 description: Use pre-generated Less compiled JS and CSS.
73 debug:
74 type: string
75 default: "no"
76 description: Show Django debug messages.
5277
=== modified file 'hooks/horizon-common'
--- hooks/horizon-common 2013-02-14 14:22:41 +0000
+++ hooks/horizon-common 2013-03-13 11:10:27 +0000
@@ -1,4 +1,5 @@
1#!/bin/bash1#!/bin/bash
2# vim: set ts=2:et
23
3CHARM="openstack-dashboard"4CHARM="openstack-dashboard"
45
@@ -16,15 +17,28 @@
16 local key=$1 value=$217 local key=$1 value=$2
17 [[ -z "$key" ]] || [[ -z "$value" ]] &&18 [[ -z "$key" ]] || [[ -z "$value" ]] &&
18 juju-log "$CHARM set_or_update: ERROR - missing parameters" && return 119 juju-log "$CHARM set_or_update: ERROR - missing parameters" && return 1
19 grep -q "^$key = \"$value\"" "$LOCAL_SETTINGS" &&20 if [ "$value" == "True" ] || [ "$value" == "False" ]; then
20 juju-log "$CHARM set_or_update: $key = $value already set" && return 021 grep -q "^$key = $value" "$LOCAL_SETTINGS" &&
22 juju-log "$CHARM set_or_update: $key = $value already set" && return 0
23 else
24 grep -q "^$key = \"$value\"" "$LOCAL_SETTINGS" &&
25 juju-log "$CHARM set_or_update: $key = $value already set" && return 0
26 fi
21 if grep -q "^$key = " "$LOCAL_SETTINGS" ; then27 if grep -q "^$key = " "$LOCAL_SETTINGS" ; then
22 juju-log "$CHARM set_or_update: Setting $key = $value"28 juju-log "$CHARM set_or_update: Setting $key = $value"
23 cp "$LOCAL_SETTINGS" /etc/openstack-dashboard/local_settings.last29 cp "$LOCAL_SETTINGS" /etc/openstack-dashboard/local_settings.last
24 sed -i "s|\(^$key = \).*|\1\"$value\"|g" "$LOCAL_SETTINGS" || return 130 if [ "$value" == "True" ] || [ "$value" == "False" ]; then
31 sed -i "s|\(^$key = \).*|\1$value|g" "$LOCAL_SETTINGS" || return 1
32 else
33 sed -i "s|\(^$key = \).*|\1\"$value\"|g" "$LOCAL_SETTINGS" || return 1
34 fi
25 else35 else
26 juju-log "$CHARM set_or_update: Adding $key = $value"36 juju-log "$CHARM set_or_update: Adding $key = $value"
27 echo "$key = \"$value\"" >>$LOCAL_SETTINGS || return 137 if [ "$value" == "True" ] || [ "$value" == "False" ]; then
38 echo "$key = $value" >>$LOCAL_SETTINGS || return 1
39 else
40 echo "$key = \"$value\"" >>$LOCAL_SETTINGS || return 1
41 fi
28 fi42 fi
29 return 043 return 0
30}44}
@@ -46,35 +60,37 @@
46 export JUJU_REMOTE_UNIT=$(relation-list -r $r_id | head -n1)60 export JUJU_REMOTE_UNIT=$(relation-list -r $r_id | head -n1)
47 export JUJU_RELATION="identity-service"61 export JUJU_RELATION="identity-service"
48 export JUJU_RELATION_ID="$r_id"62 export JUJU_RELATION_ID="$r_id"
49 local ks_host=$(relation-get -r $r_id private-address)63 local service_host=$(relation-get -r $r_id service_host)
50 if [[ -n "$ks_host" ]] ; then64 local service_port=$(relation-get -r $r_id service_port)
51 service_url="http://$ks_host:5000/v2.0"65 if [[ -n "$service_host" ]] && [[ -n "$service_port" ]] ; then
66 service_url="http://$service_host:$service_port/v2.0"
52 set_or_update OPENSTACK_KEYSTONE_URL "$service_url"67 set_or_update OPENSTACK_KEYSTONE_URL "$service_url"
53 fi68 fi
54 fi69 fi
55}70}
5671
57configure_memcached() {72configure_apache() {
58 tfile=`mktemp /etc/.memcached.conf.XXXXXXX`73 # Reconfigure to listen on provided port
59 cat > $tfile << EOF74 a2ensite default-ssl || :
60# memcache config file - juju openstack-dashboard75 a2enmod ssl || :
61-d76 for ports in $@; do
62logfile /var/log/memcached.log77 from_port=$(echo $ports | cut -d : -f 1)
63-m 6478 to_port=$(echo $ports | cut -d : -f 2)
64-p 1121179 sed -i -e "s/$from_port/$to_port/g" /etc/apache2/ports.conf
65-u memcache80 for site in $(ls -1 /etc/apache2/sites-available); do
66-l 0.0.0.081 sed -i -e "s/$from_port/$to_port/g" \
67# TODO: Enable SASL auth82 /etc/apache2/sites-available/$site
68# -S83 done
69EOF84 done
70 new_hash=`md5sum $tfile|cut -d' ' -f1`
71 old_hash=`md5sum /etc/memcached.conf|cut -d' ' -f1`
72 if [ "$new_hash" != "$old_hash" ]; then
73 juju-log "Reconfiguring memcache for clustering"
74 # TODO: setup SASL authentication
75 mv -f /etc/memcached.conf /etc/memcached.conf.$old_hash
76 mv -f $tfile /etc/memcached.conf
77 service memcached restart
78 fi
79}85}
8086
87configure_apache_cert() {
88 cert=$1
89 key=$2
90 echo $cert | base64 -di > /etc/ssl/certs/dashboard.cert
91 echo $key | base64 -di > /etc/ssl/private/dashboard.key
92 chmod 0600 /etc/ssl/private/dashboard.key
93 sed -i -e "s|\(.*SSLCertificateFile\).*|\1 /etc/ssl/certs/dashboard.cert|g" \
94 -e "s|\(.*SSLCertificateKeyFile\).*|\1 /etc/ssl/private/dashboard.key|g" \
95 /etc/apache2/sites-available/default-ssl
96}
8197
=== modified file 'hooks/horizon-relations'
--- hooks/horizon-relations 2013-02-27 05:27:51 +0000
+++ hooks/horizon-relations 2013-03-13 11:10:27 +0000
@@ -50,6 +50,12 @@
50 juju-log "Insufficient information to configure keystone url"50 juju-log "Insufficient information to configure keystone url"
51 exit 051 exit 0
52 fi52 fi
53 local ca_cert=$(relation-get ca_cert)
54 if [ -n "$ca_cert" ]; then
55 juju-log "Installing Keystone supplied CA cert."
56 echo $ca_cert | base64 -di > /usr/local/share/ca-certificates/keystone_juju_ca_cert.crt
57 update-ca-certificates --fresh
58 fi
53 service_url="http://${service_host}:${service_port}/v2.0"59 service_url="http://${service_host}:${service_port}/v2.0"
54 juju-log "$CHARM: Configuring Horizon to access keystone @ $service_url."60 juju-log "$CHARM: Configuring Horizon to access keystone @ $service_url."
55 set_or_update OPENSTACK_KEYSTONE_URL "$service_url"61 set_or_update OPENSTACK_KEYSTONE_URL "$service_url"
@@ -95,16 +101,39 @@
95 keystone_joined "$relid"101 keystone_joined "$relid"
96 done102 done
97103
98 service apache2 reload104 if [ "$(config-get offline-compression)" != "yes" ]; then
99105 set_or_update COMPRESS_OFFLINE False
106 apt-get install -y nodejs node-less
107 else
108 set_or_update COMPRESS_OFFLINE True
109 fi
110
111 # Configure default HAProxy + Apache config
112 if [ -n "$(config-get ssl_cert)" ] && \
113 [ -n "$(config-get ssl_key)" ]; then
114 configure_apache_cert "$(config-get ssl_cert)" "$(config-get ssl_key)"
115 fi
116
117 if [ "$(config-get debug)" != "yes" ]; then
118 set_or_update DEBUG False
119 else
120 set_or_update DEBUG True
121 fi
122
123 # Reconfigure Apache Ports
124 configure_apache "80:70" "443:433"
125 service apache2 restart
126 configure_haproxy "dash_insecure:80:70:http dash_secure:443:433:tcp"
127 service haproxy restart
100}128}
101129
102function cluster_changed() {130function cluster_changed() {
103 configure_haproxy "openstack_dashboard:80"131 configure_haproxy "dash_insecure:80:70:http dash_secure:443:433:tcp"
104 configure_memcached132 service haproxy reload
105}133}
106134
107function ha_relation_joined() {135function ha_relation_joined() {
136 # Configure HA Cluster
108 local corosync_bindiface=`config-get ha-bindiface`137 local corosync_bindiface=`config-get ha-bindiface`
109 local corosync_mcastport=`config-get ha-mcastport`138 local corosync_mcastport=`config-get ha-mcastport`
110 local vip=`config-get vip`139 local vip=`config-get vip`
@@ -126,28 +155,19 @@
126 init_services="{155 init_services="{
127'res_horizon_haproxy':'haproxy'156'res_horizon_haproxy':'haproxy'
128}"157}"
129 groups="{158 clones="{
130'grp_horizon_haproxy':'res_horizon_vip res_horizon_haproxy'159'cl_horizon_haproxy':'res_horizon_haproxy'
131}"160}"
132 relation-set corosync_bindiface=$corosync_bindiface \161 relation-set corosync_bindiface=$corosync_bindiface \
133 corosync_mcastport=$corosync_mcastport \162 corosync_mcastport=$corosync_mcastport \
134 resources="$resources" resource_params="$resource_params" \163 resources="$resources" resource_params="$resource_params" \
135 init_services="$init_services" groups="$groups"164 init_services="$init_services" clones="$clones"
136 else165 else
137 juju-log "Insufficient configuration data to configure hacluster"166 juju-log "Insufficient configuration data to configure hacluster"
138 exit 1167 exit 1
139 fi168 fi
140}169}
141170
142
143function ha_relation_changed() {
144 local clustered=`relation-get clustered`
145 if [ -n "$clustered" ]; then
146 open-port 10080
147 fi
148}
149
150
151juju-log "$CHARM: Running hook $ARG0."171juju-log "$CHARM: Running hook $ARG0."
152case $ARG0 in172case $ARG0 in
153 "install") install_hook ;;173 "install") install_hook ;;
@@ -161,5 +181,4 @@
161 "cluster-relation-changed") cluster_changed ;;181 "cluster-relation-changed") cluster_changed ;;
162 "cluster-relation-departed") cluster_changed ;;182 "cluster-relation-departed") cluster_changed ;;
163 "ha-relation-joined") ha_relation_joined ;;183 "ha-relation-joined") ha_relation_joined ;;
164 "ha-relation-changed") ha_relation_changed ;;
165esac184esac
166185
=== modified file 'hooks/lib/openstack-common'
--- hooks/lib/openstack-common 2013-03-08 21:15:45 +0000
+++ hooks/lib/openstack-common 2013-03-13 11:10:27 +0000
@@ -321,18 +321,16 @@
321321
322HAPROXY_CFG=/etc/haproxy/haproxy.cfg322HAPROXY_CFG=/etc/haproxy/haproxy.cfg
323HAPROXY_DEFAULT=/etc/default/haproxy323HAPROXY_DEFAULT=/etc/default/haproxy
324
325##########################################################################324##########################################################################
326# Description: Configures HAProxy services for Openstack API's325# Description: Configures HAProxy services for Openstack API's
327# Parameters:326# Parameters:
328# Space delimited list of service:port combinations for which327# Space delimited list of service:port:mode combinations for which
329# haproxy service configuration should be generated for. The function328# haproxy service configuration should be generated for. The function
330# assumes the name of the peer relation is 'cluster' and that every329# assumes the name of the peer relation is 'cluster' and that every
331# service unit in the peer relation is running the same services.330# service unit in the peer relation is running the same services.
332#331#
333# The HAProxy service will listen on port + 10000.332# Example
334# Example:333# configure_haproxy cinder_api:8776:8756:tcp nova_api:8774:8764:http
335# configure_haproxy cinder_api:12345 nova_api:9999
336##########################################################################334##########################################################################
337configure_haproxy() {335configure_haproxy() {
338 local address=`unit-get private-address`336 local address=`unit-get private-address`
@@ -354,8 +352,8 @@
354 retries 3352 retries 3
355 timeout queue 1000353 timeout queue 1000
356 timeout connect 1000354 timeout connect 1000
357 timeout client 10000355 timeout client 30000
358 timeout server 10000356 timeout server 30000
359357
360listen stats :8888358listen stats :8888
361 mode http359 mode http
@@ -368,14 +366,20 @@
368EOF366EOF
369 for service in $@; do367 for service in $@; do
370 local service_name=$(echo $service | cut -d : -f 1)368 local service_name=$(echo $service | cut -d : -f 1)
371 local api_listen_port=$(echo $service | cut -d : -f 2)369 local haproxy_listen_port=$(echo $service | cut -d : -f 2)
372 local haproxy_listen_port=$(($api_listen_port + 10000))370 local api_listen_port=$(echo $service | cut -d : -f 3)
371 local mode=$(echo $service | cut -d : -f 4)
372 juju-log "Adding haproxy configuration entry for $service "\
373 "($haproxy_listen_port -> $api_listen_port)"
373 cat >> $HAPROXY_CFG << EOF374 cat >> $HAPROXY_CFG << EOF
374listen $service_name 0.0.0.0:$haproxy_listen_port375listen $service_name 0.0.0.0:$haproxy_listen_port
375 balance roundrobin376 balance roundrobin
376 option tcplog377 mode $mode
378 option ${mode}log
377 server $name $address:$api_listen_port check379 server $name $address:$api_listen_port check
378EOF380EOF
381 local r_id=""
382 local unit=""
379 for r_id in `relation-ids cluster`; do383 for r_id in `relation-ids cluster`; do
380 for unit in `relation-list -r $r_id`; do384 for unit in `relation-list -r $r_id`; do
381 local unit_name=${unit////-}385 local unit_name=${unit////-}
@@ -388,6 +392,7 @@
388 done392 done
389 done393 done
390 echo "ENABLED=1" > $HAPROXY_DEFAULT394 echo "ENABLED=1" > $HAPROXY_DEFAULT
395 service haproxy restart
391}396}
392397
393##########################################################################398##########################################################################
@@ -395,18 +400,20 @@
395# Returns: 0 if configured, 1 if not configured400# Returns: 0 if configured, 1 if not configured
396##########################################################################401##########################################################################
397is_clustered() {402is_clustered() {
403 local r_id=""
404 local unit=""
398 for r_id in $(relation-ids ha); do405 for r_id in $(relation-ids ha); do
399 if [ -n "$r_id" ]; then406 if [ -n "$r_id" ]; then
400 for unit in $(relation-list -r $r_id); do407 for unit in $(relation-list -r $r_id); do
401 clustered=$(relation-get -r $r_id clustered $unit)408 clustered=$(relation-get -r $r_id clustered $unit)
402 if [ -n "$clustered" ]; then409 if [ -n "$clustered" ]; then
403 echo "Unit is clustered"410 juju-log "Unit is haclustered"
404 return 0411 return 0
405 fi412 fi
406 done413 done
407 fi414 fi
408 done415 done
409 echo "Unit is not clustered"416 juju-log "Unit is not haclustered"
410 return 1417 return 1
411}418}
412419
@@ -415,6 +422,7 @@
415##########################################################################422##########################################################################
416peer_units() {423peer_units() {
417 local peers=""424 local peers=""
425 local r_id=""
418 for r_id in $(relation-ids cluster); do426 for r_id in $(relation-ids cluster); do
419 peers="$peers $(relation-list -r $r_id)"427 peers="$peers $(relation-list -r $r_id)"
420 done428 done
@@ -433,11 +441,11 @@
433 echo "Comparing $JUJU_UNIT_NAME with peers: $peers"441 echo "Comparing $JUJU_UNIT_NAME with peers: $peers"
434 local r_unit_no=$(echo $peer | cut -d / -f 2)442 local r_unit_no=$(echo $peer | cut -d / -f 2)
435 if (($r_unit_no<$l_unit_no)); then443 if (($r_unit_no<$l_unit_no)); then
436 echo "Not oldest peer; deferring"444 juju-log "Not oldest peer; deferring"
437 return 1445 return 1
438 fi446 fi
439 done447 done
440 echo "Oldest peer; might take charge?"448 juju-log "Oldest peer; might take charge?"
441 return 0449 return 0
442}450}
443451
@@ -451,13 +459,13 @@
451eligible_leader() {459eligible_leader() {
452 if is_clustered; then460 if is_clustered; then
453 if ! is_leader $1; then461 if ! is_leader $1; then
454 echo 'Deferring action to CRM leader'462 juju-log 'Deferring action to CRM leader'
455 return 1463 return 1
456 fi464 fi
457 else465 else
458 peers=$(peer_units)466 peers=$(peer_units)
459 if [ -n "$peers" ] && ! oldest_peer "$peers"; then467 if [ -n "$peers" ] && ! oldest_peer "$peers"; then
460 echo 'Deferring action to oldest service unit.'468 juju-log 'Deferring action to oldest service unit.'
461 return 1469 return 1
462 fi470 fi
463 fi471 fi
@@ -469,14 +477,14 @@
469# Returns: 0 if peered, 1 if not peered477# Returns: 0 if peered, 1 if not peered
470##########################################################################478##########################################################################
471is_peered() {479is_peered() {
472 r_id=$(relation-ids cluster)480 local r_id=$(relation-ids cluster)
473 if [ -n "$r_id" ]; then481 if [ -n "$r_id" ]; then
474 if [ -n "$(relation-list -r $r_id)" ]; then482 if [ -n "$(relation-list -r $r_id)" ]; then
475 echo "Unit peered"483 juju-log "Unit peered"
476 return 0484 return 0
477 fi485 fi
478 fi486 fi
479 echo "Unit not peered"487 juju-log "Unit not peered"
480 return 1488 return 1
481}489}
482490
@@ -489,12 +497,207 @@
489 hostname=`hostname`497 hostname=`hostname`
490 if [ -x /usr/sbin/crm ]; then498 if [ -x /usr/sbin/crm ]; then
491 if crm resource show $1 | grep -q $hostname; then499 if crm resource show $1 | grep -q $hostname; then
492 echo "$hostname is cluster leader"500 juju-log "$hostname is cluster leader."
493 return 0501 return 0
494 fi502 fi
495 fi503 fi
496 echo "$hostname is not cluster leader"504 juju-log "$hostname is not cluster leader."
497 return 1505 return 1
506}
507
508##########################################################################
509# Description: Determines whether enough data has been provided in
510# configuration or relation data to configure HTTPS.
511# Parameters: None
512# Returns: 0 if HTTPS can be configured, 1 if not.
513##########################################################################
514https() {
515 local r_id=""
516 if [[ -n "$(config-get ssl_cert)" ]] &&
517 [[ -n "$(config-get ssl_key)" ]] ; then
518 return 0
519 fi
520 for r_id in $(relation-ids identity-service) ; do
521 for unit in $(relation-list -r $r_id) ; do
522 if [[ "$(relation-get -r $r_id https_keystone $unit)" == "True" ]] &&
523 [[ -n "$(relation-get -r $r_id ssl_cert $unit)" ]] &&
524 [[ -n "$(relation-get -r $r_id ssl_key $unit)" ]] &&
525 [[ -n "$(relation-get -r $r_id ca_cert $unit)" ]] ; then
526 return 0
527 fi
528 done
529 done
530 return 1
531}
532
533##########################################################################
534# Description: For a given number of port mappings, configures apache2
535# HTTPs local reverse proxying using certficates and keys provided in
536# either configuration data (preferred) or relation data. Assumes ports
537# are not in use (calling charm should ensure that).
538# Parameters: Variable number of proxy port mappings as
539# $internal:$external.
540# Returns: 0 if reverse proxy(s) have been configured, 0 if not.
541##########################################################################
542enable_https() {
543 local port_maps="$@"
544 local http_restart=""
545 juju-log "Enabling HTTPS for port mappings: $port_maps."
546
547 # allow overriding of keystone provided certs with those set manually
548 # in config.
549 local cert=$(config-get ssl_cert)
550 local key=$(config-get ssl_key)
551 local ca_cert=""
552 if [[ -z "$cert" ]] || [[ -z "$key" ]] ; then
553 juju-log "Inspecting identity-service relations for SSL certificate."
554 local r_id=""
555 cert=""
556 key=""
557 ca_cert=""
558 for r_id in $(relation-ids identity-service) ; do
559 for unit in $(relation-list -r $r_id) ; do
560 [[ -z "$cert" ]] && cert="$(relation-get -r $r_id ssl_cert $unit)"
561 [[ -z "$key" ]] && key="$(relation-get -r $r_id ssl_key $unit)"
562 [[ -z "$ca_cert" ]] && ca_cert="$(relation-get -r $r_id ca_cert $unit)"
563 done
564 done
565 [[ -n "$cert" ]] && cert=$(echo $cert | base64 -di)
566 [[ -n "$key" ]] && key=$(echo $key | base64 -di)
567 [[ -n "$ca_cert" ]] && ca_cert=$(echo $ca_cert | base64 -di)
568 else
569 juju-log "Using SSL certificate provided in service config."
570 fi
571
572 [[ -z "$cert" ]] || [[ -z "$key" ]] &&
573 juju-log "Expected but could not find SSL certificate data, not "\
574 "configuring HTTPS!" && return 1
575
576 apt-get -y install apache2
577 a2enmod ssl proxy proxy_http | grep -v "To activate the new configuration" &&
578 http_restart=1
579
580 mkdir -p /etc/apache2/ssl/$CHARM
581 echo "$cert" >/etc/apache2/ssl/$CHARM/cert
582 echo "$key" >/etc/apache2/ssl/$CHARM/key
583 if [[ -n "$ca_cert" ]] ; then
584 juju-log "Installing Keystone supplied CA cert."
585 echo "$ca_cert" >/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt
586 update-ca-certificates --fresh
587
588 # XXX TODO: Find a better way of exporting this?
589 if [[ "$CHARM" == "nova-cloud-controller" ]] ; then
590 [[ -e /var/www/keystone_juju_ca_cert.crt ]] &&
591 rm -rf /var/www/keystone_juju_ca_cert.crt
592 ln -s /usr/local/share/ca-certificates/keystone_juju_ca_cert.crt \
593 /var/www/keystone_juju_ca_cert.crt
594 fi
595
596 fi
597 for port_map in $port_maps ; do
598 local ext_port=$(echo $port_map | cut -d: -f1)
599 local int_port=$(echo $port_map | cut -d: -f2)
600 juju-log "Creating apache2 reverse proxy vhost for $port_map."
601 cat >/etc/apache2/sites-available/${CHARM}_${ext_port} <<END
602Listen $ext_port
603NameVirtualHost *:$ext_port
604<VirtualHost *:$ext_port>
605 ServerName $(unit-get private-address)
606 SSLEngine on
607 SSLCertificateFile /etc/apache2/ssl/$CHARM/cert
608 SSLCertificateKeyFile /etc/apache2/ssl/$CHARM/key
609 ProxyPass / http://localhost:$int_port/
610 ProxyPassReverse / http://localhost:$int_port/
611 ProxyPreserveHost on
612</VirtualHost>
613<Proxy *>
614 Order deny,allow
615 Allow from all
616</Proxy>
617<Location />
618 Order allow,deny
619 Allow from all
620</Location>
621END
622 a2ensite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" &&
623 http_restart=1
624 done
625 if [[ -n "$http_restart" ]] ; then
626 service apache2 restart
627 fi
628}
629
630##########################################################################
631# Description: Ensure HTTPS reverse proxying is disabled for given port
632# mappings.
633# Parameters: Variable number of proxy port mappings as
634# $internal:$external.
635# Returns: 0 if reverse proxy is not active for all portmaps, 1 on error.
636##########################################################################
637disable_https() {
638 local port_maps="$@"
639 local http_restart=""
640 juju-log "Ensuring HTTPS disabled for $port_maps."
641 ( [[ ! -d /etc/apache2 ]] || [[ ! -d /etc/apache2/ssl/$CHARM ]] ) && return 0
642 for port_map in $port_maps ; do
643 local ext_port=$(echo $port_map | cut -d: -f1)
644 local int_port=$(echo $port_map | cut -d: -f2)
645 if [[ -e /etc/apache2/sites-available/${CHARM}_${ext_port} ]] ; then
646 juju-log "Disabling HTTPS reverse proxy for $CHARM $port_map."
647 a2dissite ${CHARM}_${ext_port} | grep -v "To activate the new configuration" &&
648 http_restart=1
649 fi
650 done
651 if [[ -n "$http_restart" ]] ; then
652 service apache2 restart
653 fi
654}
655
656
657##########################################################################
658# Description: Ensures HTTPS is either enabled or disabled for given port
659# mapping.
660# Parameters: Variable number of proxy port mappings as
661# $internal:$external.
662# Returns: 0 if HTTPS reverse proxy is in place, 1 if it is not.
663##########################################################################
664setup_https() {
665 # configure https via apache reverse proxying either
666 # using certs provided by config or keystone.
667 [[ -z "$CHARM" ]] &&
668 error_out "setup_https(): CHARM not set."
669 if ! https ; then
670 disable_https $@
671 else
672 enable_https $@
673 fi
674}
675
676##########################################################################
677# Description: Determine correct API server listening port based on
678# existence of HTTPS reverse proxy and/or haproxy.
679# Paremeters: The standard public port for given service.
680# Returns: The correct listening port for API service.
681##########################################################################
682determine_api_port() {
683 local public_port="$1"
684 local i=0
685 ( [[ -n "$(peer_units)" ]] || is_clustered >/dev/null 2>&1 ) && i=$[$i + 1]
686 https >/dev/null 2>&1 && i=$[$i + 1]
687 echo $[$public_port - $[$i * 10]]
688}
689
690##########################################################################
691# Description: Determine correct proxy listening port based on public IP +
692# existence of HTTPS reverse proxy.
693# Paremeters: The standard public port for given service.
694# Returns: The correct listening port for haproxy service public address.
695##########################################################################
696determine_haproxy_port() {
697 local public_port="$1"
698 local i=0
699 https >/dev/null 2>&1 && i=$[$i + 1]
700 echo $[$public_port - $[$i * 10]]
498}701}
499702
500##########################################################################703##########################################################################

Subscribers

People subscribed via source and target branches