Merge lp:~james-page/charms/trusty/swift-proxy/network-splits-https into lp:~openstack-charmers-archive/charms/trusty/swift-proxy/next

Proposed by James Page
Status: Merged
Merged at revision: 62
Proposed branch: lp:~james-page/charms/trusty/swift-proxy/network-splits-https
Merge into: lp:~openstack-charmers-archive/charms/trusty/swift-proxy/next
Diff against target: 590 lines (+180/-178)
10 files modified
config.yaml (+0/-22)
hooks/charmhelpers/contrib/network/ip.py (+2/-0)
hooks/charmhelpers/contrib/openstack/amulet/deployment.py (+30/-33)
hooks/charmhelpers/contrib/openstack/context.py (+68/-32)
hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg (+15/-11)
hooks/swift_context.py (+1/-25)
hooks/swift_hooks.py (+18/-10)
tests/basic_deployment.py (+1/-2)
tests/charmhelpers/contrib/amulet/deployment.py (+15/-10)
tests/charmhelpers/contrib/openstack/amulet/deployment.py (+30/-33)
To merge this branch: bzr merge lp:~james-page/charms/trusty/swift-proxy/network-splits-https
Reviewer Review Type Date Requested Status
Liam Young (community) Needs Fixing
Review via email: mp+236903@code.launchpad.net

Description of the change

Add support for HTTPS+HA with multiple network endpoints

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

Resync

71. By James Page

Drop use-https and associate configuration options

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

hooks/swift_context.py:10:1: F401 'CA_CERT_PATH' imported but unused
hooks/swift_context.py:31:1: F401 'get_ca_cert' imported but unused
hooks/swift_context.py:31:1: F401 'get_cert' imported but unused
hooks/swift_context.py:36:1: F401 'b64decode' imported but unused
Makefile:5: recipe for target 'lint' failed
make: *** [lint] Error 1

+1 once ^ are fixed

review: Needs Fixing

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 2014-09-25 16:43:34 +0000
3+++ config.yaml 2014-10-02 20:31:34 +0000
4@@ -63,28 +63,6 @@
5 type: string
6 description: |
7 Base64 encoded SSL key to use with certificate specified as ssl_cert.
8- # Locally generated CA Cert info (only use without keystone)
9- # These options are deprecated and will be removed sometime
10- use-https:
11- default: "yes"
12- type: string
13- description: Whether to listen on HTTPS
14- country:
15- default: US
16- type: string
17- description: Country
18- state:
19- default: ST
20- type: string
21- description: State
22- locale:
23- default: City
24- type: string
25- description: Locale
26- common-name:
27- default: CN
28- type: string
29- description: Common Name
30 # General Swift Proxy configuration
31 bind-port:
32 default: 8080
33
34=== modified file 'hooks/charmhelpers/contrib/network/ip.py'
35--- hooks/charmhelpers/contrib/network/ip.py 2014-09-30 12:57:13 +0000
36+++ hooks/charmhelpers/contrib/network/ip.py 2014-10-02 20:31:34 +0000
37@@ -57,6 +57,8 @@
38 else:
39 if fatal:
40 not_found_error_out()
41+ else:
42+ return None
43
44 _validate_cidr(network)
45 network = netaddr.IPNetwork(network)
46
47=== modified file 'hooks/charmhelpers/contrib/openstack/amulet/deployment.py'
48--- hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2014-09-26 12:41:28 +0000
49+++ hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2014-10-02 20:31:34 +0000
50@@ -1,6 +1,3 @@
51-from bzrlib.branch import Branch
52-import os
53-import re
54 from charmhelpers.contrib.amulet.deployment import (
55 AmuletDeployment
56 )
57@@ -13,62 +10,62 @@
58 that is specifically for use by OpenStack charms.
59 """
60
61- def __init__(self, series=None, openstack=None, source=None):
62+ def __init__(self, series=None, openstack=None, source=None, stable=True):
63 """Initialize the deployment environment."""
64 super(OpenStackAmuletDeployment, self).__init__(series)
65 self.openstack = openstack
66 self.source = source
67-
68- def _is_dev_branch(self):
69- """Determine if branch being tested is a dev (i.e. next) branch."""
70- branch = Branch.open(os.getcwd())
71- parent = branch.get_parent()
72- pattern = re.compile("^.*/next/$")
73- if (pattern.match(parent)):
74- return True
75- else:
76- return False
77+ self.stable = stable
78+ # Note(coreycb): this needs to be changed when new next branches come
79+ # out.
80+ self.current_next = "trusty"
81
82 def _determine_branch_locations(self, other_services):
83 """Determine the branch locations for the other services.
84
85- If the branch being tested is a dev branch, then determine the
86- development branch locations for the other services. Otherwise,
87- the default charm store branches will be used."""
88- name = 0
89- if self._is_dev_branch():
90- updated_services = []
91- for svc in other_services:
92- if svc[name] in ['mysql', 'mongodb', 'rabbitmq-server']:
93- location = 'lp:charms/{}'.format(svc[name])
94+ Determine if the local branch being tested is derived from its
95+ stable or next (dev) branch, and based on this, use the corresonding
96+ stable or next branches for the other_services."""
97+ base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
98+
99+ if self.stable:
100+ for svc in other_services:
101+ temp = 'lp:charms/{}'
102+ svc['location'] = temp.format(svc['name'])
103+ else:
104+ for svc in other_services:
105+ if svc['name'] in base_charms:
106+ temp = 'lp:charms/{}'
107+ svc['location'] = temp.format(svc['name'])
108 else:
109- temp = 'lp:~openstack-charmers/charms/trusty/{}/next'
110- location = temp.format(svc[name])
111- updated_services.append(svc + (location,))
112- other_services = updated_services
113+ temp = 'lp:~openstack-charmers/charms/{}/{}/next'
114+ svc['location'] = temp.format(self.current_next,
115+ svc['name'])
116 return other_services
117
118 def _add_services(self, this_service, other_services):
119 """Add services to the deployment and set openstack-origin/source."""
120- name = 0
121 other_services = self._determine_branch_locations(other_services)
122+
123 super(OpenStackAmuletDeployment, self)._add_services(this_service,
124 other_services)
125+
126 services = other_services
127 services.append(this_service)
128- use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph']
129+ use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
130+ 'ceph-osd', 'ceph-radosgw']
131
132 if self.openstack:
133 for svc in services:
134- if svc[name] not in use_source:
135+ if svc['name'] not in use_source:
136 config = {'openstack-origin': self.openstack}
137- self.d.configure(svc[name], config)
138+ self.d.configure(svc['name'], config)
139
140 if self.source:
141 for svc in services:
142- if svc[name] in use_source:
143+ if svc['name'] in use_source:
144 config = {'source': self.source}
145- self.d.configure(svc[name], config)
146+ self.d.configure(svc['name'], config)
147
148 def _configure_services(self, configs):
149 """Configure all of the services."""
150
151=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
152--- hooks/charmhelpers/contrib/openstack/context.py 2014-09-26 14:54:16 +0000
153+++ hooks/charmhelpers/contrib/openstack/context.py 2014-10-02 20:31:34 +0000
154@@ -52,6 +52,7 @@
155 from charmhelpers.contrib.network.ip import (
156 get_address_in_network,
157 get_ipv6_addr,
158+ get_netmask_for_address,
159 format_ipv6_addr,
160 is_address_in_network
161 )
162@@ -408,6 +409,9 @@
163 return ctxt
164
165
166+ADDRESS_TYPES = ['admin', 'internal', 'public']
167+
168+
169 class HAProxyContext(OSContextGenerator):
170 interfaces = ['cluster']
171
172@@ -420,7 +424,6 @@
173 if not relation_ids('cluster'):
174 return {}
175
176- cluster_hosts = {}
177 l_unit = local_unit().replace('/', '-')
178
179 if config('prefer-ipv6'):
180@@ -428,17 +431,49 @@
181 else:
182 addr = unit_get('private-address')
183
184- cluster_hosts[l_unit] = get_address_in_network(config('os-internal-network'),
185- addr)
186-
187- for rid in relation_ids('cluster'):
188- for unit in related_units(rid):
189- _unit = unit.replace('/', '-')
190- addr = relation_get('private-address', rid=rid, unit=unit)
191- cluster_hosts[_unit] = addr
192+ cluster_hosts = {}
193+
194+ # NOTE(jamespage): build out map of configured network endpoints
195+ # and associated backends
196+ for addr_type in ADDRESS_TYPES:
197+ laddr = get_address_in_network(
198+ config('os-{}-network'.format(addr_type)))
199+ if laddr:
200+ cluster_hosts[laddr] = {}
201+ cluster_hosts[laddr]['network'] = "{}/{}".format(
202+ laddr,
203+ get_netmask_for_address(laddr)
204+ )
205+ cluster_hosts[laddr]['backends'] = {}
206+ cluster_hosts[laddr]['backends'][l_unit] = laddr
207+ for rid in relation_ids('cluster'):
208+ for unit in related_units(rid):
209+ _unit = unit.replace('/', '-')
210+ _laddr = relation_get('{}-address'.format(addr_type),
211+ rid=rid, unit=unit)
212+ if _laddr:
213+ cluster_hosts[laddr]['backends'][_unit] = _laddr
214+
215+ # NOTE(jamespage) no split configurations found, just use
216+ # private addresses
217+ if not cluster_hosts:
218+ cluster_hosts[addr] = {}
219+ cluster_hosts[addr]['network'] = "{}/{}".format(
220+ addr,
221+ get_netmask_for_address(addr)
222+ )
223+ cluster_hosts[addr]['backends'] = {}
224+ cluster_hosts[addr]['backends'][l_unit] = addr
225+ for rid in relation_ids('cluster'):
226+ for unit in related_units(rid):
227+ _unit = unit.replace('/', '-')
228+ _laddr = relation_get('private-address',
229+ rid=rid, unit=unit)
230+ if _laddr:
231+ cluster_hosts[addr]['backends'][_unit] = _laddr
232
233 ctxt = {
234- 'units': cluster_hosts,
235+ 'frontends': cluster_hosts,
236 }
237
238 if config('haproxy-server-timeout'):
239@@ -455,12 +490,13 @@
240 ctxt['haproxy_host'] = '0.0.0.0'
241 ctxt['stat_port'] = ':8888'
242
243- if len(cluster_hosts.keys()) > 1:
244- # Enable haproxy when we have enough peers.
245- log('Ensuring haproxy enabled in /etc/default/haproxy.')
246- with open('/etc/default/haproxy', 'w') as out:
247- out.write('ENABLED=1\n')
248- return ctxt
249+ for frontend in cluster_hosts:
250+ if len(cluster_hosts[frontend]['backends']) > 1:
251+ # Enable haproxy when we have enough peers.
252+ log('Ensuring haproxy enabled in /etc/default/haproxy.')
253+ with open('/etc/default/haproxy', 'w') as out:
254+ out.write('ENABLED=1\n')
255+ return ctxt
256 log('HAProxy context is incomplete, this unit has no peers.')
257 return {}
258
259@@ -722,22 +758,22 @@
260
261 class OSConfigFlagContext(OSContextGenerator):
262
263- """
264- Responsible for adding user-defined config-flags in charm config to a
265- template context.
266-
267- NOTE: the value of config-flags may be a comma-separated list of
268- key=value pairs and some Openstack config files support
269- comma-separated lists as values.
270- """
271-
272- def __call__(self):
273- config_flags = config('config-flags')
274- if not config_flags:
275- return {}
276-
277- flags = config_flags_parser(config_flags)
278- return {'user_config_flags': flags}
279+ """
280+ Responsible for adding user-defined config-flags in charm config to a
281+ template context.
282+
283+ NOTE: the value of config-flags may be a comma-separated list of
284+ key=value pairs and some Openstack config files support
285+ comma-separated lists as values.
286+ """
287+
288+ def __call__(self):
289+ config_flags = config('config-flags')
290+ if not config_flags:
291+ return {}
292+
293+ flags = config_flags_parser(config_flags)
294+ return {'user_config_flags': flags}
295
296
297 class SubordinateConfigContext(OSContextGenerator):
298
299=== modified file 'hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg'
300--- hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg 2014-09-26 14:54:16 +0000
301+++ hooks/charmhelpers/contrib/openstack/templates/haproxy.cfg 2014-10-02 20:31:34 +0000
302@@ -34,17 +34,21 @@
303 stats uri /
304 stats auth admin:password
305
306-{% if units -%}
307+{% if frontends -%}
308 {% for service, ports in service_ports.iteritems() -%}
309-listen {{ service }}_ipv4 0.0.0.0:{{ ports[0] }}
310- balance roundrobin
311- {% for unit, address in units.iteritems() -%}
312- server {{ unit }} {{ address }}:{{ ports[1] }} check
313- {% endfor %}
314-listen {{ service }}_ipv6 :::{{ ports[0] }}
315- balance roundrobin
316- {% for unit, address in units.iteritems() -%}
317- server {{ unit }} {{ address }}:{{ ports[1] }} check
318- {% endfor %}
319+frontend tcp-in_{{ service }}
320+ bind *:{{ ports[0] }}
321+ bind :::{{ ports[0] }}
322+ {% for frontend in frontends -%}
323+ acl net_{{ frontend }} dst {{ frontends[frontend]['network'] }}
324+ use_backend {{ service }}_{{ frontend }} if net_{{ frontend }}
325+ {% endfor %}
326+{% for frontend in frontends -%}
327+backend {{ service }}_{{ frontend }}
328+ balance leastconn
329+ {% for unit, address in frontends[frontend]['backends'].iteritems() -%}
330+ server {{ unit }} {{ address }}:{{ ports[1] }} check
331+ {% endfor %}
332+{% endfor -%}
333 {% endfor -%}
334 {% endif -%}
335
336=== added symlink 'hooks/cluster-relation-departed'
337=== target is u'swift_hooks.py'
338=== modified file 'hooks/swift_context.py'
339--- hooks/swift_context.py 2014-09-25 06:20:53 +0000
340+++ hooks/swift_context.py 2014-10-02 20:31:34 +0000
341@@ -85,33 +85,9 @@
342
343 class ApacheSSLContext(SSLContext):
344 interfaces = ['https']
345- external_ports = [determine_apache_port(config('bind-port'))]
346+ external_ports = [config('bind-port')]
347 service_namespace = 'swift'
348
349- def configure_cert(self):
350- if not os.path.isdir('/etc/apache2/ssl'):
351- os.mkdir('/etc/apache2/ssl')
352- ssl_dir = os.path.join('/etc/apache2/ssl/', self.service_namespace)
353- if not os.path.isdir(ssl_dir):
354- os.mkdir(ssl_dir)
355- cert, key = get_cert()
356- # Swift specific - generate a cert by default if not using
357- # a) user supplied cert or b) keystone signed cert
358- if None in [cert, key]:
359- cert, key = generate_cert()
360- with open(os.path.join(ssl_dir, 'cert'), 'w') as cert_out:
361- cert_out.write(b64decode(cert))
362- with open(os.path.join(ssl_dir, 'key'), 'w') as key_out:
363- key_out.write(b64decode(key))
364- ca_cert = get_ca_cert()
365- if ca_cert:
366- with open(CA_CERT_PATH, 'w') as ca_out:
367- ca_out.write(b64decode(ca_cert))
368- subprocess.check_call(['update-ca-certificates'])
369-
370- def __call__(self):
371- return super(ApacheSSLContext, self).__call__()
372-
373
374 class SwiftRingContext(OSContextGenerator):
375
376
377=== modified file 'hooks/swift_hooks.py'
378--- hooks/swift_hooks.py 2014-09-30 07:48:30 +0000
379+++ hooks/swift_hooks.py 2014-10-02 20:31:34 +0000
380@@ -62,6 +62,8 @@
381 is_ipv6
382 )
383
384+from charmhelpers.contrib.openstack.context import ADDRESS_TYPES
385+
386 extra_pkgs = [
387 "haproxy",
388 "python-jinja2"
389@@ -223,22 +225,28 @@
390 do_openstack_upgrade(CONFIGS)
391 for r_id in relation_ids('identity-service'):
392 keystone_joined(relid=r_id)
393+ [cluster_joined(rid) for rid in relation_ids('cluster')]
394
395
396 @hooks.hook('cluster-relation-joined')
397 def cluster_joined(relation_id=None):
398+ for addr_type in ADDRESS_TYPES:
399+ address = get_address_in_network(
400+ config('os-{}-network'.format(addr_type))
401+ )
402+ if address:
403+ relation_set(
404+ relation_id=relation_id,
405+ relation_settings={'{}-address'.format(addr_type): address}
406+ )
407 if config('prefer-ipv6'):
408 private_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
409- else:
410- private_addr = unit_get('private-address')
411-
412- address = get_address_in_network(config('os-internal-network'),
413- private_addr)
414- relation_set(relation_id=relation_id,
415- relation_settings={'private-address': address})
416-
417-
418-@hooks.hook('cluster-relation-changed')
419+ relation_set(relation_id=relation_id,
420+ relation_settings={'private-address': private_addr})
421+
422+
423+@hooks.hook('cluster-relation-changed',
424+ 'cluster-relation-departed')
425 @restart_on_change(restart_map())
426 def cluster_changed():
427 CONFIGS.write_all()
428
429=== modified file 'tests/basic_deployment.py'
430--- tests/basic_deployment.py 2014-07-11 16:57:37 +0000
431+++ tests/basic_deployment.py 2014-10-02 20:31:34 +0000
432@@ -58,8 +58,7 @@
433 'admin-token': 'ubuntutesting'}
434 swift_proxy_config = {'zone-assignment': 'manual',
435 'replicas': '1',
436- 'swift-hash': 'fdfef9d4-8b06-11e2-8ac0-531c923c8fae',
437- 'use-https': 'no'}
438+ 'swift-hash': 'fdfef9d4-8b06-11e2-8ac0-531c923c8fae'}
439 swift_storage_config = {'zone': '1',
440 'block-device': 'vdb',
441 'overwrite': 'true'}
442
443=== modified file 'tests/charmhelpers/contrib/amulet/deployment.py'
444--- tests/charmhelpers/contrib/amulet/deployment.py 2014-09-26 12:41:28 +0000
445+++ tests/charmhelpers/contrib/amulet/deployment.py 2014-10-02 20:31:34 +0000
446@@ -25,25 +25,30 @@
447
448 Add services to the deployment where this_service is the local charm
449 that we're testing and other_services are the other services that
450- are being used in the amulet tests.
451+ are being used in the local amulet tests.
452 """
453- name, units, location = range(3)
454-
455- if this_service[name] != os.path.basename(os.getcwd()):
456- s = this_service[name]
457+ if this_service['name'] != os.path.basename(os.getcwd()):
458+ s = this_service['name']
459 msg = "The charm's root directory name needs to be {}".format(s)
460 amulet.raise_status(amulet.FAIL, msg=msg)
461
462- self.d.add(this_service[name], units=this_service[units])
463+ if 'units' not in this_service:
464+ this_service['units'] = 1
465+
466+ self.d.add(this_service['name'], units=this_service['units'])
467
468 for svc in other_services:
469- if len(svc) > 2:
470- branch_location = svc[location]
471+ if 'location' in svc:
472+ branch_location = svc['location']
473 elif self.series:
474- branch_location = 'cs:{}/{}'.format(self.series, svc[name]),
475+ branch_location = 'cs:{}/{}'.format(self.series, svc['name']),
476 else:
477 branch_location = None
478- self.d.add(svc[name], charm=branch_location, units=svc[units])
479+
480+ if 'units' not in svc:
481+ svc['units'] = 1
482+
483+ self.d.add(svc['name'], charm=branch_location, units=svc['units'])
484
485 def _add_relations(self, relations):
486 """Add all of the relations for the services."""
487
488=== modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py'
489--- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2014-09-26 12:41:28 +0000
490+++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2014-10-02 20:31:34 +0000
491@@ -1,6 +1,3 @@
492-from bzrlib.branch import Branch
493-import os
494-import re
495 from charmhelpers.contrib.amulet.deployment import (
496 AmuletDeployment
497 )
498@@ -13,62 +10,62 @@
499 that is specifically for use by OpenStack charms.
500 """
501
502- def __init__(self, series=None, openstack=None, source=None):
503+ def __init__(self, series=None, openstack=None, source=None, stable=True):
504 """Initialize the deployment environment."""
505 super(OpenStackAmuletDeployment, self).__init__(series)
506 self.openstack = openstack
507 self.source = source
508-
509- def _is_dev_branch(self):
510- """Determine if branch being tested is a dev (i.e. next) branch."""
511- branch = Branch.open(os.getcwd())
512- parent = branch.get_parent()
513- pattern = re.compile("^.*/next/$")
514- if (pattern.match(parent)):
515- return True
516- else:
517- return False
518+ self.stable = stable
519+ # Note(coreycb): this needs to be changed when new next branches come
520+ # out.
521+ self.current_next = "trusty"
522
523 def _determine_branch_locations(self, other_services):
524 """Determine the branch locations for the other services.
525
526- If the branch being tested is a dev branch, then determine the
527- development branch locations for the other services. Otherwise,
528- the default charm store branches will be used."""
529- name = 0
530- if self._is_dev_branch():
531- updated_services = []
532- for svc in other_services:
533- if svc[name] in ['mysql', 'mongodb', 'rabbitmq-server']:
534- location = 'lp:charms/{}'.format(svc[name])
535+ Determine if the local branch being tested is derived from its
536+ stable or next (dev) branch, and based on this, use the corresonding
537+ stable or next branches for the other_services."""
538+ base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
539+
540+ if self.stable:
541+ for svc in other_services:
542+ temp = 'lp:charms/{}'
543+ svc['location'] = temp.format(svc['name'])
544+ else:
545+ for svc in other_services:
546+ if svc['name'] in base_charms:
547+ temp = 'lp:charms/{}'
548+ svc['location'] = temp.format(svc['name'])
549 else:
550- temp = 'lp:~openstack-charmers/charms/trusty/{}/next'
551- location = temp.format(svc[name])
552- updated_services.append(svc + (location,))
553- other_services = updated_services
554+ temp = 'lp:~openstack-charmers/charms/{}/{}/next'
555+ svc['location'] = temp.format(self.current_next,
556+ svc['name'])
557 return other_services
558
559 def _add_services(self, this_service, other_services):
560 """Add services to the deployment and set openstack-origin/source."""
561- name = 0
562 other_services = self._determine_branch_locations(other_services)
563+
564 super(OpenStackAmuletDeployment, self)._add_services(this_service,
565 other_services)
566+
567 services = other_services
568 services.append(this_service)
569- use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph']
570+ use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
571+ 'ceph-osd', 'ceph-radosgw']
572
573 if self.openstack:
574 for svc in services:
575- if svc[name] not in use_source:
576+ if svc['name'] not in use_source:
577 config = {'openstack-origin': self.openstack}
578- self.d.configure(svc[name], config)
579+ self.d.configure(svc['name'], config)
580
581 if self.source:
582 for svc in services:
583- if svc[name] in use_source:
584+ if svc['name'] in use_source:
585 config = {'source': self.source}
586- self.d.configure(svc[name], config)
587+ self.d.configure(svc['name'], config)
588
589 def _configure_services(self, configs):
590 """Configure all of the services."""

Subscribers

People subscribed via source and target branches