Merge lp:~1chb1n/charms/trusty/keystone/amulet-fix-lp1440950 into lp:~openstack-charmers-archive/charms/trusty/keystone/next

Proposed by Ryan Beisner
Status: Merged
Merged at revision: 140
Proposed branch: lp:~1chb1n/charms/trusty/keystone/amulet-fix-lp1440950
Merge into: lp:~openstack-charmers-archive/charms/trusty/keystone/next
Diff against target: 715 lines (+386/-103)
10 files modified
hooks/charmhelpers/contrib/openstack/amulet/deployment.py (+25/-2)
hooks/charmhelpers/contrib/openstack/context.py (+149/-5)
hooks/charmhelpers/contrib/openstack/templates/git.upstart (+13/-0)
hooks/charmhelpers/contrib/openstack/templates/section-zeromq (+14/-0)
hooks/charmhelpers/contrib/openstack/templates/zeromq (+0/-14)
hooks/charmhelpers/contrib/openstack/utils.py (+132/-69)
hooks/charmhelpers/core/hookenv.py (+14/-1)
hooks/charmhelpers/core/unitdata.py (+1/-1)
tests/basic_deployment.py (+13/-9)
tests/charmhelpers/contrib/openstack/amulet/deployment.py (+25/-2)
To merge this branch: bzr merge lp:~1chb1n/charms/trusty/keystone/amulet-fix-lp1440950
Reviewer Review Type Date Requested Status
Corey Bryant (community) Approve
Review via email: mp+255606@code.launchpad.net

Description of the change

Cherry pick amulet test fix from these branches regarding this bug so that we can fix the testing now; also sync charm helpers.

Please land this ASAP so that automated testing can resume for this charm.

https://bugs.launchpad.net/charms/+source/keystone/+bug/1440950

https://code.launchpad.net/~corey.bryant/charms/trusty/keystone/git/+merge/242864

https://code.launchpad.net/~corey.bryant/charms/trusty/keystone/git

To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #3172 keystone-next for 1chb1n mp255606
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/3172/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #2960 keystone-next for 1chb1n mp255606
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/2960/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #2967 keystone-next for 1chb1n mp255606
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/2967/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #3178 keystone-next for 1chb1n mp255606
    LINT OK: passed

Build: http://10.245.162.77:8080/job/charm_lint_check/3178/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #2966 keystone-next for 1chb1n mp255606
    UNIT OK: passed

Build: http://10.245.162.77:8080/job/charm_unit_test/2966/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_amulet_test #2982 keystone-next for 1chb1n mp255606
    AMULET OK: passed

Build: http://10.245.162.77:8080/job/charm_amulet_test/2982/

Revision history for this message
Corey Bryant (corey.bryant) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/charmhelpers/contrib/openstack/amulet/deployment.py'
2--- hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-02-26 04:32:18 +0000
3+++ hooks/charmhelpers/contrib/openstack/amulet/deployment.py 2015-04-09 02:25:23 +0000
4@@ -15,6 +15,7 @@
5 # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
6
7 import six
8+from collections import OrderedDict
9 from charmhelpers.contrib.amulet.deployment import (
10 AmuletDeployment
11 )
12@@ -100,12 +101,34 @@
13 """
14 (self.precise_essex, self.precise_folsom, self.precise_grizzly,
15 self.precise_havana, self.precise_icehouse,
16- self.trusty_icehouse) = range(6)
17+ self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8)
18 releases = {
19 ('precise', None): self.precise_essex,
20 ('precise', 'cloud:precise-folsom'): self.precise_folsom,
21 ('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
22 ('precise', 'cloud:precise-havana'): self.precise_havana,
23 ('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
24- ('trusty', None): self.trusty_icehouse}
25+ ('trusty', None): self.trusty_icehouse,
26+ ('trusty', 'cloud:trusty-juno'): self.trusty_juno,
27+ ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo}
28 return releases[(self.series, self.openstack)]
29+
30+ def _get_openstack_release_string(self):
31+ """Get openstack release string.
32+
33+ Return a string representing the openstack release.
34+ """
35+ releases = OrderedDict([
36+ ('precise', 'essex'),
37+ ('quantal', 'folsom'),
38+ ('raring', 'grizzly'),
39+ ('saucy', 'havana'),
40+ ('trusty', 'icehouse'),
41+ ('utopic', 'juno'),
42+ ('vivid', 'kilo'),
43+ ])
44+ if self.openstack:
45+ os_origin = self.openstack.split(':')[1]
46+ return os_origin.split('%s-' % self.series)[1].split('/')[0]
47+ else:
48+ return releases[self.series]
49
50=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
51--- hooks/charmhelpers/contrib/openstack/context.py 2015-03-18 13:48:33 +0000
52+++ hooks/charmhelpers/contrib/openstack/context.py 2015-04-09 02:25:23 +0000
53@@ -47,6 +47,7 @@
54 )
55
56 from charmhelpers.core.sysctl import create as sysctl_create
57+from charmhelpers.core.strutils import bool_from_string
58
59 from charmhelpers.core.host import (
60 list_nics,
61@@ -67,6 +68,7 @@
62 )
63 from charmhelpers.contrib.openstack.neutron import (
64 neutron_plugin_attribute,
65+ parse_data_port_mappings,
66 )
67 from charmhelpers.contrib.openstack.ip import (
68 resolve_address,
69@@ -82,7 +84,6 @@
70 is_bridge_member,
71 )
72 from charmhelpers.contrib.openstack.utils import get_host_ip
73-
74 CA_CERT_PATH = '/usr/local/share/ca-certificates/keystone_juju_ca_cert.crt'
75 ADDRESS_TYPES = ['admin', 'internal', 'public']
76
77@@ -319,14 +320,15 @@
78
79
80 class IdentityServiceContext(OSContextGenerator):
81- interfaces = ['identity-service']
82
83- def __init__(self, service=None, service_user=None):
84+ def __init__(self, service=None, service_user=None, rel_name='identity-service'):
85 self.service = service
86 self.service_user = service_user
87+ self.rel_name = rel_name
88+ self.interfaces = [self.rel_name]
89
90 def __call__(self):
91- log('Generating template context for identity-service', level=DEBUG)
92+ log('Generating template context for ' + self.rel_name, level=DEBUG)
93 ctxt = {}
94
95 if self.service and self.service_user:
96@@ -340,7 +342,7 @@
97
98 ctxt['signing_dir'] = cachedir
99
100- for rid in relation_ids('identity-service'):
101+ for rid in relation_ids(self.rel_name):
102 for unit in related_units(rid):
103 rdata = relation_get(rid=rid, unit=unit)
104 serv_host = rdata.get('service_host')
105@@ -1162,3 +1164,145 @@
106 sysctl_create(sysctl_dict,
107 '/etc/sysctl.d/50-{0}.conf'.format(charm_name()))
108 return {'sysctl': sysctl_dict}
109+
110+
111+class NeutronAPIContext(OSContextGenerator):
112+ '''
113+ Inspects current neutron-plugin-api relation for neutron settings. Return
114+ defaults if it is not present.
115+ '''
116+ interfaces = ['neutron-plugin-api']
117+
118+ def __call__(self):
119+ self.neutron_defaults = {
120+ 'l2_population': {
121+ 'rel_key': 'l2-population',
122+ 'default': False,
123+ },
124+ 'overlay_network_type': {
125+ 'rel_key': 'overlay-network-type',
126+ 'default': 'gre',
127+ },
128+ 'neutron_security_groups': {
129+ 'rel_key': 'neutron-security-groups',
130+ 'default': False,
131+ },
132+ 'network_device_mtu': {
133+ 'rel_key': 'network-device-mtu',
134+ 'default': None,
135+ },
136+ 'enable_dvr': {
137+ 'rel_key': 'enable-dvr',
138+ 'default': False,
139+ },
140+ 'enable_l3ha': {
141+ 'rel_key': 'enable-l3ha',
142+ 'default': False,
143+ },
144+ }
145+ ctxt = self.get_neutron_options({})
146+ for rid in relation_ids('neutron-plugin-api'):
147+ for unit in related_units(rid):
148+ rdata = relation_get(rid=rid, unit=unit)
149+ if 'l2-population' in rdata:
150+ ctxt.update(self.get_neutron_options(rdata))
151+
152+ return ctxt
153+
154+ def get_neutron_options(self, rdata):
155+ settings = {}
156+ for nkey in self.neutron_defaults.keys():
157+ defv = self.neutron_defaults[nkey]['default']
158+ rkey = self.neutron_defaults[nkey]['rel_key']
159+ if rkey in rdata.keys():
160+ if type(defv) is bool:
161+ settings[nkey] = bool_from_string(rdata[rkey])
162+ else:
163+ settings[nkey] = rdata[rkey]
164+ else:
165+ settings[nkey] = defv
166+ return settings
167+
168+
169+class ExternalPortContext(NeutronPortContext):
170+
171+ def __call__(self):
172+ ctxt = {}
173+ ports = config('ext-port')
174+ if ports:
175+ ports = [p.strip() for p in ports.split()]
176+ ports = self.resolve_ports(ports)
177+ if ports:
178+ ctxt = {"ext_port": ports[0]}
179+ napi_settings = NeutronAPIContext()()
180+ mtu = napi_settings.get('network_device_mtu')
181+ if mtu:
182+ ctxt['ext_port_mtu'] = mtu
183+
184+ return ctxt
185+
186+
187+class DataPortContext(NeutronPortContext):
188+
189+ def __call__(self):
190+ ports = config('data-port')
191+ if ports:
192+ portmap = parse_data_port_mappings(ports)
193+ ports = portmap.values()
194+ resolved = self.resolve_ports(ports)
195+ normalized = {get_nic_hwaddr(port): port for port in resolved
196+ if port not in ports}
197+ normalized.update({port: port for port in resolved
198+ if port in ports})
199+ if resolved:
200+ return {bridge: normalized[port] for bridge, port in
201+ six.iteritems(portmap) if port in normalized.keys()}
202+
203+ return None
204+
205+
206+class PhyNICMTUContext(DataPortContext):
207+
208+ def __call__(self):
209+ ctxt = {}
210+ mappings = super(PhyNICMTUContext, self).__call__()
211+ if mappings and mappings.values():
212+ ports = mappings.values()
213+ napi_settings = NeutronAPIContext()()
214+ mtu = napi_settings.get('network_device_mtu')
215+ if mtu:
216+ ctxt["devs"] = '\\n'.join(ports)
217+ ctxt['mtu'] = mtu
218+
219+ return ctxt
220+
221+
222+class NetworkServiceContext(OSContextGenerator):
223+
224+ def __init__(self, rel_name='quantum-network-service'):
225+ self.rel_name = rel_name
226+ self.interfaces = [rel_name]
227+
228+ def __call__(self):
229+ for rid in relation_ids(self.rel_name):
230+ for unit in related_units(rid):
231+ rdata = relation_get(rid=rid, unit=unit)
232+ ctxt = {
233+ 'keystone_host': rdata.get('keystone_host'),
234+ 'service_port': rdata.get('service_port'),
235+ 'auth_port': rdata.get('auth_port'),
236+ 'service_tenant': rdata.get('service_tenant'),
237+ 'service_username': rdata.get('service_username'),
238+ 'service_password': rdata.get('service_password'),
239+ 'quantum_host': rdata.get('quantum_host'),
240+ 'quantum_port': rdata.get('quantum_port'),
241+ 'quantum_url': rdata.get('quantum_url'),
242+ 'region': rdata.get('region'),
243+ 'service_protocol':
244+ rdata.get('service_protocol') or 'http',
245+ 'auth_protocol':
246+ rdata.get('auth_protocol') or 'http',
247+ }
248+ if context_complete(ctxt):
249+ return ctxt
250+ return {}
251
252=== added file 'hooks/charmhelpers/contrib/openstack/templates/git.upstart'
253--- hooks/charmhelpers/contrib/openstack/templates/git.upstart 1970-01-01 00:00:00 +0000
254+++ hooks/charmhelpers/contrib/openstack/templates/git.upstart 2015-04-09 02:25:23 +0000
255@@ -0,0 +1,13 @@
256+description "{{ service_description }}"
257+author "Juju {{ service_name }} Charm <juju@localhost>"
258+
259+start on runlevel [2345]
260+stop on runlevel [!2345]
261+
262+respawn
263+
264+exec start-stop-daemon --start --chuid {{ user_name }} \
265+ --chdir {{ start_dir }} --name {{ process_name }} \
266+ --exec {{ executable_name }} -- \
267+ --config-file={{ config_file }} \
268+ --log-file={{ log_file }}
269
270=== added file 'hooks/charmhelpers/contrib/openstack/templates/section-zeromq'
271--- hooks/charmhelpers/contrib/openstack/templates/section-zeromq 1970-01-01 00:00:00 +0000
272+++ hooks/charmhelpers/contrib/openstack/templates/section-zeromq 2015-04-09 02:25:23 +0000
273@@ -0,0 +1,14 @@
274+{% if zmq_host -%}
275+# ZeroMQ configuration (restart-nonce: {{ zmq_nonce }})
276+rpc_backend = zmq
277+rpc_zmq_host = {{ zmq_host }}
278+{% if zmq_redis_address -%}
279+rpc_zmq_matchmaker = redis
280+matchmaker_heartbeat_freq = 15
281+matchmaker_heartbeat_ttl = 30
282+[matchmaker_redis]
283+host = {{ zmq_redis_address }}
284+{% else -%}
285+rpc_zmq_matchmaker = ring
286+{% endif -%}
287+{% endif -%}
288
289=== removed file 'hooks/charmhelpers/contrib/openstack/templates/zeromq'
290--- hooks/charmhelpers/contrib/openstack/templates/zeromq 2015-02-26 04:32:18 +0000
291+++ hooks/charmhelpers/contrib/openstack/templates/zeromq 1970-01-01 00:00:00 +0000
292@@ -1,14 +0,0 @@
293-{% if zmq_host -%}
294-# ZeroMQ configuration (restart-nonce: {{ zmq_nonce }})
295-rpc_backend = zmq
296-rpc_zmq_host = {{ zmq_host }}
297-{% if zmq_redis_address -%}
298-rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_redis.MatchMakerRedis
299-matchmaker_heartbeat_freq = 15
300-matchmaker_heartbeat_ttl = 30
301-[matchmaker_redis]
302-host = {{ zmq_redis_address }}
303-{% else -%}
304-rpc_zmq_matchmaker = oslo.messaging._drivers.matchmaker_ring.MatchMakerRing
305-{% endif -%}
306-{% endif -%}
307
308=== modified file 'hooks/charmhelpers/contrib/openstack/utils.py'
309--- hooks/charmhelpers/contrib/openstack/utils.py 2015-03-04 09:51:12 +0000
310+++ hooks/charmhelpers/contrib/openstack/utils.py 2015-04-09 02:25:23 +0000
311@@ -30,6 +30,10 @@
312
313 from charmhelpers.contrib.network import ip
314
315+from charmhelpers.core import (
316+ unitdata,
317+)
318+
319 from charmhelpers.core.hookenv import (
320 config,
321 log as juju_log,
322@@ -330,6 +334,21 @@
323 error_out("Invalid openstack-release specified: %s" % rel)
324
325
326+def config_value_changed(option):
327+ """
328+ Determine if config value changed since last call to this function.
329+ """
330+ hook_data = unitdata.HookData()
331+ with hook_data():
332+ db = unitdata.kv()
333+ current = config(option)
334+ saved = db.get(option)
335+ db.set(option, current)
336+ if saved is None:
337+ return False
338+ return current != saved
339+
340+
341 def save_script_rc(script_path="scripts/scriptrc", **env_vars):
342 """
343 Write an rc file in the charm-delivered directory containing
344@@ -469,82 +488,103 @@
345
346
347 def git_install_requested():
348- """Returns true if openstack-origin-git is specified."""
349- return config('openstack-origin-git') != "None"
350+ """
351+ Returns true if openstack-origin-git is specified.
352+ """
353+ return config('openstack-origin-git') is not None
354
355
356 requirements_dir = None
357
358
359-def git_clone_and_install(file_name, core_project):
360- """Clone/install all OpenStack repos specified in yaml config file."""
361+def git_clone_and_install(projects_yaml, core_project):
362+ """
363+ Clone/install all specified OpenStack repositories.
364+
365+ The expected format of projects_yaml is:
366+ repositories:
367+ - {name: keystone,
368+ repository: 'git://git.openstack.org/openstack/keystone.git',
369+ branch: 'stable/icehouse'}
370+ - {name: requirements,
371+ repository: 'git://git.openstack.org/openstack/requirements.git',
372+ branch: 'stable/icehouse'}
373+ directory: /mnt/openstack-git
374+ http_proxy: http://squid.internal:3128
375+ https_proxy: https://squid.internal:3128
376+
377+ The directory, http_proxy, and https_proxy keys are optional.
378+ """
379 global requirements_dir
380+ parent_dir = '/mnt/openstack-git'
381
382- if file_name == "None":
383+ if not projects_yaml:
384 return
385
386- yaml_file = os.path.join(charm_dir(), file_name)
387-
388- # clone/install the requirements project first
389- installed = _git_clone_and_install_subset(yaml_file,
390- whitelist=['requirements'])
391- if 'requirements' not in installed:
392- error_out('requirements git repository must be specified')
393-
394- # clone/install all other projects except requirements and the core project
395- blacklist = ['requirements', core_project]
396- _git_clone_and_install_subset(yaml_file, blacklist=blacklist,
397- update_requirements=True)
398-
399- # clone/install the core project
400- whitelist = [core_project]
401- installed = _git_clone_and_install_subset(yaml_file, whitelist=whitelist,
402- update_requirements=True)
403- if core_project not in installed:
404- error_out('{} git repository must be specified'.format(core_project))
405-
406-
407-def _git_clone_and_install_subset(yaml_file, whitelist=[], blacklist=[],
408- update_requirements=False):
409- """Clone/install subset of OpenStack repos specified in yaml config file."""
410- global requirements_dir
411- installed = []
412-
413- with open(yaml_file, 'r') as fd:
414- projects = yaml.load(fd)
415- for proj, val in projects.items():
416- # The project subset is chosen based on the following 3 rules:
417- # 1) If project is in blacklist, we don't clone/install it, period.
418- # 2) If whitelist is empty, we clone/install everything else.
419- # 3) If whitelist is not empty, we clone/install everything in the
420- # whitelist.
421- if proj in blacklist:
422- continue
423- if whitelist and proj not in whitelist:
424- continue
425- repo = val['repository']
426- branch = val['branch']
427- repo_dir = _git_clone_and_install_single(repo, branch,
428- update_requirements)
429- if proj == 'requirements':
430- requirements_dir = repo_dir
431- installed.append(proj)
432- return installed
433-
434-
435-def _git_clone_and_install_single(repo, branch, update_requirements=False):
436- """Clone and install a single git repository."""
437- dest_parent_dir = "/mnt/openstack-git/"
438- dest_dir = os.path.join(dest_parent_dir, os.path.basename(repo))
439-
440- if not os.path.exists(dest_parent_dir):
441- juju_log('Host dir not mounted at {}. '
442- 'Creating directory there instead.'.format(dest_parent_dir))
443- os.mkdir(dest_parent_dir)
444+ projects = yaml.load(projects_yaml)
445+ _git_validate_projects_yaml(projects, core_project)
446+
447+ if 'http_proxy' in projects.keys():
448+ os.environ['http_proxy'] = projects['http_proxy']
449+
450+ if 'https_proxy' in projects.keys():
451+ os.environ['https_proxy'] = projects['https_proxy']
452+
453+ if 'directory' in projects.keys():
454+ parent_dir = projects['directory']
455+
456+ for p in projects['repositories']:
457+ repo = p['repository']
458+ branch = p['branch']
459+ if p['name'] == 'requirements':
460+ repo_dir = _git_clone_and_install_single(repo, branch, parent_dir,
461+ update_requirements=False)
462+ requirements_dir = repo_dir
463+ else:
464+ repo_dir = _git_clone_and_install_single(repo, branch, parent_dir,
465+ update_requirements=True)
466+
467+
468+def _git_validate_projects_yaml(projects, core_project):
469+ """
470+ Validate the projects yaml.
471+ """
472+ _git_ensure_key_exists('repositories', projects)
473+
474+ for project in projects['repositories']:
475+ _git_ensure_key_exists('name', project.keys())
476+ _git_ensure_key_exists('repository', project.keys())
477+ _git_ensure_key_exists('branch', project.keys())
478+
479+ if projects['repositories'][0]['name'] != 'requirements':
480+ error_out('{} git repo must be specified first'.format('requirements'))
481+
482+ if projects['repositories'][-1]['name'] != core_project:
483+ error_out('{} git repo must be specified last'.format(core_project))
484+
485+
486+def _git_ensure_key_exists(key, keys):
487+ """
488+ Ensure that key exists in keys.
489+ """
490+ if key not in keys:
491+ error_out('openstack-origin-git key \'{}\' is missing'.format(key))
492+
493+
494+def _git_clone_and_install_single(repo, branch, parent_dir, update_requirements):
495+ """
496+ Clone and install a single git repository.
497+ """
498+ dest_dir = os.path.join(parent_dir, os.path.basename(repo))
499+
500+ if not os.path.exists(parent_dir):
501+ juju_log('Directory already exists at {}. '
502+ 'No need to create directory.'.format(parent_dir))
503+ os.mkdir(parent_dir)
504
505 if not os.path.exists(dest_dir):
506 juju_log('Cloning git repo: {}, branch: {}'.format(repo, branch))
507- repo_dir = install_remote(repo, dest=dest_parent_dir, branch=branch)
508+ repo_dir = install_remote(repo, dest=parent_dir, branch=branch)
509 else:
510 repo_dir = dest_dir
511
512@@ -561,16 +601,39 @@
513
514
515 def _git_update_requirements(package_dir, reqs_dir):
516- """Update from global requirements.
517+ """
518+ Update from global requirements.
519
520- Update an OpenStack git directory's requirements.txt and
521- test-requirements.txt from global-requirements.txt."""
522+ Update an OpenStack git directory's requirements.txt and
523+ test-requirements.txt from global-requirements.txt.
524+ """
525 orig_dir = os.getcwd()
526 os.chdir(reqs_dir)
527- cmd = "python update.py {}".format(package_dir)
528+ cmd = ['python', 'update.py', package_dir]
529 try:
530- subprocess.check_call(cmd.split(' '))
531+ subprocess.check_call(cmd)
532 except subprocess.CalledProcessError:
533 package = os.path.basename(package_dir)
534 error_out("Error updating {} from global-requirements.txt".format(package))
535 os.chdir(orig_dir)
536+
537+
538+def git_src_dir(projects_yaml, project):
539+ """
540+ Return the directory where the specified project's source is located.
541+ """
542+ parent_dir = '/mnt/openstack-git'
543+
544+ if not projects_yaml:
545+ return
546+
547+ projects = yaml.load(projects_yaml)
548+
549+ if 'directory' in projects.keys():
550+ parent_dir = projects['directory']
551+
552+ for p in projects['repositories']:
553+ if p['name'] == project:
554+ return os.path.join(parent_dir, os.path.basename(p['repository']))
555+
556+ return None
557
558=== modified file 'hooks/charmhelpers/core/hookenv.py'
559--- hooks/charmhelpers/core/hookenv.py 2015-03-18 13:48:33 +0000
560+++ hooks/charmhelpers/core/hookenv.py 2015-04-09 02:25:23 +0000
561@@ -20,11 +20,13 @@
562 # Authors:
563 # Charm Helpers Developers <juju@lists.ubuntu.com>
564
565+from __future__ import print_function
566 import os
567 import json
568 import yaml
569 import subprocess
570 import sys
571+import errno
572 from subprocess import CalledProcessError
573
574 import six
575@@ -87,7 +89,18 @@
576 if not isinstance(message, six.string_types):
577 message = repr(message)
578 command += [message]
579- subprocess.call(command)
580+ # Missing juju-log should not cause failures in unit tests
581+ # Send log output to stderr
582+ try:
583+ subprocess.call(command)
584+ except OSError as e:
585+ if e.errno == errno.ENOENT:
586+ if level:
587+ message = "{}: {}".format(level, message)
588+ message = "juju-log: {}".format(message)
589+ print(message, file=sys.stderr)
590+ else:
591+ raise
592
593
594 class Serializable(UserDict):
595
596=== modified file 'hooks/charmhelpers/core/unitdata.py'
597--- hooks/charmhelpers/core/unitdata.py 2015-02-19 04:16:18 +0000
598+++ hooks/charmhelpers/core/unitdata.py 2015-04-09 02:25:23 +0000
599@@ -443,7 +443,7 @@
600 data = hookenv.execution_environment()
601 self.conf = conf_delta = self.kv.delta(data['conf'], 'config')
602 self.rels = rels_delta = self.kv.delta(data['rels'], 'rels')
603- self.kv.set('env', data['env'])
604+ self.kv.set('env', dict(data['env']))
605 self.kv.set('unit', data['unit'])
606 self.kv.set('relid', data.get('relid'))
607 return conf_delta, rels_delta
608
609=== modified file 'tests/basic_deployment.py'
610--- tests/basic_deployment.py 2015-03-10 12:02:11 +0000
611+++ tests/basic_deployment.py 2015-04-09 02:25:23 +0000
612@@ -146,14 +146,13 @@
613 'tenantId': u.not_null,
614 'id': u.not_null,
615 'email': 'juju@localhost'}
616- user3 = {'name': 'cinder',
617+ user3 = {'name': 'cinder_cinderv2',
618 'enabled': True,
619 'tenantId': u.not_null,
620 'id': u.not_null,
621 'email': u'juju@localhost'}
622 expected = [user1, user2, user3]
623 actual = self.keystone.users.list()
624-
625 ret = u.validate_user_data(expected, actual)
626 if ret:
627 amulet.raise_status(amulet.FAIL, msg=ret)
628@@ -254,13 +253,13 @@
629 'auth_protocol': 'http',
630 'private-address': u.valid_ip,
631 'auth_host': u.valid_ip,
632- 'service_username': 'cinder',
633+ 'service_username': 'cinder_cinderv2',
634 'service_tenant_id': u.not_null,
635 'service_host': u.valid_ip
636 }
637 ret = u.validate_relation_data(unit, relation, expected)
638 if ret:
639- message = u.relation_error('cinder identity-service', ret)
640+ message = u.relation_error('keystone identity-service', ret)
641 amulet.raise_status(amulet.FAIL, msg=message)
642
643 def test_cinder_identity_service_relation(self):
644@@ -268,12 +267,17 @@
645 unit = self.cinder_sentry
646 relation = ['identity-service', 'keystone:identity-service']
647 expected = {
648- 'service': 'cinder',
649- 'region': 'RegionOne',
650- 'public_url': u.valid_url,
651- 'internal_url': u.valid_url,
652+ 'cinder_service': 'cinder',
653+ 'cinder_region': 'RegionOne',
654+ 'cinder_public_url': u.valid_url,
655+ 'cinder_internal_url': u.valid_url,
656+ 'cinder_admin_url': u.valid_url,
657+ 'cinderv2_service': 'cinderv2',
658+ 'cinderv2_region': 'RegionOne',
659+ 'cinderv2_public_url': u.valid_url,
660+ 'cinderv2_internal_url': u.valid_url,
661+ 'cinderv2_admin_url': u.valid_url,
662 'private-address': u.valid_ip,
663- 'admin_url': u.valid_url
664 }
665 ret = u.validate_relation_data(unit, relation, expected)
666 if ret:
667
668=== modified file 'tests/charmhelpers/contrib/openstack/amulet/deployment.py'
669--- tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-02-26 04:32:18 +0000
670+++ tests/charmhelpers/contrib/openstack/amulet/deployment.py 2015-04-09 02:25:23 +0000
671@@ -15,6 +15,7 @@
672 # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
673
674 import six
675+from collections import OrderedDict
676 from charmhelpers.contrib.amulet.deployment import (
677 AmuletDeployment
678 )
679@@ -100,12 +101,34 @@
680 """
681 (self.precise_essex, self.precise_folsom, self.precise_grizzly,
682 self.precise_havana, self.precise_icehouse,
683- self.trusty_icehouse) = range(6)
684+ self.trusty_icehouse, self.trusty_juno, self.trusty_kilo) = range(8)
685 releases = {
686 ('precise', None): self.precise_essex,
687 ('precise', 'cloud:precise-folsom'): self.precise_folsom,
688 ('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
689 ('precise', 'cloud:precise-havana'): self.precise_havana,
690 ('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
691- ('trusty', None): self.trusty_icehouse}
692+ ('trusty', None): self.trusty_icehouse,
693+ ('trusty', 'cloud:trusty-juno'): self.trusty_juno,
694+ ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo}
695 return releases[(self.series, self.openstack)]
696+
697+ def _get_openstack_release_string(self):
698+ """Get openstack release string.
699+
700+ Return a string representing the openstack release.
701+ """
702+ releases = OrderedDict([
703+ ('precise', 'essex'),
704+ ('quantal', 'folsom'),
705+ ('raring', 'grizzly'),
706+ ('saucy', 'havana'),
707+ ('trusty', 'icehouse'),
708+ ('utopic', 'juno'),
709+ ('vivid', 'kilo'),
710+ ])
711+ if self.openstack:
712+ os_origin = self.openstack.split(':')[1]
713+ return os_origin.split('%s-' % self.series)[1].split('/')[0]
714+ else:
715+ return releases[self.series]

Subscribers

People subscribed via source and target branches