Merge lp:~thedac/charms/trusty/neutron-api/status into lp:~openstack-charmers-archive/charms/trusty/neutron-api/next

Proposed by David Ames
Status: Work in progress
Proposed branch: lp:~thedac/charms/trusty/neutron-api/status
Merge into: lp:~openstack-charmers-archive/charms/trusty/neutron-api/next
Diff against target: 638 lines (+246/-37)
6 files modified
hooks/charmhelpers/contrib/openstack/context.py (+8/-0)
hooks/charmhelpers/contrib/openstack/utils.py (+83/-1)
hooks/charmhelpers/core/hookenv.py (+84/-16)
hooks/neutron_api_hooks.py (+25/-1)
hooks/neutron_api_utils.py (+8/-0)
unit_tests/test_neutron_api_hooks.py (+38/-19)
To merge this branch: bzr merge lp:~thedac/charms/trusty/neutron-api/status
Reviewer Review Type Date Requested Status
James Page Needs Fixing
Review via email: mp+264315@code.launchpad.net

Commit message

Add workload status settings

Description of the change

Based on Liam Young's original work add workload status settings to the neutron-api charm as a proof of concept.

The plan is to move context_status, set_context_status and incomplete_contexts to charmhelpers.

Looking for feedback before proceeding.

To post a comment you must log in.
Revision history for this message
David Ames (thedac) wrote :
118. By David Ames

More status sets for install process

119. By David Ames

Use functools wraps

120. By David Ames

With @wraps in the decorator can now apply context_status to *_joined functions

121. By David Ames

Set status when waiting on a particular variable in a given context
Compound the status messages keeping the highest priority workload state

Revision history for this message
David Ames (thedac) wrote :

charmhelpers.contrib.openstack.context.context_complete now sets a waiting state when missing specific data. It uses status_compound which takes in the current status and a new state and message and "adds" them together keeping the most severe workload state and concatenating the messages.

It is important to note that in practice these statuses are ephemeral as the context_status decorator comes around and runs set_context_status which is a bit more of a hammer. This is necessary to make sure we set a known state rather than just the last set state wins.

I am very much open to ideas to get us further granularity into set_context_status. set_context_status relies on charmhelpers.contrib.openstack.templ
ates.OSConfigRenderer.complete_contexts which ultimately runs the __call__() function of the context object. We may be able to expand this somehow.

122. By David Ames

Updates to status_set

Revision history for this message
James Page (james-page) :
review: Needs Fixing
123. By David Ames

Set workload state waiting or blocked

124. By David Ames

Let the decorator set the status

125. By David Ames

Fix unit tests for new related(interface) check

Unmerged revisions

125. By David Ames

Fix unit tests for new related(interface) check

124. By David Ames

Let the decorator set the status

123. By David Ames

Set workload state waiting or blocked

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/charmhelpers/contrib/openstack/context.py'
2--- hooks/charmhelpers/contrib/openstack/context.py 2015-07-16 20:17:53 +0000
3+++ hooks/charmhelpers/contrib/openstack/context.py 2015-07-17 22:28:29 +0000
4@@ -37,6 +37,8 @@
5 relation_ids,
6 related_units,
7 relation_set,
8+ status_compound,
9+ status_get,
10 unit_get,
11 unit_private_ip,
12 charm_name,
13@@ -101,11 +103,17 @@
14
15 def context_complete(ctxt):
16 _missing = []
17+ # keys are set by default even before the relation completes them
18+ # i.e. rabbitmq-password: None
19+ # so if they are None or '' they are missing from the relation
20 for k, v in six.iteritems(ctxt):
21 if v is None or v == '':
22 _missing.append(k)
23
24 if _missing:
25+ status_compound(status_get(include_data=True), 'waiting',
26+ 'Missing required data: %s' %
27+ ' '.join(_missing))
28 log('Missing required data: %s' % ' '.join(_missing), level=INFO)
29 return False
30
31
32=== modified file 'hooks/charmhelpers/contrib/openstack/utils.py'
33--- hooks/charmhelpers/contrib/openstack/utils.py 2015-07-16 20:17:53 +0000
34+++ hooks/charmhelpers/contrib/openstack/utils.py 2015-07-17 22:28:29 +0000
35@@ -40,7 +40,8 @@
36 charm_dir,
37 INFO,
38 relation_ids,
39- relation_set
40+ relation_set,
41+ status_set
42 )
43
44 from charmhelpers.contrib.storage.linux.lvm import (
45@@ -704,3 +705,84 @@
46 return projects[key]
47
48 return None
49+
50+
51+def context_status(configs, required_interfaces):
52+ """
53+ Decorator to set workload status based on complete contexts
54+ after contexts have been acted on
55+ """
56+ def wrap(f):
57+ @wraps(f)
58+ def wrapped_f(*args, **kwargs):
59+ # Run the original function first
60+ f(*args, **kwargs)
61+ # Set workload status now that contexts have been
62+ # acted on
63+ set_context_status(configs, required_interfaces)
64+ return wrapped_f
65+ return wrap
66+
67+
68+def set_context_status(configs, required_interfaces):
69+ """
70+ Set workload status based on complete contexts
71+ Left outside of the decorator, context_status,
72+ to allow manual use
73+ """
74+ incomplete_ctxts = incomplete_contexts(configs, required_interfaces)
75+ state = 'active'
76+ message = ''
77+ for context in incomplete_ctxts:
78+ related_interface = None
79+ for interface in required_interfaces[context]:
80+ if related(interface):
81+ related_interface = interface
82+ if not related_interface:
83+ message += "{} context is missing and must be related for " \
84+ "functionality. ".format(context)
85+ state = 'blocked'
86+ else:
87+ message += "{} context's interface, {}, has joined but has not " \
88+ "yet provided the required data on the relation. " \
89+ "".format(context, related_interface)
90+ if state != 'blocked':
91+ state = 'waiting'
92+
93+ if state == 'active':
94+ message = "All required contexts are present and complete"
95+
96+ status_set(state, message)
97+
98+
99+def incomplete_contexts(configs, required_interfaces):
100+ """
101+ Check complete contexts against required_interfaces
102+ Return list of incomplete contexts
103+
104+ configs is an OSConfigRenderer object with configs registered
105+
106+ required_interfaces is a dictionary of required general interfaces
107+ with list values of possible specific interfaces.
108+ The interface is said to be satisfied if anyone of the interfaces in the
109+ list has a complete context.
110+ Example:
111+ required_interfaces = {'database': ['shared-db', 'pgsql-db']}
112+ """
113+ complete_ctxts = configs.complete_contexts()
114+ incomplete_contexts = []
115+ for svc_type in required_interfaces.keys():
116+ found_ctxt = False
117+ for interface in required_interfaces[svc_type]:
118+ if interface in complete_ctxts:
119+ found_ctxt = True
120+ if not found_ctxt:
121+ incomplete_contexts.append(svc_type)
122+ return incomplete_contexts
123+
124+
125+def related(interface):
126+ if relation_ids(interface):
127+ return True
128+ else:
129+ return False
130
131=== modified file 'hooks/charmhelpers/core/hookenv.py'
132--- hooks/charmhelpers/core/hookenv.py 2015-07-16 20:17:53 +0000
133+++ hooks/charmhelpers/core/hookenv.py 2015-07-17 22:28:29 +0000
134@@ -660,35 +660,103 @@
135 )
136 cmd = ['status-set', workload_state, message]
137 try:
138- ret = subprocess.call(cmd)
139- if ret == 0:
140+ subprocess.call(cmd)
141+ except OSError as e:
142+ if e.errno == errno.ENOENT:
143+ log_message = 'status-set failed: {} {}'.format(workload_state,
144+ message)
145+ log(log_message, level='INFO')
146 return
147- except OSError as e:
148- if e.errno != errno.ENOENT:
149+ else:
150 raise
151- log_message = 'status-set failed: {} {}'.format(workload_state,
152- message)
153- log(log_message, level='INFO')
154-
155-
156-def status_get():
157- """Retrieve the previously set juju workload state
158+ # Log the status change
159+ if workload_state == 'blocked' or workload_state == 'waiting':
160+ lvl = 'WARN'
161+ else:
162+ lvl = 'INFO'
163+ log('{}: {}'.format(workload_state, message), lvl)
164+
165+
166+def status_get(include_data=True, service=False):
167+ """Retrieve the previously set juju workload state and return as a
168+ dictionary.
169+
170+ If service is set return status for all units of this service if this unit
171+ is the leader
172
173 If the status-set command is not found then assume this is juju < 1.23 and
174 return 'unknown'
175 """
176- cmd = ['status-get']
177+ cmd = ['status-get', '--format', 'json']
178+ if include_data:
179+ cmd.append('--include-data')
180+ if service:
181+ cmd.append('--service')
182 try:
183- raw_status = subprocess.check_output(cmd, universal_newlines=True)
184- status = raw_status.rstrip()
185- return status
186+ return json.loads(subprocess.check_output(cmd,
187+ universal_newlines=True))
188 except OSError as e:
189 if e.errno == errno.ENOENT:
190- return 'unknown'
191+ return {'status': 'unknown'}
192 else:
193 raise
194
195
196+def status_compound(current_status, workload_state, message):
197+ """Compound statuses: Take the current status as a dictionary
198+ and new workload state and message then status_set with the highest
199+ severity workload state and a compound message
200+ Example:
201+ status_compound(status_get(include-data=True),
202+ 'waiting',
203+ 'waiting on relations data')
204+ """
205+ hierarchy = {'unknown': -1,
206+ 'active': 0,
207+ 'maintenance': 1,
208+ 'waiting': 2,
209+ 'blocked': 3,
210+ }
211+ current_workload_state = current_status.get('status')
212+ current_message = current_status.get('message')
213+
214+ # Do not set unknown or other invalid state
215+ if hierarchy.get(workload_state) is None:
216+ return {}
217+ elif hierarchy.get(workload_state) < 0:
218+ return {}
219+ if hierarchy.get(current_workload_state) is None:
220+ current_workload_state = 'unknown'
221+ current_message = None
222+ elif hierarchy.get(current_workload_state) < 0:
223+ current_message = None
224+
225+ # New state of 'active' overrides all others
226+ if workload_state == 'active':
227+ hierarchy['active'] = 10
228+ current_message = None
229+
230+ # Set workload_state based on hierarchy of statuses
231+ if hierarchy.get(current_workload_state) > hierarchy.get(workload_state):
232+ workload_state = current_workload_state
233+ else:
234+ if current_workload_state == 'active':
235+ current_message = None
236+
237+ # Compound the message
238+ if current_message and message:
239+ message = message + "; " + current_message
240+ elif current_message and not message:
241+ message = current_message
242+
243+ # Set new status
244+ if workload_state:
245+ status_set(workload_state, message)
246+
247+ # Return new status
248+ return {'status': workload_state, 'message': message}
249+
250+
251 def translate_exc(from_exc, to_exc):
252 def inner_translate_exc1(f):
253 def inner_translate_exc2(*args, **kwargs):
254
255=== modified file 'hooks/neutron_api_hooks.py'
256--- hooks/neutron_api_hooks.py 2015-04-23 08:49:03 +0000
257+++ hooks/neutron_api_hooks.py 2015-07-17 22:28:29 +0000
258@@ -17,6 +17,7 @@
259 relation_get,
260 relation_ids,
261 relation_set,
262+ status_set,
263 open_port,
264 unit_get,
265 )
266@@ -36,6 +37,7 @@
267 from charmhelpers.contrib.openstack.utils import (
268 config_value_changed,
269 configure_installation_source,
270+ context_status,
271 git_install_requested,
272 openstack_upgrade_available,
273 os_requires_version,
274@@ -46,6 +48,7 @@
275 from neutron_api_utils import (
276 CLUSTER_RES,
277 NEUTRON_CONF,
278+ REQUIRED_INTERFACES,
279 api_port,
280 determine_packages,
281 determine_ports,
282@@ -140,14 +143,18 @@
283
284
285 @hooks.hook()
286+@context_status(CONFIGS, REQUIRED_INTERFACES)
287 def install():
288+ status_set('maintenance', 'Executing pre-install')
289 execd_preinstall()
290 configure_installation_source(config('openstack-origin'))
291
292+ status_set('maintenance', 'Installing apt packages')
293 apt_update()
294 apt_install(determine_packages(config('openstack-origin')),
295 fatal=True)
296
297+ status_set('maintenance', 'Git install')
298 git_install(config('openstack-origin-git'))
299
300 [open_port(port) for port in determine_ports()]
301@@ -155,6 +162,7 @@
302
303 @hooks.hook('upgrade-charm')
304 @hooks.hook('config-changed')
305+@context_status(CONFIGS, REQUIRED_INTERFACES)
306 @restart_on_change(restart_map(), stopstart=True)
307 def config_changed():
308 # If neutron is ready to be queried then check for incompatability between
309@@ -163,14 +171,16 @@
310 if l3ha_router_present() and not get_l3ha():
311 e = ('Cannot disable Router HA while ha enabled routers exist.'
312 ' Please remove any ha routers')
313- log(e, level=ERROR)
314+ status_set('blocked', e)
315 raise Exception(e)
316 if dvr_router_present() and not get_dvr():
317 e = ('Cannot disable dvr while dvr enabled routers exist. Please'
318 ' remove any distributed routers')
319 log(e, level=ERROR)
320+ status_set('blocked', e)
321 raise Exception(e)
322 if config('prefer-ipv6'):
323+ status_set('maintenance', 'configuring ipv6')
324 setup_ipv6()
325 sync_db_with_multi_ipv6_addresses(config('database'),
326 config('database-user'))
327@@ -178,11 +188,14 @@
328 global CONFIGS
329 if git_install_requested():
330 if config_value_changed('openstack-origin-git'):
331+ status_set('maintenance', 'Running Git install')
332 git_install(config('openstack-origin-git'))
333 else:
334 if openstack_upgrade_available('neutron-server'):
335+ status_set('maintenance', 'Running openstack upgrade')
336 do_openstack_upgrade(CONFIGS)
337
338+ status_set('maintenance', 'Installing apt packages')
339 apt_install(filter_installed_packages(
340 determine_packages(config('openstack-origin'))),
341 fatal=True)
342@@ -203,6 +216,7 @@
343
344
345 @hooks.hook('amqp-relation-joined')
346+@context_status(CONFIGS, REQUIRED_INTERFACES)
347 def amqp_joined(relation_id=None):
348 relation_set(relation_id=relation_id,
349 username=config('rabbit-user'), vhost=config('rabbit-vhost'))
350@@ -210,6 +224,7 @@
351
352 @hooks.hook('amqp-relation-changed')
353 @hooks.hook('amqp-relation-departed')
354+@context_status(CONFIGS, REQUIRED_INTERFACES)
355 @restart_on_change(restart_map())
356 def amqp_changed():
357 if 'amqp' not in CONFIGS.complete_contexts():
358@@ -219,6 +234,7 @@
359
360
361 @hooks.hook('shared-db-relation-joined')
362+@context_status(CONFIGS, REQUIRED_INTERFACES)
363 def db_joined():
364 if is_relation_made('pgsql-db'):
365 # error, postgresql is used
366@@ -238,6 +254,7 @@
367
368
369 @hooks.hook('pgsql-db-relation-joined')
370+@context_status(CONFIGS, REQUIRED_INTERFACES)
371 def pgsql_neutron_db_joined():
372 if is_relation_made('shared-db'):
373 # raise error
374@@ -250,6 +267,7 @@
375
376
377 @hooks.hook('shared-db-relation-changed')
378+@context_status(CONFIGS, REQUIRED_INTERFACES)
379 @restart_on_change(restart_map())
380 def db_changed():
381 if 'shared-db' not in CONFIGS.complete_contexts():
382@@ -260,6 +278,7 @@
383
384
385 @hooks.hook('pgsql-db-relation-changed')
386+@context_status(CONFIGS, REQUIRED_INTERFACES)
387 @restart_on_change(restart_map())
388 def postgresql_neutron_db_changed():
389 CONFIGS.write(NEUTRON_CONF)
390@@ -270,11 +289,13 @@
391 'identity-service-relation-broken',
392 'shared-db-relation-broken',
393 'pgsql-db-relation-broken')
394+@context_status(CONFIGS, REQUIRED_INTERFACES)
395 def relation_broken():
396 CONFIGS.write_all()
397
398
399 @hooks.hook('identity-service-relation-joined')
400+@context_status(CONFIGS, REQUIRED_INTERFACES)
401 def identity_joined(rid=None, relation_trigger=False):
402 public_url = '{}:{}'.format(canonical_url(CONFIGS, PUBLIC),
403 api_port('neutron-server'))
404@@ -296,6 +317,7 @@
405
406
407 @hooks.hook('identity-service-relation-changed')
408+@context_status(CONFIGS, REQUIRED_INTERFACES)
409 @restart_on_change(restart_map())
410 def identity_changed():
411 if 'identity-service' not in CONFIGS.complete_contexts():
412@@ -472,6 +494,7 @@
413
414
415 @hooks.hook('zeromq-configuration-relation-joined')
416+@context_status(CONFIGS, REQUIRED_INTERFACES)
417 @os_requires_version('kilo', 'neutron-server')
418 def zeromq_configuration_relation_joined(relid=None):
419 relation_set(relation_id=relid,
420@@ -480,6 +503,7 @@
421
422
423 @hooks.hook('zeromq-configuration-relation-changed')
424+@context_status(CONFIGS, REQUIRED_INTERFACES)
425 @restart_on_change(restart_map(), stopstart=True)
426 def zeromq_configuration_relation_changed():
427 CONFIGS.write_all()
428
429=== modified file 'hooks/neutron_api_utils.py'
430--- hooks/neutron_api_utils.py 2015-07-13 19:07:37 +0000
431+++ hooks/neutron_api_utils.py 2015-07-17 22:28:29 +0000
432@@ -155,6 +155,14 @@
433 }),
434 ])
435
436+# The interface is said to be satisfied if anyone of the interfaces in the
437+# list has a complete context.
438+REQUIRED_INTERFACES = {
439+ 'database': ['shared-db', 'pgsql-db'],
440+ 'message': ['amqp', 'zeromq-configuration'],
441+ 'identity': ['identity-service'],
442+}
443+
444
445 def api_port(service):
446 return API_PORTS[service]
447
448=== modified file 'unit_tests/test_neutron_api_hooks.py'
449--- unit_tests/test_neutron_api_hooks.py 2015-06-04 23:28:14 +0000
450+++ unit_tests/test_neutron_api_hooks.py 2015-07-17 22:28:29 +0000
451@@ -96,8 +96,9 @@
452 hooks.hooks.execute([
453 'hooks/{}'.format(hookname)])
454
455+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
456 @patch.object(utils, 'git_install_requested')
457- def test_install_hook(self, git_requested):
458+ def test_install_hook(self, git_requested, related):
459 git_requested.return_value = False
460 _pkgs = ['foo', 'bar']
461 _ports = [80, 81, 82]
462@@ -115,8 +116,9 @@
463 self.open_port.assert_has_calls(_port_calls)
464 self.assertTrue(self.execd_preinstall.called)
465
466+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
467 @patch.object(utils, 'git_install_requested')
468- def test_install_hook_git(self, git_requested):
469+ def test_install_hook_git(self, git_requested, related):
470 git_requested.return_value = True
471 _pkgs = ['foo', 'bar']
472 _ports = [80, 81, 82]
473@@ -148,9 +150,10 @@
474 self.git_install.assert_called_with(projects_yaml)
475 self.open_port.assert_has_calls(_port_calls)
476
477+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
478 @patch.object(hooks, 'configure_https')
479 @patch.object(hooks, 'git_install_requested')
480- def test_config_changed(self, git_requested, conf_https):
481+ def test_config_changed(self, git_requested, conf_https, related):
482 git_requested.return_value = False
483 self.neutron_ready.return_value = True
484 self.openstack_upgrade_available.return_value = True
485@@ -196,11 +199,12 @@
486 'Cannot disable Router HA while ha enabled routers'
487 ' exist. Please remove any ha routers')
488
489+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
490 @patch.object(hooks, 'configure_https')
491 @patch.object(hooks, 'git_install_requested')
492 @patch.object(hooks, 'config_value_changed')
493 def test_config_changed_git(self, config_val_changed, git_requested,
494- configure_https):
495+ configure_https, related):
496 git_requested.return_value = True
497 self.neutron_ready.return_value = True
498 self.dvr_router_present.return_value = False
499@@ -243,7 +247,8 @@
500 self.assertTrue(_zmq_joined.called)
501 self.assertTrue(_id_cluster_joined.called)
502
503- def test_amqp_joined(self):
504+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
505+ def test_amqp_joined(self, related):
506 self._call_hook('amqp-relation-joined')
507 self.relation_set.assert_called_with(
508 username='neutron',
509@@ -251,16 +256,19 @@
510 relation_id=None
511 )
512
513- def test_amqp_changed(self):
514+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
515+ def test_amqp_changed(self, related):
516 self.CONFIGS.complete_contexts.return_value = ['amqp']
517 self._call_hook('amqp-relation-changed')
518 self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
519
520- def test_amqp_departed(self):
521+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
522+ def test_amqp_departed(self, related):
523 self._call_hook('amqp-relation-departed')
524 self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
525
526- def test_db_joined(self):
527+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
528+ def test_db_joined(self, related):
529 self.is_relation_made.return_value = False
530 self.unit_get.return_value = 'myhostname'
531 self._call_hook('shared-db-relation-joined')
532@@ -270,7 +278,8 @@
533 hostname='myhostname',
534 )
535
536- def test_db_joined_with_postgresql(self):
537+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
538+ def test_db_joined_with_postgresql(self, related):
539 self.is_relation_made.return_value = True
540
541 with self.assertRaises(Exception) as context:
542@@ -279,7 +288,8 @@
543 'Attempting to associate a mysql database when there '
544 'is already associated a postgresql one')
545
546- def test_postgresql_db_joined(self):
547+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
548+ def test_postgresql_db_joined(self, related):
549 self.unit_get.return_value = 'myhostname'
550 self.is_relation_made.return_value = False
551 self._call_hook('pgsql-db-relation-joined')
552@@ -287,7 +297,8 @@
553 database='neutron',
554 )
555
556- def test_postgresql_joined_with_db(self):
557+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
558+ def test_postgresql_joined_with_db(self, related):
559 self.is_relation_made.return_value = True
560
561 with self.assertRaises(Exception) as context:
562@@ -296,30 +307,35 @@
563 'Attempting to associate a postgresql database when'
564 ' there is already associated a mysql one')
565
566+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
567 @patch.object(hooks, 'conditional_neutron_migration')
568- def test_shared_db_changed(self, cond_neutron_mig):
569+ def test_shared_db_changed(self, cond_neutron_mig, related):
570 self.CONFIGS.complete_contexts.return_value = ['shared-db']
571 self._call_hook('shared-db-relation-changed')
572 self.assertTrue(self.CONFIGS.write_all.called)
573 cond_neutron_mig.assert_called_with()
574
575- def test_shared_db_changed_partial_ctxt(self):
576+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
577+ def test_shared_db_changed_partial_ctxt(self, related):
578 self.CONFIGS.complete_contexts.return_value = []
579 self._call_hook('shared-db-relation-changed')
580 self.assertFalse(self.CONFIGS.write_all.called)
581
582+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
583 @patch.object(hooks, 'conditional_neutron_migration')
584- def test_pgsql_db_changed(self, cond_neutron_mig):
585+ def test_pgsql_db_changed(self, cond_neutron_mig, related):
586 self._call_hook('pgsql-db-relation-changed')
587 self.assertTrue(self.CONFIGS.write.called)
588 cond_neutron_mig.assert_called_with()
589
590- def test_amqp_broken(self):
591+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=False)
592+ def test_amqp_broken(self, related):
593 self._call_hook('amqp-relation-broken')
594 self.assertTrue(self.CONFIGS.write_all.called)
595
596+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
597 @patch.object(hooks, 'canonical_url')
598- def test_identity_joined(self, _canonical_url):
599+ def test_identity_joined(self, _canonical_url, related):
600 _canonical_url.return_value = 'http://127.0.0.1'
601 self.api_port.return_value = '9696'
602 self.test_config.set('region', 'region1')
603@@ -337,13 +353,14 @@
604 relation_settings=_endpoints
605 )
606
607+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
608 @patch('charmhelpers.contrib.openstack.ip.service_name',
609 lambda *args: 'neutron-api')
610 @patch('charmhelpers.contrib.openstack.ip.unit_get')
611 @patch('charmhelpers.contrib.openstack.ip.is_clustered')
612 @patch('charmhelpers.contrib.openstack.ip.config')
613 def test_identity_changed_public_name(self, _config, _is_clustered,
614- _unit_get):
615+ _unit_get, related):
616 _unit_get.return_value = '127.0.0.1'
617 _is_clustered.return_value = False
618 _config.side_effect = self.test_config.get
619@@ -365,15 +382,17 @@
620 relation_settings=_endpoints
621 )
622
623- def test_identity_changed_partial_ctxt(self):
624+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
625+ def test_identity_changed_partial_ctxt(self, related):
626 self.CONFIGS.complete_contexts.return_value = []
627 _api_rel_joined = self.patch('neutron_api_relation_joined')
628 self.relation_ids.side_effect = self._fake_relids
629 self._call_hook('identity-service-relation-changed')
630 self.assertFalse(_api_rel_joined.called)
631
632+ @patch('charmhelpers.contrib.openstack.utils.related', return_value=True)
633 @patch.object(hooks, 'configure_https')
634- def test_identity_changed(self, conf_https):
635+ def test_identity_changed(self, conf_https, related):
636 self.CONFIGS.complete_contexts.return_value = ['identity-service']
637 _api_rel_joined = self.patch('neutron_api_relation_joined')
638 self.relation_ids.side_effect = self._fake_relids

Subscribers

People subscribed via source and target branches