Merge lp:~corey.bryant/charms/trusty/quantum-gateway/amulet-updates into lp:~openstack-charmers/charms/trusty/quantum-gateway/next

Proposed by Corey Bryant
Status: Merged
Merged at revision: 69
Proposed branch: lp:~corey.bryant/charms/trusty/quantum-gateway/amulet-updates
Merge into: lp:~openstack-charmers/charms/trusty/quantum-gateway/next
Diff against target: 1141 lines (+490/-186)
14 files modified
Makefile (+2/-1)
hooks/charmhelpers/contrib/hahelpers/apache.py (+10/-3)
hooks/charmhelpers/contrib/hahelpers/cluster.py (+1/-2)
hooks/charmhelpers/contrib/network/ip.py (+101/-14)
hooks/charmhelpers/contrib/openstack/amulet/deployment.py (+30/-33)
hooks/charmhelpers/contrib/openstack/context.py (+201/-71)
hooks/charmhelpers/contrib/openstack/ip.py (+1/-1)
hooks/charmhelpers/contrib/openstack/utils.py (+28/-1)
hooks/charmhelpers/core/sysctl.py (+34/-0)
tests/00-setup (+5/-4)
tests/README (+6/-0)
tests/basic_deployment.py (+26/-13)
tests/charmhelpers/contrib/amulet/deployment.py (+15/-10)
tests/charmhelpers/contrib/openstack/amulet/deployment.py (+30/-33)
To merge this branch: bzr merge lp:~corey.bryant/charms/trusty/quantum-gateway/amulet-updates
Reviewer Review Type Date Requested Status
OpenStack Charmers Pending
Review via email: mp+237491@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile'
--- Makefile 2014-07-29 07:46:01 +0000
+++ Makefile 2014-10-07 21:21:43 +0000
@@ -23,7 +23,8 @@
23 # coreycb note: The -v should only be temporary until Amulet sends23 # coreycb note: The -v should only be temporary until Amulet sends
24 # raise_status() messages to stderr:24 # raise_status() messages to stderr:
25 # https://bugs.launchpad.net/amulet/+bug/132035725 # https://bugs.launchpad.net/amulet/+bug/1320357
26 @juju test -v -p AMULET_HTTP_PROXY26 @juju test -v -p AMULET_HTTP_PROXY --timeout 900 \
27 00-setup 14-basic-precise-icehouse 15-basic-trusty-icehouse
2728
28publish: lint unit_test29publish: lint unit_test
29 bzr push lp:charms/quantum-gateway30 bzr push lp:charms/quantum-gateway
3031
=== modified file 'hooks/charmhelpers/contrib/hahelpers/apache.py'
--- hooks/charmhelpers/contrib/hahelpers/apache.py 2014-03-27 11:20:28 +0000
+++ hooks/charmhelpers/contrib/hahelpers/apache.py 2014-10-07 21:21:43 +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 'hooks/charmhelpers/contrib/hahelpers/cluster.py'
--- hooks/charmhelpers/contrib/hahelpers/cluster.py 2014-08-13 13:12:47 +0000
+++ hooks/charmhelpers/contrib/hahelpers/cluster.py 2014-10-07 21:21:43 +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 'hooks/charmhelpers/contrib/network/ip.py'
--- hooks/charmhelpers/contrib/network/ip.py 2014-09-19 10:56:29 +0000
+++ hooks/charmhelpers/contrib/network/ip.py 2014-10-07 21:21:43 +0000
@@ -1,11 +1,16 @@
1import glob1import glob
2import re
3import subprocess
2import sys4import sys
35
4from functools import partial6from functools import partial
57
8from charmhelpers.core.hookenv import unit_get
6from charmhelpers.fetch import apt_install9from charmhelpers.fetch import apt_install
7from charmhelpers.core.hookenv import (10from charmhelpers.core.hookenv import (
8 ERROR, log,11 WARNING,
12 ERROR,
13 log
9)14)
1015
11try:16try:
@@ -52,6 +57,8 @@
52 else:57 else:
53 if fatal:58 if fatal:
54 not_found_error_out()59 not_found_error_out()
60 else:
61 return None
5562
56 _validate_cidr(network)63 _validate_cidr(network)
57 network = netaddr.IPNetwork(network)64 network = netaddr.IPNetwork(network)
@@ -164,13 +171,14 @@
164 if is_ipv6(address):171 if is_ipv6(address):
165 address = "[%s]" % address172 address = "[%s]" % address
166 else:173 else:
167 log("Not an valid ipv6 address: %s" % address,174 log("Not a valid ipv6 address: %s" % address, level=WARNING)
168 level=ERROR)
169 address = None175 address = None
176
170 return address177 return address
171178
172179
173def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False, fatal=True, exc_list=None):180def get_iface_addr(iface='eth0', inet_type='AF_INET', inc_aliases=False,
181 fatal=True, exc_list=None):
174 """182 """
175 Return the assigned IP address for a given interface, if any, or [].183 Return the assigned IP address for a given interface, if any, or [].
176 """184 """
@@ -210,26 +218,105 @@
210 if 'addr' in entry and entry['addr'] not in exc_list:218 if 'addr' in entry and entry['addr'] not in exc_list:
211 addresses.append(entry['addr'])219 addresses.append(entry['addr'])
212 if fatal and not addresses:220 if fatal and not addresses:
213 raise Exception("Interface '%s' doesn't have any %s addresses." % (iface, inet_type))221 raise Exception("Interface '%s' doesn't have any %s addresses." %
222 (iface, inet_type))
214 return addresses223 return addresses
215224
216get_ipv4_addr = partial(get_iface_addr, inet_type='AF_INET')225get_ipv4_addr = partial(get_iface_addr, inet_type='AF_INET')
217226
218227
219def get_ipv6_addr(iface='eth0', inc_aliases=False, fatal=True, exc_list=None):228def get_iface_from_addr(addr):
229 """Work out on which interface the provided address is configured."""
230 for iface in netifaces.interfaces():
231 addresses = netifaces.ifaddresses(iface)
232 for inet_type in addresses:
233 for _addr in addresses[inet_type]:
234 _addr = _addr['addr']
235 # link local
236 ll_key = re.compile("(.+)%.*")
237 raw = re.match(ll_key, _addr)
238 if raw:
239 _addr = raw.group(1)
240 if _addr == addr:
241 log("Address '%s' is configured on iface '%s'" %
242 (addr, iface))
243 return iface
244
245 msg = "Unable to infer net iface on which '%s' is configured" % (addr)
246 raise Exception(msg)
247
248
249def sniff_iface(f):
250 """If no iface provided, inject net iface inferred from unit private
251 address.
220 """252 """
221 Return the assigned IPv6 address for a given interface, if any, or [].253 def iface_sniffer(*args, **kwargs):
254 if not kwargs.get('iface', None):
255 kwargs['iface'] = get_iface_from_addr(unit_get('private-address'))
256
257 return f(*args, **kwargs)
258
259 return iface_sniffer
260
261
262@sniff_iface
263def get_ipv6_addr(iface=None, inc_aliases=False, fatal=True, exc_list=None,
264 dynamic_only=True):
265 """Get assigned IPv6 address for a given interface.
266
267 Returns list of addresses found. If no address found, returns empty list.
268
269 If iface is None, we infer the current primary interface by doing a reverse
270 lookup on the unit private-address.
271
272 We currently only support scope global IPv6 addresses i.e. non-temporary
273 addresses. If no global IPv6 address is found, return the first one found
274 in the ipv6 address list.
222 """275 """
223 addresses = get_iface_addr(iface=iface, inet_type='AF_INET6',276 addresses = get_iface_addr(iface=iface, inet_type='AF_INET6',
224 inc_aliases=inc_aliases, fatal=fatal,277 inc_aliases=inc_aliases, fatal=fatal,
225 exc_list=exc_list)278 exc_list=exc_list)
226 remotly_addressable = []279
227 for address in addresses:280 if addresses:
228 if not address.startswith('fe80'):281 global_addrs = []
229 remotly_addressable.append(address)282 for addr in addresses:
230 if fatal and not remotly_addressable:283 key_scope_link_local = re.compile("^fe80::..(.+)%(.+)")
231 raise Exception("Interface '%s' doesn't have global ipv6 address." % iface)284 m = re.match(key_scope_link_local, addr)
232 return remotly_addressable285 if m:
286 eui_64_mac = m.group(1)
287 iface = m.group(2)
288 else:
289 global_addrs.append(addr)
290
291 if global_addrs:
292 # Make sure any found global addresses are not temporary
293 cmd = ['ip', 'addr', 'show', iface]
294 out = subprocess.check_output(cmd)
295 if dynamic_only:
296 key = re.compile("inet6 (.+)/[0-9]+ scope global dynamic.*")
297 else:
298 key = re.compile("inet6 (.+)/[0-9]+ scope global.*")
299
300 addrs = []
301 for line in out.split('\n'):
302 line = line.strip()
303 m = re.match(key, line)
304 if m and 'temporary' not in line:
305 # Return the first valid address we find
306 for addr in global_addrs:
307 if m.group(1) == addr:
308 if not dynamic_only or \
309 m.group(1).endswith(eui_64_mac):
310 addrs.append(addr)
311
312 if addrs:
313 return addrs
314
315 if fatal:
316 raise Exception("Interface '%s' doesn't have a scope global "
317 "non-temporary ipv6 address." % iface)
318
319 return []
233320
234321
235def get_bridges(vnic_dir='/sys/devices/virtual/net'):322def get_bridges(vnic_dir='/sys/devices/virtual/net'):
236323
=== modified file 'hooks/charmhelpers/contrib/openstack/amulet/deployment.py'
--- hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2014-09-25 15:37:05 +0000
+++ hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2014-10-07 21:21:43 +0000
@@ -1,6 +1,3 @@
1from bzrlib.branch import Branch
2import os
3import re
4from charmhelpers.contrib.amulet.deployment import (1from charmhelpers.contrib.amulet.deployment import (
5 AmuletDeployment2 AmuletDeployment
6)3)
@@ -13,62 +10,62 @@
13 that is specifically for use by OpenStack charms.10 that is specifically for use by OpenStack charms.
14 """11 """
1512
16 def __init__(self, series=None, openstack=None, source=None):13 def __init__(self, series=None, openstack=None, source=None, stable=True):
17 """Initialize the deployment environment."""14 """Initialize the deployment environment."""
18 super(OpenStackAmuletDeployment, self).__init__(series)15 super(OpenStackAmuletDeployment, self).__init__(series)
19 self.openstack = openstack16 self.openstack = openstack
20 self.source = source17 self.source = source
2118 self.stable = stable
22 def _is_dev_branch(self):19 # Note(coreycb): this needs to be changed when new next branches come
23 """Determine if branch being tested is a dev (i.e. next) branch."""20 # out.
24 branch = Branch.open(os.getcwd())21 self.current_next = "trusty"
25 parent = branch.get_parent()
26 pattern = re.compile("^.*/next/$")
27 if (pattern.match(parent)):
28 return True
29 else:
30 return False
3122
32 def _determine_branch_locations(self, other_services):23 def _determine_branch_locations(self, other_services):
33 """Determine the branch locations for the other services.24 """Determine the branch locations for the other services.
3425
35 If the branch being tested is a dev branch, then determine the26 Determine if the local branch being tested is derived from its
36 development branch locations for the other services. Otherwise,27 stable or next (dev) branch, and based on this, use the corresonding
37 the default charm store branches will be used."""28 stable or next branches for the other_services."""
38 name = 029 base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
39 if self._is_dev_branch():30
40 updated_services = []31 if self.stable:
41 for svc in other_services:32 for svc in other_services:
42 if svc[name] in ['mysql', 'mongodb', 'rabbitmq-server']:33 temp = 'lp:charms/{}'
43 location = 'lp:charms/{}'.format(svc[name])34 svc['location'] = temp.format(svc['name'])
35 else:
36 for svc in other_services:
37 if svc['name'] in base_charms:
38 temp = 'lp:charms/{}'
39 svc['location'] = temp.format(svc['name'])
44 else:40 else:
45 temp = 'lp:~openstack-charmers/charms/trusty/{}/next'41 temp = 'lp:~openstack-charmers/charms/{}/{}/next'
46 location = temp.format(svc[name])42 svc['location'] = temp.format(self.current_next,
47 updated_services.append(svc + (location,))43 svc['name'])
48 other_services = updated_services
49 return other_services44 return other_services
5045
51 def _add_services(self, this_service, other_services):46 def _add_services(self, this_service, other_services):
52 """Add services to the deployment and set openstack-origin/source."""47 """Add services to the deployment and set openstack-origin/source."""
53 name = 0
54 other_services = self._determine_branch_locations(other_services)48 other_services = self._determine_branch_locations(other_services)
49
55 super(OpenStackAmuletDeployment, self)._add_services(this_service,50 super(OpenStackAmuletDeployment, self)._add_services(this_service,
56 other_services)51 other_services)
52
57 services = other_services53 services = other_services
58 services.append(this_service)54 services.append(this_service)
59 use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph']55 use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
56 'ceph-osd', 'ceph-radosgw']
6057
61 if self.openstack:58 if self.openstack:
62 for svc in services:59 for svc in services:
63 if svc[name] not in use_source:60 if svc['name'] not in use_source:
64 config = {'openstack-origin': self.openstack}61 config = {'openstack-origin': self.openstack}
65 self.d.configure(svc[name], config)62 self.d.configure(svc['name'], config)
6663
67 if self.source:64 if self.source:
68 for svc in services:65 for svc in services:
69 if svc[name] in use_source:66 if svc['name'] in use_source:
70 config = {'source': self.source}67 config = {'source': self.source}
71 self.d.configure(svc[name], config)68 self.d.configure(svc['name'], config)
7269
73 def _configure_services(self, configs):70 def _configure_services(self, configs):
74 """Configure all of the services."""71 """Configure all of the services."""
7572
=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
--- hooks/charmhelpers/contrib/openstack/context.py 2014-09-25 15:37:05 +0000
+++ hooks/charmhelpers/contrib/openstack/context.py 2014-10-07 21:21:43 +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,8 +52,13 @@
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 get_netmask_for_address,
56 format_ipv6_addr,
57 is_address_in_network
50)58)
5159
60from charmhelpers.contrib.openstack.utils import get_host_ip
61
52CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'62CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
5363
5464
@@ -168,8 +178,10 @@
168 for rid in relation_ids('shared-db'):178 for rid in relation_ids('shared-db'):
169 for unit in related_units(rid):179 for unit in related_units(rid):
170 rdata = relation_get(rid=rid, unit=unit)180 rdata = relation_get(rid=rid, unit=unit)
181 host = rdata.get('db_host')
182 host = format_ipv6_addr(host) or host
171 ctxt = {183 ctxt = {
172 'database_host': rdata.get('db_host'),184 'database_host': host,
173 'database': self.database,185 'database': self.database,
174 'database_user': self.user,186 'database_user': self.user,
175 'database_password': rdata.get(password_setting),187 'database_password': rdata.get(password_setting),
@@ -245,10 +257,15 @@
245 for rid in relation_ids('identity-service'):257 for rid in relation_ids('identity-service'):
246 for unit in related_units(rid):258 for unit in related_units(rid):
247 rdata = relation_get(rid=rid, unit=unit)259 rdata = relation_get(rid=rid, unit=unit)
260 serv_host = rdata.get('service_host')
261 serv_host = format_ipv6_addr(serv_host) or serv_host
262 auth_host = rdata.get('auth_host')
263 auth_host = format_ipv6_addr(auth_host) or auth_host
264
248 ctxt = {265 ctxt = {
249 'service_port': rdata.get('service_port'),266 'service_port': rdata.get('service_port'),
250 'service_host': rdata.get('service_host'),267 'service_host': serv_host,
251 'auth_host': rdata.get('auth_host'),268 'auth_host': auth_host,
252 'auth_port': rdata.get('auth_port'),269 'auth_port': rdata.get('auth_port'),
253 'admin_tenant_name': rdata.get('service_tenant'),270 'admin_tenant_name': rdata.get('service_tenant'),
254 'admin_user': rdata.get('service_username'),271 'admin_user': rdata.get('service_username'),
@@ -297,11 +314,13 @@
297 for unit in related_units(rid):314 for unit in related_units(rid):
298 if relation_get('clustered', rid=rid, unit=unit):315 if relation_get('clustered', rid=rid, unit=unit):
299 ctxt['clustered'] = True316 ctxt['clustered'] = True
300 ctxt['rabbitmq_host'] = relation_get('vip', rid=rid,317 vip = relation_get('vip', rid=rid, unit=unit)
301 unit=unit)318 vip = format_ipv6_addr(vip) or vip
319 ctxt['rabbitmq_host'] = vip
302 else:320 else:
303 ctxt['rabbitmq_host'] = relation_get('private-address',321 host = relation_get('private-address', rid=rid, unit=unit)
304 rid=rid, unit=unit)322 host = format_ipv6_addr(host) or host
323 ctxt['rabbitmq_host'] = host
305 ctxt.update({324 ctxt.update({
306 'rabbitmq_user': username,325 'rabbitmq_user': username,
307 'rabbitmq_password': relation_get('password', rid=rid,326 'rabbitmq_password': relation_get('password', rid=rid,
@@ -340,8 +359,9 @@
340 and len(related_units(rid)) > 1:359 and len(related_units(rid)) > 1:
341 rabbitmq_hosts = []360 rabbitmq_hosts = []
342 for unit in related_units(rid):361 for unit in related_units(rid):
343 rabbitmq_hosts.append(relation_get('private-address',362 host = relation_get('private-address', rid=rid, unit=unit)
344 rid=rid, unit=unit))363 host = format_ipv6_addr(host) or host
364 rabbitmq_hosts.append(host)
345 ctxt['rabbitmq_hosts'] = ','.join(rabbitmq_hosts)365 ctxt['rabbitmq_hosts'] = ','.join(rabbitmq_hosts)
346 if not context_complete(ctxt):366 if not context_complete(ctxt):
347 return {}367 return {}
@@ -370,6 +390,7 @@
370 ceph_addr = \390 ceph_addr = \
371 relation_get('ceph-public-address', rid=rid, unit=unit) or \391 relation_get('ceph-public-address', rid=rid, unit=unit) or \
372 relation_get('private-address', rid=rid, unit=unit)392 relation_get('private-address', rid=rid, unit=unit)
393 ceph_addr = format_ipv6_addr(ceph_addr) or ceph_addr
373 mon_hosts.append(ceph_addr)394 mon_hosts.append(ceph_addr)
374395
375 ctxt = {396 ctxt = {
@@ -390,6 +411,9 @@
390 return ctxt411 return ctxt
391412
392413
414ADDRESS_TYPES = ['admin', 'internal', 'public']
415
416
393class HAProxyContext(OSContextGenerator):417class HAProxyContext(OSContextGenerator):
394 interfaces = ['cluster']418 interfaces = ['cluster']
395419
@@ -402,29 +426,62 @@
402 if not relation_ids('cluster'):426 if not relation_ids('cluster'):
403 return {}427 return {}
404428
429 l_unit = local_unit().replace('/', '-')
430
431 if config('prefer-ipv6'):
432 addr = get_ipv6_addr(exc_list=[config('vip')])[0]
433 else:
434 addr = get_host_ip(unit_get('private-address'))
435
405 cluster_hosts = {}436 cluster_hosts = {}
406 l_unit = local_unit().replace('/', '-')437
407 if config('prefer-ipv6'):438 # NOTE(jamespage): build out map of configured network endpoints
408 addr = get_ipv6_addr()439 # and associated backends
409 else:440 for addr_type in ADDRESS_TYPES:
410 addr = unit_get('private-address')441 laddr = get_address_in_network(
411 cluster_hosts[l_unit] = get_address_in_network(config('os-internal-network'),442 config('os-{}-network'.format(addr_type)))
412 addr)443 if laddr:
413444 cluster_hosts[laddr] = {}
414 for rid in relation_ids('cluster'):445 cluster_hosts[laddr]['network'] = "{}/{}".format(
415 for unit in related_units(rid):446 laddr,
416 _unit = unit.replace('/', '-')447 get_netmask_for_address(laddr)
417 addr = relation_get('private-address', rid=rid, unit=unit)448 )
418 cluster_hosts[_unit] = addr449 cluster_hosts[laddr]['backends'] = {}
450 cluster_hosts[laddr]['backends'][l_unit] = laddr
451 for rid in relation_ids('cluster'):
452 for unit in related_units(rid):
453 _unit = unit.replace('/', '-')
454 _laddr = relation_get('{}-address'.format(addr_type),
455 rid=rid, unit=unit)
456 if _laddr:
457 cluster_hosts[laddr]['backends'][_unit] = _laddr
458
459 # NOTE(jamespage) no split configurations found, just use
460 # private addresses
461 if not cluster_hosts:
462 cluster_hosts[addr] = {}
463 cluster_hosts[addr]['network'] = "{}/{}".format(
464 addr,
465 get_netmask_for_address(addr)
466 )
467 cluster_hosts[addr]['backends'] = {}
468 cluster_hosts[addr]['backends'][l_unit] = addr
469 for rid in relation_ids('cluster'):
470 for unit in related_units(rid):
471 _unit = unit.replace('/', '-')
472 _laddr = relation_get('private-address',
473 rid=rid, unit=unit)
474 if _laddr:
475 cluster_hosts[addr]['backends'][_unit] = _laddr
419476
420 ctxt = {477 ctxt = {
421 'units': cluster_hosts,478 'frontends': cluster_hosts,
422 }479 }
423480
424 if config('haproxy-server-timeout'):481 if config('haproxy-server-timeout'):
425 ctxt['haproxy-server-timeout'] = config('haproxy-server-timeout')482 ctxt['haproxy_server_timeout'] = config('haproxy-server-timeout')
426 if config('haproxy-client-timeout'):483 if config('haproxy-client-timeout'):
427 ctxt['haproxy-client-timeout'] = config('haproxy-client-timeout')484 ctxt['haproxy_client_timeout'] = config('haproxy-client-timeout')
428485
429 if config('prefer-ipv6'):486 if config('prefer-ipv6'):
430 ctxt['local_host'] = 'ip6-localhost'487 ctxt['local_host'] = 'ip6-localhost'
@@ -435,12 +492,13 @@
435 ctxt['haproxy_host'] = '0.0.0.0'492 ctxt['haproxy_host'] = '0.0.0.0'
436 ctxt['stat_port'] = ':8888'493 ctxt['stat_port'] = ':8888'
437494
438 if len(cluster_hosts.keys()) > 1:495 for frontend in cluster_hosts:
439 # Enable haproxy when we have enough peers.496 if len(cluster_hosts[frontend]['backends']) > 1:
440 log('Ensuring haproxy enabled in /etc/default/haproxy.')497 # Enable haproxy when we have enough peers.
441 with open('/etc/default/haproxy', 'w') as out:498 log('Ensuring haproxy enabled in /etc/default/haproxy.')
442 out.write('ENABLED=1\n')499 with open('/etc/default/haproxy', 'w') as out:
443 return ctxt500 out.write('ENABLED=1\n')
501 return ctxt
444 log('HAProxy context is incomplete, this unit has no peers.')502 log('HAProxy context is incomplete, this unit has no peers.')
445 return {}503 return {}
446504
@@ -495,22 +553,36 @@
495 cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']553 cmd = ['a2enmod', 'ssl', 'proxy', 'proxy_http']
496 check_call(cmd)554 check_call(cmd)
497555
498 def configure_cert(self):556 def configure_cert(self, cn=None):
499 if not os.path.isdir('/etc/apache2/ssl'):
500 os.mkdir('/etc/apache2/ssl')
501 ssl_dir = os.path.join('/etc/apache2/ssl/', self.service_namespace)557 ssl_dir = os.path.join('/etc/apache2/ssl/', self.service_namespace)
502 if not os.path.isdir(ssl_dir):558 mkdir(path=ssl_dir)
503 os.mkdir(ssl_dir)559 cert, key = get_cert(cn)
504 cert, key = get_cert()560 if cn:
505 with open(os.path.join(ssl_dir, 'cert'), 'w') as cert_out:561 cert_filename = 'cert_{}'.format(cn)
506 cert_out.write(b64decode(cert))562 key_filename = 'key_{}'.format(cn)
507 with open(os.path.join(ssl_dir, 'key'), 'w') as key_out:563 else:
508 key_out.write(b64decode(key))564 cert_filename = 'cert'
565 key_filename = 'key'
566 write_file(path=os.path.join(ssl_dir, cert_filename),
567 content=b64decode(cert))
568 write_file(path=os.path.join(ssl_dir, key_filename),
569 content=b64decode(key))
570
571 def configure_ca(self):
509 ca_cert = get_ca_cert()572 ca_cert = get_ca_cert()
510 if ca_cert:573 if ca_cert:
511 with open(CA_CERT_PATH, 'w') as ca_out:574 install_ca_cert(b64decode(ca_cert))
512 ca_out.write(b64decode(ca_cert))575
513 check_call(['update-ca-certificates'])576 def canonical_names(self):
577 '''Figure out which canonical names clients will access this service'''
578 cns = []
579 for r_id in relation_ids('identity-service'):
580 for unit in related_units(r_id):
581 rdata = relation_get(rid=r_id, unit=unit)
582 for k in rdata:
583 if k.startswith('ssl_key_'):
584 cns.append(k.lstrip('ssl_key_'))
585 return list(set(cns))
514586
515 def __call__(self):587 def __call__(self):
516 if isinstance(self.external_ports, basestring):588 if isinstance(self.external_ports, basestring):
@@ -518,21 +590,47 @@
518 if (not self.external_ports or not https()):590 if (not self.external_ports or not https()):
519 return {}591 return {}
520592
521 self.configure_cert()593 self.configure_ca()
522 self.enable_modules()594 self.enable_modules()
523595
524 ctxt = {596 ctxt = {
525 'namespace': self.service_namespace,597 'namespace': self.service_namespace,
526 'private_address': unit_get('private-address'),598 'endpoints': [],
527 'endpoints': []599 'ext_ports': []
528 }600 }
529 if is_clustered():601
530 ctxt['private_address'] = config('vip')602 for cn in self.canonical_names():
531 for api_port in self.external_ports:603 self.configure_cert(cn)
532 ext_port = determine_apache_port(api_port)604
533 int_port = determine_api_port(api_port)605 addresses = []
534 portmap = (int(ext_port), int(int_port))606 vips = []
535 ctxt['endpoints'].append(portmap)607 if config('vip'):
608 vips = config('vip').split()
609
610 for network_type in ['os-internal-network',
611 'os-admin-network',
612 'os-public-network']:
613 address = get_address_in_network(config(network_type),
614 unit_get('private-address'))
615 if len(vips) > 0 and is_clustered():
616 for vip in vips:
617 if is_address_in_network(config(network_type),
618 vip):
619 addresses.append((address, vip))
620 break
621 elif is_clustered():
622 addresses.append((address, config('vip')))
623 else:
624 addresses.append((address, address))
625
626 for address, endpoint in set(addresses):
627 for api_port in self.external_ports:
628 ext_port = determine_apache_port(api_port)
629 int_port = determine_api_port(api_port)
630 portmap = (address, endpoint, int(ext_port), int(int_port))
631 ctxt['endpoints'].append(portmap)
632 ctxt['ext_ports'].append(int(ext_port))
633 ctxt['ext_ports'] = list(set(ctxt['ext_ports']))
536 return ctxt634 return ctxt
537635
538636
@@ -662,22 +760,22 @@
662760
663class OSConfigFlagContext(OSContextGenerator):761class OSConfigFlagContext(OSContextGenerator):
664762
665 """763 """
666 Responsible for adding user-defined config-flags in charm config to a764 Responsible for adding user-defined config-flags in charm config to a
667 template context.765 template context.
668766
669 NOTE: the value of config-flags may be a comma-separated list of767 NOTE: the value of config-flags may be a comma-separated list of
670 key=value pairs and some Openstack config files support768 key=value pairs and some Openstack config files support
671 comma-separated lists as values.769 comma-separated lists as values.
672 """770 """
673771
674 def __call__(self):772 def __call__(self):
675 config_flags = config('config-flags')773 config_flags = config('config-flags')
676 if not config_flags:774 if not config_flags:
677 return {}775 return {}
678776
679 flags = config_flags_parser(config_flags)777 flags = config_flags_parser(config_flags)
680 return {'user_config_flags': flags}778 return {'user_config_flags': flags}
681779
682780
683class SubordinateConfigContext(OSContextGenerator):781class SubordinateConfigContext(OSContextGenerator):
@@ -792,3 +890,35 @@
792 'use_syslog': config('use-syslog')890 'use_syslog': config('use-syslog')
793 }891 }
794 return ctxt892 return ctxt
893
894
895class BindHostContext(OSContextGenerator):
896
897 def __call__(self):
898 if config('prefer-ipv6'):
899 return {
900 'bind_host': '::'
901 }
902 else:
903 return {
904 'bind_host': '0.0.0.0'
905 }
906
907
908class WorkerConfigContext(OSContextGenerator):
909
910 @property
911 def num_cpus(self):
912 try:
913 from psutil import NUM_CPUS
914 except ImportError:
915 apt_install('python-psutil', fatal=True)
916 from psutil import NUM_CPUS
917 return NUM_CPUS
918
919 def __call__(self):
920 multiplier = config('worker-multiplier') or 1
921 ctxt = {
922 "workers": self.num_cpus * multiplier
923 }
924 return ctxt
795925
=== modified file 'hooks/charmhelpers/contrib/openstack/ip.py'
--- hooks/charmhelpers/contrib/openstack/ip.py 2014-08-13 13:12:47 +0000
+++ hooks/charmhelpers/contrib/openstack/ip.py 2014-10-07 21:21:43 +0000
@@ -66,7 +66,7 @@
66 resolved_address = vip66 resolved_address = vip
67 else:67 else:
68 if config('prefer-ipv6'):68 if config('prefer-ipv6'):
69 fallback_addr = get_ipv6_addr()69 fallback_addr = get_ipv6_addr(exc_list=[config('vip')])[0]
70 else:70 else:
71 fallback_addr = unit_get(_address_map[endpoint_type]['fallback'])71 fallback_addr = unit_get(_address_map[endpoint_type]['fallback'])
72 resolved_address = get_address_in_network(72 resolved_address = get_address_in_network(
7373
=== modified file 'hooks/charmhelpers/contrib/openstack/utils.py'
--- hooks/charmhelpers/contrib/openstack/utils.py 2014-09-17 10:33:02 +0000
+++ hooks/charmhelpers/contrib/openstack/utils.py 2014-10-07 21:21:43 +0000
@@ -4,6 +4,7 @@
4from collections import OrderedDict4from collections import OrderedDict
55
6import subprocess6import subprocess
7import json
7import os8import os
8import socket9import socket
9import sys10import sys
@@ -13,7 +14,9 @@
13 log as juju_log,14 log as juju_log,
14 charm_dir,15 charm_dir,
15 ERROR,16 ERROR,
16 INFO17 INFO,
18 relation_ids,
19 relation_set
17)20)
1821
19from charmhelpers.contrib.storage.linux.lvm import (22from charmhelpers.contrib.storage.linux.lvm import (
@@ -22,6 +25,10 @@
22 remove_lvm_physical_volume,25 remove_lvm_physical_volume,
23)26)
2427
28from charmhelpers.contrib.network.ip import (
29 get_ipv6_addr
30)
31
25from charmhelpers.core.host import lsb_release, mounts, umount32from charmhelpers.core.host import lsb_release, mounts, umount
26from charmhelpers.fetch import apt_install, apt_cache33from charmhelpers.fetch import apt_install, apt_cache
27from charmhelpers.contrib.storage.linux.utils import is_block_device, zap_disk34from charmhelpers.contrib.storage.linux.utils import is_block_device, zap_disk
@@ -71,6 +78,8 @@
71 ('1.12.0', 'icehouse'),78 ('1.12.0', 'icehouse'),
72 ('1.11.0', 'icehouse'),79 ('1.11.0', 'icehouse'),
73 ('2.0.0', 'juno'),80 ('2.0.0', 'juno'),
81 ('2.1.0', 'juno'),
82 ('2.2.0', 'juno'),
74])83])
7584
76DEFAULT_LOOPBACK_SIZE = '5G'85DEFAULT_LOOPBACK_SIZE = '5G'
@@ -457,3 +466,21 @@
457 return result466 return result
458 else:467 else:
459 return result.split('.')[0]468 return result.split('.')[0]
469
470
471def sync_db_with_multi_ipv6_addresses(database, database_user,
472 relation_prefix=None):
473 hosts = get_ipv6_addr(dynamic_only=False)
474
475 kwargs = {'database': database,
476 'username': database_user,
477 'hostname': json.dumps(hosts)}
478
479 if relation_prefix:
480 keys = kwargs.keys()
481 for key in keys:
482 kwargs["%s_%s" % (relation_prefix, key)] = kwargs[key]
483 del kwargs[key]
484
485 for rid in relation_ids('shared-db'):
486 relation_set(relation_id=rid, **kwargs)
460487
=== added file 'hooks/charmhelpers/core/sysctl.py'
--- hooks/charmhelpers/core/sysctl.py 1970-01-01 00:00:00 +0000
+++ hooks/charmhelpers/core/sysctl.py 2014-10-07 21:21:43 +0000
@@ -0,0 +1,34 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4__author__ = 'Jorge Niedbalski R. <jorge.niedbalski@canonical.com>'
5
6import yaml
7
8from subprocess import check_call
9
10from charmhelpers.core.hookenv import (
11 log,
12 DEBUG,
13)
14
15
16def create(sysctl_dict, sysctl_file):
17 """Creates a sysctl.conf file from a YAML associative array
18
19 :param sysctl_dict: a dict of sysctl options eg { 'kernel.max_pid': 1337 }
20 :type sysctl_dict: dict
21 :param sysctl_file: path to the sysctl file to be saved
22 :type sysctl_file: str or unicode
23 :returns: None
24 """
25 sysctl_dict = yaml.load(sysctl_dict)
26
27 with open(sysctl_file, "w") as fd:
28 for key, value in sysctl_dict.items():
29 fd.write("{}={}\n".format(key, value))
30
31 log("Updating sysctl_file: %s values: %s" % (sysctl_file, sysctl_dict),
32 level=DEBUG)
33
34 check_call(["sysctl", "-p", sysctl_file])
035
=== modified file 'tests/00-setup'
--- tests/00-setup 2014-07-17 15:16:21 +0000
+++ tests/00-setup 2014-10-07 21:21:43 +0000
@@ -4,7 +4,8 @@
44
5sudo add-apt-repository --yes ppa:juju/stable5sudo add-apt-repository --yes ppa:juju/stable
6sudo apt-get update --yes6sudo apt-get update --yes
7sudo apt-get install --yes python-amulet7sudo apt-get install --yes python-amulet \
8sudo apt-get install --yes python-neutronclient8 python-neutronclient \
9sudo apt-get install --yes python-keystoneclient9 python-keystoneclient \
10sudo apt-get install --yes python-novaclient10 python-novaclient \
11 python-glanceclient
1112
=== modified file 'tests/README'
--- tests/README 2014-07-17 15:16:21 +0000
+++ tests/README 2014-10-07 21:21:43 +0000
@@ -1,6 +1,12 @@
1This directory provides Amulet tests that focus on verification of1This directory provides Amulet tests that focus on verification of
2quantum-gateway deployments.2quantum-gateway deployments.
33
4In order to run tests, you'll need charm-tools installed (in addition to
5juju, of course):
6 sudo add-apt-repository ppa:juju/stable
7 sudo apt-get update
8 sudo apt-get install charm-tools
9
4If you use a web proxy server to access the web, you'll need to set the10If you use a web proxy server to access the web, you'll need to set the
5AMULET_HTTP_PROXY environment variable to the http URL of the proxy server.11AMULET_HTTP_PROXY environment variable to the http URL of the proxy server.
612
713
=== modified file 'tests/basic_deployment.py'
--- tests/basic_deployment.py 2014-09-08 19:02:06 +0000
+++ tests/basic_deployment.py 2014-10-07 21:21:43 +0000
@@ -1,6 +1,7 @@
1#!/usr/bin/python1#!/usr/bin/python
22
3import amulet3import amulet
4import time
4try:5try:
5 from quantumclient.v2_0 import client as neutronclient6 from quantumclient.v2_0 import client as neutronclient
6except ImportError:7except ImportError:
@@ -23,10 +24,10 @@
23class QuantumGatewayBasicDeployment(OpenStackAmuletDeployment):24class QuantumGatewayBasicDeployment(OpenStackAmuletDeployment):
24 """Amulet tests on a basic quantum-gateway deployment."""25 """Amulet tests on a basic quantum-gateway deployment."""
2526
26 def __init__(self, series, openstack=None, source=None):27 def __init__(self, series, openstack=None, source=None, stable=False):
27 """Deploy the entire test environment."""28 """Deploy the entire test environment."""
28 super(QuantumGatewayBasicDeployment, self).__init__(series, openstack,29 super(QuantumGatewayBasicDeployment, self).__init__(series, openstack,
29 source)30 source, stable)
30 self._add_services()31 self._add_services()
31 self._add_relations()32 self._add_relations()
32 self._configure_services()33 self._configure_services()
@@ -34,13 +35,16 @@
34 self._initialize_tests()35 self._initialize_tests()
3536
36 def _add_services(self):37 def _add_services(self):
37 """Add the service that we're testing, including the number of units,38 """Add services
38 where quantum-gateway is local, and the other charms are from39
39 the charm store."""40 Add the services that we're testing, where quantum-gateway is local,
40 this_service = ('quantum-gateway', 1)41 and the rest of the service are from lp branches that are
41 other_services = [('mysql', 1),42 compatible with the local charm (e.g. stable or next).
42 ('rabbitmq-server', 1), ('keystone', 1),43 """
43 ('nova-cloud-controller', 1)]44 this_service = {'name': 'quantum-gateway'}
45 other_services = [{'name': 'mysql'},
46 {'name': 'rabbitmq-server'}, {'name': 'keystone'},
47 {'name': 'nova-cloud-controller'}]
44 super(QuantumGatewayBasicDeployment, self)._add_services(this_service,48 super(QuantumGatewayBasicDeployment, self)._add_services(this_service,
45 other_services)49 other_services)
4650
@@ -77,6 +81,9 @@
77 self.nova_cc_sentry = self.d.sentry.unit['nova-cloud-controller/0']81 self.nova_cc_sentry = self.d.sentry.unit['nova-cloud-controller/0']
78 self.quantum_gateway_sentry = self.d.sentry.unit['quantum-gateway/0']82 self.quantum_gateway_sentry = self.d.sentry.unit['quantum-gateway/0']
7983
84 # Let things settle a bit before moving forward
85 time.sleep(30)
86
80 # Authenticate admin with keystone87 # Authenticate admin with keystone
81 self.keystone = u.authenticate_keystone_admin(self.keystone_sentry,88 self.keystone = u.authenticate_keystone_admin(self.keystone_sentry,
82 user='admin',89 user='admin',
@@ -238,9 +245,14 @@
238 message = u.relation_error('nova-cc network-service', ret)245 message = u.relation_error('nova-cc network-service', ret)
239 amulet.raise_status(amulet.FAIL, msg=message)246 amulet.raise_status(amulet.FAIL, msg=message)
240247
241 def test_restart_on_config_change(self):248 def test_z_restart_on_config_change(self):
242 """Verify that the specified services are restarted when the config249 """Verify that the specified services are restarted when the config
243 is changed."""250 is changed.
251
252 Note(coreycb): The method name with the _z_ is a little odd
253 but it forces the test to run last. It just makes things
254 easier because restarting services requires re-authorization.
255 """
244 if self._get_openstack_release() >= self.precise_havana:256 if self._get_openstack_release() >= self.precise_havana:
245 conf = '/etc/neutron/neutron.conf'257 conf = '/etc/neutron/neutron.conf'
246 services = ['neutron-dhcp-agent', 'neutron-openvswitch-agent',258 services = ['neutron-dhcp-agent', 'neutron-openvswitch-agent',
@@ -261,6 +273,7 @@
261 for s in services:273 for s in services:
262 if not u.service_restarted(self.quantum_gateway_sentry, s, conf,274 if not u.service_restarted(self.quantum_gateway_sentry, s, conf,
263 pgrep_full=True, sleep_time=time):275 pgrep_full=True, sleep_time=time):
276 self.d.configure('quantum-gateway', {'debug': 'False'})
264 msg = "service {} didn't restart after config change".format(s)277 msg = "service {} didn't restart after config change".format(s)
265 amulet.raise_status(amulet.FAIL, msg=msg)278 amulet.raise_status(amulet.FAIL, msg=msg)
266 time = 0279 time = 0
@@ -347,7 +360,7 @@
347 'ml2': {360 'ml2': {
348 'type_drivers': 'gre,vxlan',361 'type_drivers': 'gre,vxlan',
349 'tenant_network_types': 'gre,vxlan',362 'tenant_network_types': 'gre,vxlan',
350 'mechanism_drivers': 'openvswitch'363 'mechanism_drivers': 'openvswitch,l2population'
351 },364 },
352 'ml2_type_gre': {365 'ml2_type_gre': {
353 'tunnel_id_ranges': '1:1000'366 'tunnel_id_ranges': '1:1000'
@@ -629,7 +642,7 @@
629 'nova_metadata_port': '8775'642 'nova_metadata_port': '8775'
630 }643 }
631 if self._get_openstack_release() >= self.precise_icehouse:644 if self._get_openstack_release() >= self.precise_icehouse:
632 expected['cache_url'] = 'memory://?default_ttl=5'645 expected['cache_url'] = 'memory://?default_ttl=5'
633646
634 ret = u.validate_config_data(unit, conf, 'DEFAULT', expected)647 ret = u.validate_config_data(unit, conf, 'DEFAULT', expected)
635 if ret:648 if ret:
636649
=== modified file 'tests/charmhelpers/contrib/amulet/deployment.py'
--- tests/charmhelpers/contrib/amulet/deployment.py 2014-09-25 15:37:05 +0000
+++ tests/charmhelpers/contrib/amulet/deployment.py 2014-10-07 21:21:43 +0000
@@ -25,25 +25,30 @@
2525
26 Add services to the deployment where this_service is the local charm26 Add services to the deployment where this_service is the local charm
27 that we're testing and other_services are the other services that27 that we're testing and other_services are the other services that
28 are being used in the amulet tests.28 are being used in the local amulet tests.
29 """29 """
30 name, units, location = range(3)30 if this_service['name'] != os.path.basename(os.getcwd()):
3131 s = this_service['name']
32 if this_service[name] != os.path.basename(os.getcwd()):
33 s = this_service[name]
34 msg = "The charm's root directory name needs to be {}".format(s)32 msg = "The charm's root directory name needs to be {}".format(s)
35 amulet.raise_status(amulet.FAIL, msg=msg)33 amulet.raise_status(amulet.FAIL, msg=msg)
3634
37 self.d.add(this_service[name], units=this_service[units])35 if 'units' not in this_service:
36 this_service['units'] = 1
37
38 self.d.add(this_service['name'], units=this_service['units'])
3839
39 for svc in other_services:40 for svc in other_services:
40 if len(svc) > 2:41 if 'location' in svc:
41 branch_location = svc[location]42 branch_location = svc['location']
42 elif self.series:43 elif self.series:
43 branch_location = 'cs:{}/{}'.format(self.series, svc[name]),44 branch_location = 'cs:{}/{}'.format(self.series, svc['name']),
44 else:45 else:
45 branch_location = None46 branch_location = None
46 self.d.add(svc[name], charm=branch_location, units=svc[units])47
48 if 'units' not in svc:
49 svc['units'] = 1
50
51 self.d.add(svc['name'], charm=branch_location, units=svc['units'])
4752
48 def _add_relations(self, relations):53 def _add_relations(self, relations):
49 """Add all of the relations for the services."""54 """Add all of the relations for the services."""
5055
=== modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py'
--- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2014-09-25 15:37:05 +0000
+++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2014-10-07 21:21:43 +0000
@@ -1,6 +1,3 @@
1from bzrlib.branch import Branch
2import os
3import re
4from charmhelpers.contrib.amulet.deployment import (1from charmhelpers.contrib.amulet.deployment import (
5 AmuletDeployment2 AmuletDeployment
6)3)
@@ -13,62 +10,62 @@
13 that is specifically for use by OpenStack charms.10 that is specifically for use by OpenStack charms.
14 """11 """
1512
16 def __init__(self, series=None, openstack=None, source=None):13 def __init__(self, series=None, openstack=None, source=None, stable=True):
17 """Initialize the deployment environment."""14 """Initialize the deployment environment."""
18 super(OpenStackAmuletDeployment, self).__init__(series)15 super(OpenStackAmuletDeployment, self).__init__(series)
19 self.openstack = openstack16 self.openstack = openstack
20 self.source = source17 self.source = source
2118 self.stable = stable
22 def _is_dev_branch(self):19 # Note(coreycb): this needs to be changed when new next branches come
23 """Determine if branch being tested is a dev (i.e. next) branch."""20 # out.
24 branch = Branch.open(os.getcwd())21 self.current_next = "trusty"
25 parent = branch.get_parent()
26 pattern = re.compile("^.*/next/$")
27 if (pattern.match(parent)):
28 return True
29 else:
30 return False
3122
32 def _determine_branch_locations(self, other_services):23 def _determine_branch_locations(self, other_services):
33 """Determine the branch locations for the other services.24 """Determine the branch locations for the other services.
3425
35 If the branch being tested is a dev branch, then determine the26 Determine if the local branch being tested is derived from its
36 development branch locations for the other services. Otherwise,27 stable or next (dev) branch, and based on this, use the corresonding
37 the default charm store branches will be used."""28 stable or next branches for the other_services."""
38 name = 029 base_charms = ['mysql', 'mongodb', 'rabbitmq-server']
39 if self._is_dev_branch():30
40 updated_services = []31 if self.stable:
41 for svc in other_services:32 for svc in other_services:
42 if svc[name] in ['mysql', 'mongodb', 'rabbitmq-server']:33 temp = 'lp:charms/{}'
43 location = 'lp:charms/{}'.format(svc[name])34 svc['location'] = temp.format(svc['name'])
35 else:
36 for svc in other_services:
37 if svc['name'] in base_charms:
38 temp = 'lp:charms/{}'
39 svc['location'] = temp.format(svc['name'])
44 else:40 else:
45 temp = 'lp:~openstack-charmers/charms/trusty/{}/next'41 temp = 'lp:~openstack-charmers/charms/{}/{}/next'
46 location = temp.format(svc[name])42 svc['location'] = temp.format(self.current_next,
47 updated_services.append(svc + (location,))43 svc['name'])
48 other_services = updated_services
49 return other_services44 return other_services
5045
51 def _add_services(self, this_service, other_services):46 def _add_services(self, this_service, other_services):
52 """Add services to the deployment and set openstack-origin/source."""47 """Add services to the deployment and set openstack-origin/source."""
53 name = 0
54 other_services = self._determine_branch_locations(other_services)48 other_services = self._determine_branch_locations(other_services)
49
55 super(OpenStackAmuletDeployment, self)._add_services(this_service,50 super(OpenStackAmuletDeployment, self)._add_services(this_service,
56 other_services)51 other_services)
52
57 services = other_services53 services = other_services
58 services.append(this_service)54 services.append(this_service)
59 use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph']55 use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
56 'ceph-osd', 'ceph-radosgw']
6057
61 if self.openstack:58 if self.openstack:
62 for svc in services:59 for svc in services:
63 if svc[name] not in use_source:60 if svc['name'] not in use_source:
64 config = {'openstack-origin': self.openstack}61 config = {'openstack-origin': self.openstack}
65 self.d.configure(svc[name], config)62 self.d.configure(svc['name'], config)
6663
67 if self.source:64 if self.source:
68 for svc in services:65 for svc in services:
69 if svc[name] in use_source:66 if svc['name'] in use_source:
70 config = {'source': self.source}67 config = {'source': self.source}
71 self.d.configure(svc[name], config)68 self.d.configure(svc['name'], config)
7269
73 def _configure_services(self, configs):70 def _configure_services(self, configs):
74 """Configure all of the services."""71 """Configure all of the services."""

Subscribers

People subscribed via source and target branches