Merge lp:~1chb1n/charm-helpers/amulet-relations-settled into lp:charm-helpers

Proposed by Ryan Beisner
Status: Work in progress
Proposed branch: lp:~1chb1n/charm-helpers/amulet-relations-settled
Merge into: lp:charm-helpers
Diff against target: 63 lines (+46/-0)
1 file modified
charmhelpers/contrib/amulet/utils.py (+46/-0)
To merge this branch: bzr merge lp:~1chb1n/charm-helpers/amulet-relations-settled
Reviewer Review Type Date Requested Status
Ryan Beisner (community) Disapprove
Corey Bryant (community) Approve
James Page Pending
Liam Young Pending
Review via email: mp+263724@code.launchpad.net

Description of the change

Add check_hooks_are_settled() to amulet/utils.py, based on openstack-mojo-specs.

Prior to this, openstack amulet tests relied on an arbitrary sleep time after deployment returned "complete," to wait for hooks to settle. That was racey, as the sleep time was not always enough during higher testing load.

This proposal uses the logic that openstack-mojo-specs has been using to address this challenge.

# Charm test MPs which depend on this landing:
https://code.launchpad.net/~1chb1n/charms/trusty/cinder-ceph/next-amulet-relation-settle/+merge/263716

To post a comment you must log in.
Revision history for this message
Ryan Beisner (1chb1n) wrote :
Revision history for this message
Ryan Beisner (1chb1n) wrote :
Revision history for this message
Corey Bryant (corey.bryant) wrote :

Looks good but I have a couple comments.

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Thanks, see replies, questions in line.

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

Responded inline

402. By Ryan Beisner

Plumb timeout all the way through;
Remove 2nd _remote_runs check;
Adjust _remote_run failure feedback.

Revision history for this message
Corey Bryant (corey.bryant) :
review: Approve
403. By Ryan Beisner

add 2nd _remote_runs check back in

Revision history for this message
Ryan Beisner (1chb1n) wrote :

FYI, with the 2nd remote run check removed, the test race condition re-appeared. So I added it back, which also keeps the approach in line with the same in openstack mojo specs.

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

Sounds fine to me then.

404. By Ryan Beisner

rebase

Revision history for this message
Ryan Beisner (1chb1n) wrote :

Abandoning this as the juju run twice approach appears to no longer be effective.

I disapprove. ;-)

review: Disapprove

Unmerged revisions

404. By Ryan Beisner

rebase

403. By Ryan Beisner

add 2nd _remote_runs check back in

402. By Ryan Beisner

Plumb timeout all the way through;
Remove 2nd _remote_runs check;
Adjust _remote_run failure feedback.

401. By Ryan Beisner

add juju_hooks_complete to amulet/utils.py (based on openstack-mojospecs)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'charmhelpers/contrib/amulet/utils.py'
2--- charmhelpers/contrib/amulet/utils.py 2015-06-29 13:19:46 +0000
3+++ charmhelpers/contrib/amulet/utils.py 2015-07-13 14:36:55 +0000
4@@ -22,9 +22,11 @@
5 import os
6 import re
7 import six
8+import subprocess
9 import sys
10 import time
11 import urlparse
12+import yaml
13
14
15 class AmuletUtils(object):
16@@ -531,3 +533,47 @@
17 return 'Dicts within list are not identical'
18
19 return None
20+
21+ def _remote_shell_check(self, unit, timeout='2m0s'):
22+ """Check that a juju run shell command succeeds on a juju unit."""
23+ cmd = ['juju', 'run', '--timeout', timeout,
24+ '--unit', unit, 'uname -a']
25+ fnull = open(os.devnull, 'w')
26+ return not subprocess.call(cmd, stdout=fnull, stderr=subprocess.STDOUT)
27+
28+ def _remote_runs(self, units, timeout='2m0s'):
29+ """Check that juju run succeeds against a list of units."""
30+ self.log.debug('Checking juju run command completion on '
31+ 'units: {}'.format(units))
32+ for unit in units:
33+ if not self._remote_shell_check(unit, timeout):
34+ msg = 'Juju run failed or timed out on {}'.format(unit)
35+ amulet.raise_status(amulet.FAIL, msg=msg)
36+ self.log.debug('Units completed juju run command checks OK.')
37+
38+ def get_juju_status(self):
39+ """Get juju status yaml data, return as dictionary."""
40+ self.log.debug('Getting juju status yaml data...')
41+ cmd = ['juju', 'status', '--format', 'yaml']
42+ status_file = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
43+ return yaml.load(status_file)
44+
45+ def get_juju_units(self):
46+ """Get a list of juju units from juju status output."""
47+ self.log.debug('Getting juju unit list from juju status data...')
48+ juju_status = self.get_juju_status()
49+ units = []
50+ services = [svc for svc in juju_status['services']]
51+ for svc in services:
52+ if 'units' in juju_status['services'][svc]:
53+ for unit in juju_status['services'][svc]['units']:
54+ units.append(unit)
55+ return units
56+
57+ def check_hooks_are_settled(self, timeout='2m0s'):
58+ """Use juju run (twice) against all units as an indicator that
59+ hooks are done. Raise exception if any unit fails or times out."""
60+ self.log.info('Checking that juju hooks appear to be complete...')
61+ juju_units = self.get_juju_units()
62+ self._remote_runs(juju_units, timeout)
63+ self._remote_runs(juju_units, timeout)

Subscribers

People subscribed via source and target branches