Merge lp:~1chb1n/charms/trusty/keystone/amulet-fix-lp1440950 into lp:~openstack-charmers-archive/charms/trusty/keystone/next
- Trusty Tahr (14.04)
- amulet-fix-lp1440950
- Merge into next
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Corey Bryant (community) | Approve | ||
Review via email: mp+255606@code.launchpad.net |
Commit message
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:/
https:/
https:/
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #2960 keystone-next for 1chb1n mp255606
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #2967 keystone-next for 1chb1n mp255606
AMULET OK: passed
Build: http://
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_lint_check #3178 keystone-next for 1chb1n mp255606
LINT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #2966 keystone-next for 1chb1n mp255606
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #2982 keystone-next for 1chb1n mp255606
AMULET OK: passed
Build: http://
Corey Bryant (corey.bryant) : | # |
Preview Diff
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] |
charm_lint_check #3172 keystone-next for 1chb1n mp255606
LINT OK: passed
Build: http:// 10.245. 162.77: 8080/job/ charm_lint_ check/3172/