Merge lp:~james-page/charm-helpers/multiple-https-networks into lp:charm-helpers

Proposed by James Page
Status: Merged
Merged at revision: 221
Proposed branch: lp:~james-page/charm-helpers/multiple-https-networks
Merge into: lp:charm-helpers
Diff against target: 638 lines (+313/-85)
7 files modified
charmhelpers/contrib/hahelpers/apache.py (+10/-3)
charmhelpers/contrib/hahelpers/cluster.py (+1/-2)
charmhelpers/contrib/openstack/context.py (+70/-24)
charmhelpers/contrib/openstack/templates/openstack_https_frontend (+9/-8)
tests/contrib/hahelpers/test_apache_utils.py (+34/-8)
tests/contrib/hahelpers/test_cluster_utils.py (+2/-2)
tests/contrib/openstack/test_os_contexts.py (+187/-38)
To merge this branch: bzr merge lp:~james-page/charm-helpers/multiple-https-networks
Reviewer Review Type Date Requested Status
Liam Young (community) Approve
Review via email: mp+235676@code.launchpad.net

Description of the change

This branch adds support for keystone signed certificates for multiple endpoints IP's for a single service.

It also retains backwards compatibility so that existing deploys don't break!

To post a comment you must log in.
220. By James Page

Fixup backwards compat, tidy lint

221. By James Page

Support unset cn, add test case

Revision history for this message
Liam Young (gnuoy) wrote :

Approve

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/contrib/hahelpers/apache.py'
--- charmhelpers/contrib/hahelpers/apache.py 2014-02-26 21:48:09 +0000
+++ charmhelpers/contrib/hahelpers/apache.py 2014-09-24 12:45:35 +0000
@@ -20,20 +20,27 @@
20)20)
2121
2222
23def get_cert():23def get_cert(cn=None):
24 # TODO: deal with multiple https endpoints via charm config
24 cert = config_get('ssl_cert')25 cert = config_get('ssl_cert')
25 key = config_get('ssl_key')26 key = config_get('ssl_key')
26 if not (cert and key):27 if not (cert and key):
27 log("Inspecting identity-service relations for SSL certificate.",28 log("Inspecting identity-service relations for SSL certificate.",
28 level=INFO)29 level=INFO)
29 cert = key = None30 cert = key = None
31 if cn:
32 ssl_cert_attr = 'ssl_cert_{}'.format(cn)
33 ssl_key_attr = 'ssl_key_{}'.format(cn)
34 else:
35 ssl_cert_attr = 'ssl_cert'
36 ssl_key_attr = 'ssl_key'
30 for r_id in relation_ids('identity-service'):37 for r_id in relation_ids('identity-service'):
31 for unit in relation_list(r_id):38 for unit in relation_list(r_id):
32 if not cert:39 if not cert:
33 cert = relation_get('ssl_cert',40 cert = relation_get(ssl_cert_attr,
34 rid=r_id, unit=unit)41 rid=r_id, unit=unit)
35 if not key:42 if not key:
36 key = relation_get('ssl_key',43 key = relation_get(ssl_key_attr,
37 rid=r_id, unit=unit)44 rid=r_id, unit=unit)
38 return (cert, key)45 return (cert, key)
3946
4047
=== modified file 'charmhelpers/contrib/hahelpers/cluster.py'
--- charmhelpers/contrib/hahelpers/cluster.py 2014-08-07 10:25:37 +0000
+++ charmhelpers/contrib/hahelpers/cluster.py 2014-09-24 12:45:35 +0000
@@ -139,10 +139,9 @@
139 return True139 return True
140 for r_id in relation_ids('identity-service'):140 for r_id in relation_ids('identity-service'):
141 for unit in relation_list(r_id):141 for unit in relation_list(r_id):
142 # TODO - needs fixing for new helper as ssl_cert/key suffixes with CN
142 rel_state = [143 rel_state = [
143 relation_get('https_keystone', rid=r_id, unit=unit),144 relation_get('https_keystone', rid=r_id, unit=unit),
144 relation_get('ssl_cert', rid=r_id, unit=unit),
145 relation_get('ssl_key', rid=r_id, unit=unit),
146 relation_get('ca_cert', rid=r_id, unit=unit),145 relation_get('ca_cert', rid=r_id, unit=unit),
147 ]146 ]
148 # NOTE: works around (LP: #1203241)147 # NOTE: works around (LP: #1203241)
149148
=== modified file 'charmhelpers/contrib/openstack/context.py'
--- charmhelpers/contrib/openstack/context.py 2014-08-06 03:02:27 +0000
+++ charmhelpers/contrib/openstack/context.py 2014-09-24 12:45:35 +0000
@@ -8,7 +8,6 @@
8 check_call8 check_call
9)9)
1010
11
12from charmhelpers.fetch import (11from charmhelpers.fetch import (
13 apt_install,12 apt_install,
14 filter_installed_packages,13 filter_installed_packages,
@@ -28,6 +27,11 @@
28 INFO27 INFO
29)28)
3029
30from charmhelpers.core.host import (
31 mkdir,
32 write_file
33)
34
31from charmhelpers.contrib.hahelpers.cluster import (35from charmhelpers.contrib.hahelpers.cluster import (
32 determine_apache_port,36 determine_apache_port,
33 determine_api_port,37 determine_api_port,
@@ -38,6 +42,7 @@
38from charmhelpers.contrib.hahelpers.apache import (42from charmhelpers.contrib.hahelpers.apache import (
39 get_cert,43 get_cert,
40 get_ca_cert,44 get_ca_cert,
45 install_ca_cert,
41)46)
4247
43from charmhelpers.contrib.openstack.neutron import (48from charmhelpers.contrib.openstack.neutron import (
@@ -47,6 +52,7 @@
47from charmhelpers.contrib.network.ip import (52from charmhelpers.contrib.network.ip import (
48 get_address_in_network,53 get_address_in_network,
49 get_ipv6_addr,54 get_ipv6_addr,
55 is_address_in_network
50)56)
5157
52CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'58CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
@@ -490,22 +496,36 @@
490 cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']496 cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']
491 check_call(cmd)497 check_call(cmd)
492498
493 def configure_cert(self):499 def configure_cert(self, cn=None):
494 if not os.path.isdir('/etc/apache2/ssl'):
495 os.mkdir('/etc/apache2/ssl')
496 ssl_dir = os.path.join('/etc/apache2/ssl/', self.service_namespace)500 ssl_dir = os.path.join('/etc/apache2/ssl/', self.service_namespace)
497 if not os.path.isdir(ssl_dir):501 mkdir(path=ssl_dir)
498 os.mkdir(ssl_dir)502 cert, key = get_cert(cn)
499 cert, key = get_cert()503 if cn:
500 with open(os.path.join(ssl_dir, 'cert'), 'w') as cert_out:504 cert_filename = 'cert_{}'.format(cn)
501 cert_out.write(b64decode(cert))505 key_filename = 'key_{}'.format(cn)
502 with open(os.path.join(ssl_dir, 'key'), 'w') as key_out:506 else:
503 key_out.write(b64decode(key))507 cert_filename = 'cert'
508 key_filename = 'key'
509 write_file(path=os.path.join(ssl_dir, cert_filename),
510 content=b64decode(cert))
511 write_file(path=os.path.join(ssl_dir, key_filename),
512 content=b64decode(key))
513
514 def configure_ca(self):
504 ca_cert = get_ca_cert()515 ca_cert = get_ca_cert()
505 if ca_cert:516 if ca_cert:
506 with open(CA_CERT_PATH, 'w') as ca_out:517 install_ca_cert(b64decode(ca_cert))
507 ca_out.write(b64decode(ca_cert))518
508 check_call(['update-ca-certificates'])519 def canonical_names(self):
520 '''Figure out which canonical names clients will access this service'''
521 cns = []
522 for r_id in relation_ids('identity-service'):
523 for unit in related_units(r_id):
524 rdata = relation_get(rid=r_id, unit=unit)
525 for k in rdata:
526 if k.startswith('ssl_key_'):
527 cns.append(k.lstrip('ssl_key_'))
528 return list(set(cns))
509529
510 def __call__(self):530 def __call__(self):
511 if isinstance(self.external_ports, basestring):531 if isinstance(self.external_ports, basestring):
@@ -513,21 +533,47 @@
513 if (not self.external_ports or not https()):533 if (not self.external_ports or not https()):
514 return {}534 return {}
515535
516 self.configure_cert()536 self.configure_ca()
517 self.enable_modules()537 self.enable_modules()
518538
519 ctxt = {539 ctxt = {
520 'namespace': self.service_namespace,540 'namespace': self.service_namespace,
521 'private_address': unit_get('private-address'),541 'endpoints': [],
522 'endpoints': []542 'ext_ports': []
523 }543 }
524 if is_clustered():544
525 ctxt['private_address'] = config('vip')545 for cn in self.canonical_names():
526 for api_port in self.external_ports:546 self.configure_cert(cn)
527 ext_port = determine_apache_port(api_port)547
528 int_port = determine_api_port(api_port)548 addresses = []
529 portmap = (int(ext_port), int(int_port))549 vips = []
530 ctxt['endpoints'].append(portmap)550 if config('vip'):
551 vips = config('vip').split()
552
553 for network_type in ['os-internal-network',
554 'os-admin-network',
555 'os-public-network']:
556 address = get_address_in_network(config(network_type),
557 unit_get('private-address'))
558 if len(vips) > 0 and is_clustered():
559 for vip in vips:
560 if is_address_in_network(config(network_type),
561 vip):
562 addresses.append((address, vip))
563 break
564 elif is_clustered():
565 addresses.append((address, config('vip')))
566 else:
567 addresses.append((address, address))
568
569 for address, endpoint in set(addresses):
570 for api_port in self.external_ports:
571 ext_port = determine_apache_port(api_port)
572 int_port = determine_api_port(api_port)
573 portmap = (address, endpoint, int(ext_port), int(int_port))
574 ctxt['endpoints'].append(portmap)
575 ctxt['ext_ports'].append(int(ext_port))
576 ctxt['ext_ports'] = list(set(ctxt['ext_ports']))
531 return ctxt577 return ctxt
532578
533579
534580
=== modified file 'charmhelpers/contrib/openstack/templates/openstack_https_frontend'
--- charmhelpers/contrib/openstack/templates/openstack_https_frontend 2013-07-19 23:31:35 +0000
+++ charmhelpers/contrib/openstack/templates/openstack_https_frontend 2014-09-24 12:45:35 +0000
@@ -1,16 +1,18 @@
1{% if endpoints -%}1{% if endpoints -%}
2{% for ext, int in endpoints -%}2{% for ext_port in ext_ports -%}
3Listen {{ ext }}3Listen {{ ext_port }}
4NameVirtualHost *:{{ ext }}4{% endfor -%}
5<VirtualHost *:{{ ext }}>5{% for address, endpoint, ext, int in endpoints -%}
6 ServerName {{ private_address }}6<VirtualHost {{ address }}:{{ ext }}>
7 ServerName {{ endpoint }}
7 SSLEngine on8 SSLEngine on
8 SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert9 SSLCertificateFile /etc/apache2/ssl/{{ namespace }}/cert_{{ endpoint }}
9 SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key10 SSLCertificateKeyFile /etc/apache2/ssl/{{ namespace }}/key_{{ endpoint }}
10 ProxyPass / http://localhost:{{ int }}/11 ProxyPass / http://localhost:{{ int }}/
11 ProxyPassReverse / http://localhost:{{ int }}/12 ProxyPassReverse / http://localhost:{{ int }}/
12 ProxyPreserveHost on13 ProxyPreserveHost on
13</VirtualHost>14</VirtualHost>
15{% endfor -%}
14<Proxy *>16<Proxy *>
15 Order deny,allow17 Order deny,allow
16 Allow from all18 Allow from all
@@ -19,5 +21,4 @@
19 Order allow,deny21 Order allow,deny
20 Allow from all22 Allow from all
21</Location>23</Location>
22{% endfor -%}
23{% endif -%}24{% endif -%}
2425
=== modified file 'tests/contrib/hahelpers/test_apache_utils.py'
--- tests/contrib/hahelpers/test_apache_utils.py 2014-04-22 15:42:41 +0000
+++ tests/contrib/hahelpers/test_apache_utils.py 2014-09-24 12:45:35 +0000
@@ -1,7 +1,7 @@
1from mock import patch1from mock import patch
22
3from testtools import TestCase3from testtools import TestCase
4from tests.helpers import patch_open4from tests.helpers import patch_open, FakeRelation
55
6import charmhelpers.contrib.hahelpers.apache as apache_utils6import charmhelpers.contrib.hahelpers.apache as apache_utils
77
@@ -29,6 +29,24 @@
29-----END CERTIFICATE-----29-----END CERTIFICATE-----
30'''30'''
3131
32IDENTITY_NEW_STYLE_CERTS = {
33 'identity:0': {
34 'keystone/0': {
35 'ssl_cert_test-cn': 'keystone_provided_cert',
36 'ssl_key_test-cn': 'keystone_provided_key',
37 }
38 }
39}
40
41IDENTITY_OLD_STYLE_CERTS = {
42 'identity:0': {
43 'keystone/0': {
44 'ssl_cert': 'keystone_provided_cert',
45 'ssl_key': 'keystone_provided_key',
46 }
47 }
48}
49
3250
33class ApacheUtilsTests(TestCase):51class ApacheUtilsTests(TestCase):
34 def setUp(self):52 def setUp(self):
@@ -54,7 +72,7 @@
54 'some_ca_cert', # config_get('ssl_cert')72 'some_ca_cert', # config_get('ssl_cert')
55 'some_ca_key', # config_Get('ssl_key')73 'some_ca_key', # config_Get('ssl_key')
56 ]74 ]
57 result = apache_utils.get_cert()75 result = apache_utils.get_cert('test-cn')
58 self.assertEquals(('some_ca_cert', 'some_ca_key'), result)76 self.assertEquals(('some_ca_cert', 'some_ca_key'), result)
5977
60 def test_get_ca_cert_from_config(self):78 def test_get_ca_cert_from_config(self):
@@ -63,12 +81,20 @@
6381
64 def test_get_cert_from_relation(self):82 def test_get_cert_from_relation(self):
65 self.config_get.return_value = None83 self.config_get.return_value = None
66 self.relation_ids.return_value = 'identity-service:0'84 rel = FakeRelation(IDENTITY_NEW_STYLE_CERTS)
67 self.relation_list.return_value = 'keystone/0'85 self.relation_ids.side_effect = rel.relation_ids
68 self.relation_get.side_effect = [86 self.relation_list.side_effect = rel.relation_units
69 'keystone_provided_cert',87 self.relation_get.side_effect = rel.get
70 'keystone_provided_key',88 result = apache_utils.get_cert('test-cn')
71 ]89 self.assertEquals(('keystone_provided_cert', 'keystone_provided_key'),
90 result)
91
92 def test_get_cert_from_relation_deprecated(self):
93 self.config_get.return_value = None
94 rel = FakeRelation(IDENTITY_OLD_STYLE_CERTS)
95 self.relation_ids.side_effect = rel.relation_ids
96 self.relation_list.side_effect = rel.relation_units
97 self.relation_get.side_effect = rel.get
72 result = apache_utils.get_cert()98 result = apache_utils.get_cert()
73 self.assertEquals(('keystone_provided_cert', 'keystone_provided_key'),99 self.assertEquals(('keystone_provided_cert', 'keystone_provided_key'),
74 result)100 result)
75101
=== modified file 'tests/contrib/hahelpers/test_cluster_utils.py'
--- tests/contrib/hahelpers/test_cluster_utils.py 2014-08-07 10:25:37 +0000
+++ tests/contrib/hahelpers/test_cluster_utils.py 2014-09-24 12:45:35 +0000
@@ -117,7 +117,7 @@
117 @patch.object(cluster_utils, 'peer_units')117 @patch.object(cluster_utils, 'peer_units')
118 @patch.object(cluster_utils, 'is_clustered')118 @patch.object(cluster_utils, 'is_clustered')
119 def test_is_is_elected_leader_unclustered(self, is_clustered,119 def test_is_is_elected_leader_unclustered(self, is_clustered,
120 peer_units, oldest_peer):120 peer_units, oldest_peer):
121 '''It detects it is the eligible leader in non-clustered peer group'''121 '''It detects it is the eligible leader in non-clustered peer group'''
122 is_clustered.return_value = False122 is_clustered.return_value = False
123 oldest_peer.return_value = True123 oldest_peer.return_value = True
@@ -127,7 +127,7 @@
127 @patch.object(cluster_utils, 'peer_units')127 @patch.object(cluster_utils, 'peer_units')
128 @patch.object(cluster_utils, 'is_clustered')128 @patch.object(cluster_utils, 'is_clustered')
129 def test_not_is_elected_leader_unclustered(self, is_clustered,129 def test_not_is_elected_leader_unclustered(self, is_clustered,
130 peer_units, oldest_peer):130 peer_units, oldest_peer):
131 '''It detects it is not the eligible leader in non-clustered group'''131 '''It detects it is not the eligible leader in non-clustered group'''
132 is_clustered.return_value = False132 is_clustered.return_value = False
133 oldest_peer.return_value = False133 oldest_peer.return_value = False
134134
=== modified file 'tests/contrib/openstack/test_os_contexts.py'
--- tests/contrib/openstack/test_os_contexts.py 2014-08-04 07:47:26 +0000
+++ tests/contrib/openstack/test_os_contexts.py 2014-09-24 12:45:35 +0000
@@ -59,6 +59,8 @@
59 relation = self.relation_data[rid][unit]59 relation = self.relation_data[rid][unit]
60 except KeyError:60 except KeyError:
61 return None61 return None
62 if attribute is None:
63 return relation
62 if attribute in relation:64 if attribute in relation:
63 return relation[attribute]65 return relation[attribute]
64 return None66 return None
@@ -228,6 +230,39 @@
228 }230 }
229}231}
230232
233IDENTITY_RELATION_NO_CERT = {
234 'identity-service:0': {
235 'keystone/0': {
236 'private-address': 'keystone1',
237 },
238 }
239}
240
241IDENTITY_RELATION_SINGLE_CERT = {
242 'identity-service:0': {
243 'keystone/0': {
244 'private-address': 'keystone1',
245 'ssl_cert_cinderhost1': 'certa',
246 'ssl_key_cinderhost1': 'keya',
247 },
248 }
249}
250
251IDENTITY_RELATION_MULTIPLE_CERT = {
252 'identity-service:0': {
253 'keystone/0': {
254 'private-address': 'keystone1',
255 'ssl_cert_cinderhost1-int-network': 'certa',
256 'ssl_key_cinderhost1-int-network': 'keya',
257 'ssl_cert_cinderhost1-pub-network': 'certa',
258 'ssl_key_cinderhost1-pub-network': 'keya',
259 'ssl_cert_cinderhost1-adm-network': 'certa',
260 'ssl_key_cinderhost1-adm-network': 'keya',
261 },
262 }
263}
264
265
231SUB_CONFIG = """266SUB_CONFIG = """
232nova:267nova:
233 /etc/nova/nova.conf:268 /etc/nova/nova.conf:
@@ -294,12 +329,27 @@
294 },329 },
295}330}
296331
332NONET_CONFIG = {
333 'vip': 'cinderhost1vip',
334 'os-internal-network': None,
335 'os-admin-network': None,
336 'os-public-network': None
337}
338
339FULLNET_CONFIG = {
340 'vip': '10.5.1.1 10.5.2.1 10.5.3.1',
341 'os-internal-network': "10.5.1.0/24",
342 'os-admin-network': "10.5.2.0/24",
343 'os-public-network': "10.5.3.0/24"
344}
345
297# Imported in contexts.py and needs patching in setUp()346# Imported in contexts.py and needs patching in setUp()
298TO_PATCH = [347TO_PATCH = [
299 'b64decode',348 'b64decode',
300 'check_call',349 'check_call',
301 'get_cert',350 'get_cert',
302 'get_ca_cert',351 'get_ca_cert',
352 'install_ca_cert',
303 'log',353 'log',
304 'config',354 'config',
305 'relation_get',355 'relation_get',
@@ -315,8 +365,11 @@
315 'time',365 'time',
316 'https',366 'https',
317 'get_address_in_network',367 'get_address_in_network',
368 'is_address_in_network',
318 'local_unit',369 'local_unit',
319 'get_ipv6_addr'370 'get_ipv6_addr',
371 'mkdir',
372 'write_file'
320]373]
321374
322375
@@ -937,41 +990,100 @@
937 self.https.return_value = False990 self.https.return_value = False
938 self.assertEquals({}, apache())991 self.assertEquals({}, apache())
939992
940 def _test_https_context(self, apache, is_clustered, peer_units):993 def _test_https_context(self, apache, is_clustered, peer_units,
994 network_config=NONET_CONFIG, multinet=False):
941 self.https.return_value = True995 self.https.return_value = True
996 vips = network_config['vip'].split()
997 if multinet:
998 self.get_address_in_network.side_effect = ['10.5.1.100',
999 '10.5.2.100',
1000 '10.5.3.100']
1001 else:
1002 self.get_address_in_network.return_value = 'cinderhost1'
1003
1004 config = {}
1005 config.update(network_config)
1006 self.config.side_effect = lambda key: config[key]
1007
1008 self.unit_get.return_value = 'cinderhost1'
1009 self.is_clustered.return_value = is_clustered
1010
1011 apache = context.ApacheSSLContext()
1012 apache.configure_cert = MagicMock()
1013 apache.enable_modules = MagicMock()
1014 apache.configure_ca = MagicMock()
1015 apache.canonical_names = MagicMock()
9421016
943 if is_clustered:1017 if is_clustered:
1018 apache.canonical_names.return_value = \
1019 network_config['vip'].split()
944 self.determine_api_port.return_value = 87561020 self.determine_api_port.return_value = 8756
945 self.determine_apache_port.return_value = 87661021 self.determine_apache_port.return_value = 8766
1022 if len(vips) > 1:
1023 self.is_address_in_network.side_effect = [
1024 True, False, True, False, False, True
1025 ]
1026 else:
1027 self.is_address_in_network.return_value = True
946 else:1028 else:
1029 apache.canonical_names.return_value = ['cinderhost1']
947 self.determine_api_port.return_value = 87661030 self.determine_api_port.return_value = 8766
948 self.determine_apache_port.return_value = 87761031 self.determine_apache_port.return_value = 8776
9491032
950 config = {'vip': 'cinderhost1vip'}
951 self.config.side_effect = lambda key: config[key]
952 self.unit_get.return_value = 'cinderhost1'
953 self.is_clustered.return_value = is_clustered
954 apache = context.ApacheSSLContext()
955 apache.configure_cert = MagicMock
956 apache.enable_modules = MagicMock
957 apache.external_ports = '8776'1033 apache.external_ports = '8776'
958 apache.service_namespace = 'cinder'1034 apache.service_namespace = 'cinder'
9591035
960 if is_clustered:1036 if is_clustered:
961 ex = {1037 if len(vips) > 1:
962 'private_address': 'cinderhost1vip',1038 ex = {
963 'namespace': 'cinder',1039 'namespace': 'cinder',
964 'endpoints': [(8766, 8756)],1040 'endpoints': [('10.5.1.100', '10.5.1.1',
965 }1041 8766, 8756),
1042 ('10.5.2.100', '10.5.2.1',
1043 8766, 8756),
1044 ('10.5.3.100', '10.5.3.1',
1045 8766, 8756)],
1046 'ext_ports': [8766]
1047 }
1048 else:
1049 ex = {
1050 'namespace': 'cinder',
1051 'endpoints': [('cinderhost1', 'cinderhost1vip',
1052 8766, 8756)],
1053 'ext_ports': [8766]
1054 }
966 else:1055 else:
967 ex = {1056 if multinet:
968 'private_address': 'cinderhost1',1057 ex = {
969 'namespace': 'cinder',1058 'namespace': 'cinder',
970 'endpoints': [(8776, 8766)],1059 'endpoints': [('10.5.3.100', '10.5.3.100',
971 }1060 8776, 8766),
1061 ('10.5.2.100', '10.5.2.100',
1062 8776, 8766),
1063 ('10.5.1.100', '10.5.1.100',
1064 8776, 8766)],
1065 'ext_ports': [8776]
1066 }
1067 else:
1068 ex = {
1069 'namespace': 'cinder',
1070 'endpoints': [('cinderhost1', 'cinderhost1', 8776, 8766)],
1071 'ext_ports': [8776]
1072 }
9721073
973 self.assertEquals(ex, apache())1074 self.assertEquals(ex, apache())
974 self.assertTrue(apache.configure_cert.called)1075 if is_clustered:
1076 if len(vips) > 1:
1077 apache.configure_cert.assert_has_calls([
1078 call('10.5.1.1'),
1079 call('10.5.2.1'),
1080 call('10.5.3.1')
1081 ])
1082 else:
1083 apache.configure_cert.assert_called_with('cinderhost1vip')
1084 else:
1085 apache.configure_cert.assert_called_with('cinderhost1')
1086 self.assertTrue(apache.configure_ca.called)
975 self.assertTrue(apache.enable_modules.called)1087 self.assertTrue(apache.enable_modules.called)
9761088
977 def test_https_context_no_peers_no_cluster(self):1089 def test_https_context_no_peers_no_cluster(self):
@@ -979,6 +1091,16 @@
979 apache = context.ApacheSSLContext()1091 apache = context.ApacheSSLContext()
980 self._test_https_context(apache, is_clustered=False, peer_units=None)1092 self._test_https_context(apache, is_clustered=False, peer_units=None)
9811093
1094 def test_https_context_multinetwork(self):
1095 apache = context.ApacheSSLContext()
1096 self._test_https_context(apache, is_clustered=False, peer_units=None,
1097 network_config=FULLNET_CONFIG, multinet=True)
1098
1099 def test_https_context_multinetwork_cluster(self):
1100 apache = context.ApacheSSLContext()
1101 self._test_https_context(apache, is_clustered=True, peer_units=None,
1102 network_config=FULLNET_CONFIG, multinet=True)
1103
982 def test_https_context_wth_peers_no_cluster(self):1104 def test_https_context_wth_peers_no_cluster(self):
983 '''Test apache2 https on a unclustered unit with peers'''1105 '''Test apache2 https on a unclustered unit with peers'''
984 apache = context.ApacheSSLContext()1106 apache = context.ApacheSSLContext()
@@ -996,31 +1118,58 @@
996 ex_cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']1118 ex_cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']
997 self.check_call.assert_called_with(ex_cmd)1119 self.check_call.assert_called_with(ex_cmd)
9981120
999 @patch('__builtin__.open')1121 def test_https_configure_cert(self):
1000 @patch('os.mkdir')1122 '''Test apache2 properly installs certs and keys to disk'''
1001 @patch('os.path.isdir')1123 self.get_cert.return_value = ('SSL_CERT', 'SSL_KEY')
1002 def test_https_configure_cert(self, isdir, mkdir, _open):1124 self.b64decode.side_effect = ['SSL_CERT', 'SSL_KEY']
1003 '''Test apache2 properly installs certs and keys to disk'''1125 apache = context.ApacheSSLContext()
1004 isdir.return_value = False1126 apache.service_namespace = 'cinder'
1005 self.get_cert.return_value = ('SSL_CERT', 'SSL_KEY')1127 apache.configure_cert('test-cn')
1006 self.get_ca_cert.return_value = 'CA_CERT'1128 # appropriate directories are created.
1129 self.mkdir.assert_called_with(path='/etc/apache2/ssl/cinder')
1130 # appropriate files are written.
1131 files = [call(path='/etc/apache2/ssl/cinder/cert_test-cn',
1132 content='SSL_CERT'),
1133 call(path='/etc/apache2/ssl/cinder/key_test-cn',
1134 content='SSL_KEY')]
1135 self.write_file.assert_has_calls(files)
1136 # appropriate bits are b64decoded.
1137 decode = [call('SSL_CERT'), call('SSL_KEY')]
1138 self.assertEquals(decode, self.b64decode.call_args_list)
1139
1140 def test_https_configure_cert_deprecated(self):
1141 '''Test apache2 properly installs certs and keys to disk'''
1142 self.get_cert.return_value = ('SSL_CERT', 'SSL_KEY')
1143 self.b64decode.side_effect = ['SSL_CERT', 'SSL_KEY']
1007 apache = context.ApacheSSLContext()1144 apache = context.ApacheSSLContext()
1008 apache.service_namespace = 'cinder'1145 apache.service_namespace = 'cinder'
1009 apache.configure_cert()1146 apache.configure_cert()
1010 # appropriate directories are created.1147 # appropriate directories are created.
1011 dirs = [call('/etc/apache2/ssl'), call('/etc/apache2/ssl/cinder')]1148 self.mkdir.assert_called_with(path='/etc/apache2/ssl/cinder')
1012 self.assertEquals(dirs, mkdir.call_args_list)1149 # appropriate files are written.
1013 # appropriate files are opened for writing.1150 files = [call(path='/etc/apache2/ssl/cinder/cert',
1014 _ca = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'1151 content='SSL_CERT'),
1015 files = [call('/etc/apache2/ssl/cinder/cert', 'w'),1152 call(path='/etc/apache2/ssl/cinder/key',
1016 call('/etc/apache2/ssl/cinder/key', 'w'),1153 content='SSL_KEY')]
1017 call(_ca, 'w')]1154 self.write_file.assert_has_calls(files)
1018 for f in files:
1019 self.assertIn(f, _open.call_args_list)
1020 # appropriate bits are b64decoded.1155 # appropriate bits are b64decoded.
1021 decode = [call('SSL_CERT'), call('SSL_KEY'), call('CA_CERT')]1156 decode = [call('SSL_CERT'), call('SSL_KEY')]
1022 self.assertEquals(decode, self.b64decode.call_args_list)1157 self.assertEquals(decode, self.b64decode.call_args_list)
10231158
1159 def test_https_canonical_names(self):
1160 rel = FakeRelation(IDENTITY_RELATION_SINGLE_CERT)
1161 self.relation_ids.side_effect = rel.relation_ids
1162 self.related_units.side_effect = rel.relation_units
1163 self.relation_get.side_effect = rel.get
1164 apache = context.ApacheSSLContext()
1165 self.assertEquals(apache.canonical_names(), ['cinderhost1'])
1166 rel.relation_data = IDENTITY_RELATION_MULTIPLE_CERT
1167 self.assertEquals(apache.canonical_names(), ['cinderhost1-adm-network',
1168 'cinderhost1-int-network',
1169 'cinderhost1-pub-network'])
1170 rel.relation_data = IDENTITY_RELATION_NO_CERT
1171 self.assertEquals(apache.canonical_names(), [])
1172
1024 def test_image_service_context_missing_data(self):1173 def test_image_service_context_missing_data(self):
1025 '''Test image-service with missing relation and missing data'''1174 '''Test image-service with missing relation and missing data'''
1026 image_service = context.ImageServiceContext()1175 image_service = context.ImageServiceContext()

Subscribers

People subscribed via source and target branches