Merge lp:~marcoceppi/charm-tools/test-cfg into lp:charm-tools/1.2
- test-cfg
- Merge into 1.2
Status: | Rejected |
---|---|
Rejected by: | Marco Ceppi |
Proposed branch: | lp:~marcoceppi/charm-tools/test-cfg |
Merge into: | lp:charm-tools/1.2 |
Diff against target: |
269 lines (+50/-21) 5 files modified
charmtools/bundles.py (+0/-1) charmtools/generate.py (+0/-1) charmtools/test.py (+36/-10) charmtools/update.py (+2/-0) tests/test_juju_test.py (+12/-9) |
To merge this branch: | bzr merge lp:~marcoceppi/charm-tools/test-cfg |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
charmers | Pending | ||
Review via email: mp+200921@code.launchpad.net |
Commit message
Description of the change
Added support for substrate parsing in TestCfg
- 287. By Marco Ceppi
-
PEP8 Fixes
Charm Tester (charmtester) wrote : | # |
Charm Tester (charmtester) wrote : | # |
Please take a look.
Benjamin Saller (bcsaller) wrote : | # |
I like what you started here and put a few comments inline.
I took a stab at extending your work in another branch.
https:/
Look at this when you have time. I think its more testable than what you
have there (and more tested infact). If you like the model we can look
at cleaning it up a little more and merging. Let me know what you think.
https:/
File charmtools/test.py (right):
https:/
charmtools/
While this is a common pattern, its generally better to whitelist vars
that can be set in this way. Its possible now for the options to break
the tests by setting a name they sholdn't have on this class.
https:/
charmtools/
I think while we could validate the substrates its important to note
that what we produce from this parse is a set of rules, not a list of
substrates.
As we add substrates we want to automatically include those unless the
charm explicitly said it only tests on one substrate (which could happen
for EC2 specific charms for example) or that it explicitly doesn't run
on one (or more) substrates
Charm Tester (charmtester) wrote : | # |
I'll take a look at your proposal too, thanks for the review!
https:/
File charmtools/test.py (right):
https:/
charmtools/
I agree, think of self.substrates as more self.substrate_
as if it's inclusive or not and the values for inclusive or not. It
never has a comprehensive list of _all_ substrates at any one time, it's
more a parsing of the substrate option provided in the test_config.yaml
On 2014/01/09 07:52:40, benjamin.saller wrote:
> I think while we could validate the substrates its important to note
that what
> we produce from this parse is a set of rules, not a list of
substrates.
> As we add substrates we want to automatically include those unless the
charm
> explicitly said it only tests on one substrate (which could happen for
EC2
> specific charms for example) or that it explicitly doesn't run on one
(or more)
> substrates
Unmerged revisions
Preview Diff
1 | === modified file 'charmtools/bundles.py' | |||
2 | --- charmtools/bundles.py 2013-12-20 14:06:43 +0000 | |||
3 | +++ charmtools/bundles.py 2014-01-08 22:43:54 +0000 | |||
4 | @@ -2,7 +2,6 @@ | |||
5 | 2 | import yaml | 2 | import yaml |
6 | 3 | import glob | 3 | import glob |
7 | 4 | import json | 4 | import json |
8 | 5 | import requests | ||
9 | 6 | 5 | ||
10 | 7 | from linter import Linter | 6 | from linter import Linter |
11 | 8 | from charmworldlib import bundle as cw_bundle | 7 | from charmworldlib import bundle as cw_bundle |
12 | 9 | 8 | ||
13 | === modified file 'charmtools/generate.py' | |||
14 | --- charmtools/generate.py 2013-12-12 17:20:39 +0000 | |||
15 | +++ charmtools/generate.py 2014-01-08 22:43:54 +0000 | |||
16 | @@ -16,7 +16,6 @@ | |||
17 | 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | 17 | 17 | ||
19 | 18 | import os | 18 | import os |
20 | 19 | import sys | ||
21 | 20 | import shutil | 19 | import shutil |
22 | 21 | import argparse | 20 | import argparse |
23 | 22 | 21 | ||
24 | 23 | 22 | ||
25 | === modified file 'charmtools/test.py' | |||
26 | --- charmtools/test.py 2013-12-21 12:59:08 +0000 | |||
27 | +++ charmtools/test.py 2014-01-08 22:43:54 +0000 | |||
28 | @@ -3,7 +3,6 @@ | |||
29 | 3 | 3 | ||
30 | 4 | import os | 4 | import os |
31 | 5 | import sys | 5 | import sys |
32 | 6 | import uuid | ||
33 | 7 | import yaml | 6 | import yaml |
34 | 8 | import time | 7 | import time |
35 | 9 | import glob | 8 | import glob |
36 | @@ -12,7 +11,6 @@ | |||
37 | 12 | import argparse | 11 | import argparse |
38 | 13 | import subprocess | 12 | import subprocess |
39 | 14 | 13 | ||
40 | 15 | from tempfile import mkdtemp | ||
41 | 16 | from datetime import timedelta | 14 | from datetime import timedelta |
42 | 17 | from contextlib import contextmanager | 15 | from contextlib import contextmanager |
43 | 18 | 16 | ||
44 | @@ -44,6 +42,10 @@ | |||
45 | 44 | pass | 42 | pass |
46 | 45 | 43 | ||
47 | 46 | 44 | ||
48 | 45 | class SubstrateMismatch(Exception): | ||
49 | 46 | pass | ||
50 | 47 | |||
51 | 48 | |||
52 | 47 | class TimeoutError(Exception): | 49 | class TimeoutError(Exception): |
53 | 48 | def __init__(self, value="Timed Out"): | 50 | def __init__(self, value="Timed Out"): |
54 | 49 | self.value = value | 51 | self.value = value |
55 | @@ -114,7 +116,7 @@ | |||
56 | 114 | self.destroy(self.juju_env) | 116 | self.destroy(self.juju_env) |
57 | 115 | except DestroyUnreliable: | 117 | except DestroyUnreliable: |
58 | 116 | self.log.warn('Unable to destroy bootstrap, trying again') | 118 | self.log.warn('Unable to destroy bootstrap, trying again') |
60 | 117 | sleep(2) | 119 | time.sleep(2) |
61 | 118 | try: | 120 | try: |
62 | 119 | self.destroy(self.juju_env) | 121 | self.destroy(self.juju_env) |
63 | 120 | except: | 122 | except: |
64 | @@ -258,6 +260,7 @@ | |||
65 | 258 | try: | 260 | try: |
66 | 259 | with timeout(self.conductor.args.timeout): | 261 | with timeout(self.conductor.args.timeout): |
67 | 260 | output = subprocess.check_output(self.test, env=self.env) | 262 | output = subprocess.check_output(self.test, env=self.env) |
68 | 263 | self.log.debug(output) | ||
69 | 261 | except TimeoutError, e: | 264 | except TimeoutError, e: |
70 | 262 | self.log.debug('Killed by timeout after %s seconds', | 265 | self.log.debug('Killed by timeout after %s seconds', |
71 | 263 | self.conductor.args.timeout) | 266 | self.conductor.args.timeout) |
72 | @@ -279,7 +282,7 @@ | |||
73 | 279 | try: | 282 | try: |
74 | 280 | self.archive_logs() | 283 | self.archive_logs() |
75 | 281 | except OrchestraError, e: | 284 | except OrchestraError, e: |
77 | 282 | juju.log.error(e) | 285 | self.log.error(e) |
78 | 283 | 286 | ||
79 | 284 | if error: | 287 | if error: |
80 | 285 | raise error | 288 | raise error |
81 | @@ -293,7 +296,7 @@ | |||
82 | 293 | raise OrchestraError('Unable to query juju status') | 296 | raise OrchestraError('Unable to query juju status') |
83 | 294 | 297 | ||
84 | 295 | services = status['services'] | 298 | services = status['services'] |
86 | 296 | machines = status['machines'] | 299 | # machines = status['machines'] |
87 | 297 | 300 | ||
88 | 298 | if self.conductor.juju_version.major == 0: | 301 | if self.conductor.juju_version.major == 0: |
89 | 299 | logs.append('/var/lib/juju/units/./*/charm.log') | 302 | logs.append('/var/lib/juju/units/./*/charm.log') |
90 | @@ -402,9 +405,18 @@ | |||
91 | 402 | with open(config_file) as f: | 405 | with open(config_file) as f: |
92 | 403 | cfg = yaml.safe_load(f.read()) | 406 | cfg = yaml.safe_load(f.read()) |
93 | 404 | 407 | ||
97 | 405 | for key, val in cfg['options'].iteritems(): | 408 | if 'options' in cfg: |
98 | 406 | if key in self._keys: | 409 | for key, val in cfg['options'].iteritems(): |
99 | 407 | setattr(self, key, val) | 410 | if key in self._keys: |
100 | 411 | setattr(self, key, val) | ||
101 | 412 | if 'substrates' in cfg: | ||
102 | 413 | self.substrates = {} | ||
103 | 414 | if 'allow' in cfg: | ||
104 | 415 | self.substrates['inclusive'] = True | ||
105 | 416 | self.substrates['values'] = cfg['substrates']['allow'] | ||
106 | 417 | elif 'skip' in cfg: | ||
107 | 418 | self.substrates['inclusive'] = False | ||
108 | 419 | self.substrates['values'] = cfg['substrates']['skip'] | ||
109 | 408 | 420 | ||
110 | 409 | 421 | ||
111 | 410 | def get_juju_version(): | 422 | def get_juju_version(): |
112 | @@ -564,8 +576,9 @@ | |||
113 | 564 | logger.info('Starting test run on %s using Juju %s' | 576 | logger.info('Starting test run on %s using Juju %s' |
114 | 565 | % (args.juju_env, get_juju_version())) | 577 | % (args.juju_env, get_juju_version())) |
115 | 566 | logger.debug('Loading configuration options from testplan YAML') | 578 | logger.debug('Loading configuration options from testplan YAML') |
118 | 567 | test_plans = glob.glob(os.path.join(os.getcwd(), 'tests', 'testplan.y*ml')) | 579 | test_plans = glob.glob(os.path.join(os.getcwd(), 'tests', |
119 | 568 | test_plan = test_plan[0] if test_plans else None | 580 | 'test_config.y*ml')) |
120 | 581 | test_plan = test_plans[0] if test_plans else None | ||
121 | 569 | if test_plan: | 582 | if test_plan: |
122 | 570 | cfg = TestCfg(test_plan) | 583 | cfg = TestCfg(test_plan) |
123 | 571 | for key, val in args.iteritems(): | 584 | for key, val in args.iteritems(): |
124 | @@ -577,10 +590,23 @@ | |||
125 | 577 | logger.debug('Creating a new Conductor') | 590 | logger.debug('Creating a new Conductor') |
126 | 578 | try: | 591 | try: |
127 | 579 | tester = Conductor(args) | 592 | tester = Conductor(args) |
128 | 593 | env_yaml = tester.get_environment(cfg.juju_env) | ||
129 | 594 | if 'substrates' in cfg: | ||
130 | 595 | # We have substrate configuration data. | ||
131 | 596 | substrate_match = env_yaml['type'] in cfg.substrates['values'] | ||
132 | 597 | if cfg.substrates['inclusive'] and not substrate_match: | ||
133 | 598 | pass | ||
134 | 599 | if not cfg.substrates['inclusive'] and substrate_match: | ||
135 | 600 | raise Exception('%s is not in allowed substrates: %s' % | ||
136 | 601 | (env_yaml['type'], | ||
137 | 602 | cfg.substrates['values'].join(', '))) | ||
138 | 580 | errors, failures, passes = tester.run() | 603 | errors, failures, passes = tester.run() |
139 | 581 | except NoTests: | 604 | except NoTests: |
140 | 582 | logger.critical('No tests were found') | 605 | logger.critical('No tests were found') |
141 | 583 | sys.exit(1) | 606 | sys.exit(1) |
142 | 607 | except Exception as e: | ||
143 | 608 | logger.critical(str(e)) | ||
144 | 609 | sys.exit(1) | ||
145 | 584 | except: | 610 | except: |
146 | 585 | raise | 611 | raise |
147 | 586 | 612 | ||
148 | 587 | 613 | ||
149 | === modified file 'charmtools/update.py' | |||
150 | --- charmtools/update.py 2013-12-16 16:12:29 +0000 | |||
151 | +++ charmtools/update.py 2014-01-08 22:43:54 +0000 | |||
152 | @@ -34,6 +34,7 @@ | |||
153 | 34 | 34 | ||
154 | 35 | return parser | 35 | return parser |
155 | 36 | 36 | ||
156 | 37 | |||
157 | 37 | def update(charm_dir, fix=False): | 38 | def update(charm_dir, fix=False): |
158 | 38 | mr = Mr(charm_dir) | 39 | mr = Mr(charm_dir) |
159 | 39 | for charm in charms.remote(): | 40 | for charm in charms.remote(): |
160 | @@ -48,6 +49,7 @@ | |||
161 | 48 | except Exception as e: | 49 | except Exception as e: |
162 | 49 | raise Exception(".mrconfig not saved: %s" % e.strerror) | 50 | raise Exception(".mrconfig not saved: %s" % e.strerror) |
163 | 50 | 51 | ||
164 | 52 | |||
165 | 51 | def main(): | 53 | def main(): |
166 | 52 | parser = setup_parser() | 54 | parser = setup_parser() |
167 | 53 | args = parser.parse_args() | 55 | args = parser.parse_args() |
168 | 54 | 56 | ||
169 | === modified file 'tests/test_juju_test.py' | |||
170 | --- tests/test_juju_test.py 2013-12-20 12:33:21 +0000 | |||
171 | +++ tests/test_juju_test.py 2014-01-08 22:43:54 +0000 | |||
172 | @@ -30,13 +30,16 @@ | |||
173 | 30 | 30 | ||
174 | 31 | PARSED_ENVIRONMENTS_YAML = yaml.safe_load(RAW_ENVIRONMENTS_YAML) | 31 | PARSED_ENVIRONMENTS_YAML = yaml.safe_load(RAW_ENVIRONMENTS_YAML) |
175 | 32 | 32 | ||
176 | 33 | |||
177 | 33 | class Arguments(object): | 34 | class Arguments(object): |
178 | 34 | def __init__(self, **kwargs): | 35 | def __init__(self, **kwargs): |
179 | 35 | for key, value in kwargs.items(): | 36 | for key, value in kwargs.items(): |
180 | 36 | setattr(self, key, value) | 37 | setattr(self, key, value) |
181 | 38 | |||
182 | 37 | def __getattr__(self, name): | 39 | def __getattr__(self, name): |
183 | 38 | return None | 40 | return None |
184 | 39 | 41 | ||
185 | 42 | |||
186 | 40 | class JujuTestPluginTest(unittest.TestCase): | 43 | class JujuTestPluginTest(unittest.TestCase): |
187 | 41 | @patch('subprocess.check_output') | 44 | @patch('subprocess.check_output') |
188 | 42 | def test_get_gojuju_version(self, mock_check_output): | 45 | def test_get_gojuju_version(self, mock_check_output): |
189 | @@ -77,7 +80,7 @@ | |||
190 | 77 | self.assertEqual(100, juju_test.convert_to_timedelta('100s')) | 80 | self.assertEqual(100, juju_test.convert_to_timedelta('100s')) |
191 | 78 | self.assertEqual(100, juju_test.convert_to_timedelta(100)) | 81 | self.assertEqual(100, juju_test.convert_to_timedelta(100)) |
192 | 79 | self.assertEqual(60, juju_test.convert_to_timedelta('1m')) | 82 | self.assertEqual(60, juju_test.convert_to_timedelta('1m')) |
194 | 80 | self.assertEqual(60*60, juju_test.convert_to_timedelta('1h')) | 83 | self.assertEqual(60 * 60, juju_test.convert_to_timedelta('1h')) |
195 | 81 | 84 | ||
196 | 82 | @patch('glob.glob') | 85 | @patch('glob.glob') |
197 | 83 | @patch('os.path.isfile') | 86 | @patch('os.path.isfile') |
198 | @@ -89,7 +92,7 @@ | |||
199 | 89 | mock_isfile.side_effect = files_exist | 92 | mock_isfile.side_effect = files_exist |
200 | 90 | mock_glob.return_value = tests_directory | 93 | mock_glob.return_value = tests_directory |
201 | 91 | 94 | ||
203 | 92 | args = Arguments(tests = 'dummy') | 95 | args = Arguments(tests='dummy') |
204 | 93 | c = juju_test.Conductor(args) | 96 | c = juju_test.Conductor(args) |
205 | 94 | results = c.find_tests() | 97 | results = c.find_tests() |
206 | 95 | 98 | ||
207 | @@ -100,7 +103,7 @@ | |||
208 | 100 | def test_conductor_find_tests_fails(self, mock_glob): | 103 | def test_conductor_find_tests_fails(self, mock_glob): |
209 | 101 | mock_glob.return_value = [] | 104 | mock_glob.return_value = [] |
210 | 102 | 105 | ||
212 | 103 | args = Arguments(tests = 'dummy') | 106 | args = Arguments(tests='dummy') |
213 | 104 | c = juju_test.Conductor(args) | 107 | c = juju_test.Conductor(args) |
214 | 105 | results = c.find_tests() | 108 | results = c.find_tests() |
215 | 106 | 109 | ||
216 | @@ -126,7 +129,7 @@ | |||
217 | 126 | 129 | ||
218 | 127 | mcheck_output.side_effect = [yml_output, Exception('not bootstrapped')] | 130 | mcheck_output.side_effect = [yml_output, Exception('not bootstrapped')] |
219 | 128 | juju_env = 'test' | 131 | juju_env = 'test' |
221 | 129 | args = Arguments(tests = 'dummy') | 132 | args = Arguments(tests='dummy') |
222 | 130 | c = juju_test.Conductor(args) | 133 | c = juju_test.Conductor(args) |
223 | 131 | results = c.status(juju_env) | 134 | results = c.status(juju_env) |
224 | 132 | 135 | ||
225 | @@ -193,7 +196,7 @@ | |||
226 | 193 | 196 | ||
227 | 194 | @patch('subprocess.check_call') | 197 | @patch('subprocess.check_call') |
228 | 195 | def test_conductor_destroy(self, mock_check_call): | 198 | def test_conductor_destroy(self, mock_check_call): |
230 | 196 | args = Arguments(tests = 'dummy') | 199 | args = Arguments(tests='dummy') |
231 | 197 | c = juju_test.Conductor(args) | 200 | c = juju_test.Conductor(args) |
232 | 198 | c.juju_version = juju_test.JujuVersion(major=1, minor=1, patch=1) | 201 | c.juju_version = juju_test.JujuVersion(major=1, minor=1, patch=1) |
233 | 199 | good_env = 'valid' | 202 | good_env = 'valid' |
234 | @@ -216,7 +219,7 @@ | |||
235 | 216 | 219 | ||
236 | 217 | bad_env = 'invalid' | 220 | bad_env = 'invalid' |
237 | 218 | 221 | ||
239 | 219 | args = Arguments(tests = 'dummy') | 222 | args = Arguments(tests='dummy') |
240 | 220 | c = juju_test.Conductor(args) | 223 | c = juju_test.Conductor(args) |
241 | 221 | c.juju_version = juju_test.JujuVersion(major=1, minor=8, patch=0) | 224 | c.juju_version = juju_test.JujuVersion(major=1, minor=8, patch=0) |
242 | 222 | self.assertRaises(juju_test.DestroyUnreliable, c.destroy, bad_env) | 225 | self.assertRaises(juju_test.DestroyUnreliable, c.destroy, bad_env) |
243 | @@ -448,7 +451,7 @@ | |||
244 | 448 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, | 451 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, |
245 | 449 | juju_test.TEST_TIMEOUT)) | 452 | juju_test.TEST_TIMEOUT)) |
246 | 450 | 453 | ||
248 | 451 | o.conductor.args.on_timeout='skip' | 454 | o.conductor.args.on_timeout = 'skip' |
249 | 452 | o.log.status.reset_mock() | 455 | o.log.status.reset_mock() |
250 | 453 | o.print_status(124) | 456 | o.print_status(124) |
251 | 454 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, | 457 | o.log.status.assert_called_with('%s (%s)' % (juju_test.TEST_FAIL, |
252 | @@ -583,7 +586,7 @@ | |||
253 | 583 | goyml_parsed = yaml.safe_load(goyml_output) | 586 | goyml_parsed = yaml.safe_load(goyml_output) |
254 | 584 | mstatus.return_value = goyml_parsed | 587 | mstatus.return_value = goyml_parsed |
255 | 585 | 588 | ||
257 | 586 | juju_env='testing' | 589 | juju_env = 'testing' |
258 | 587 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') | 590 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') |
259 | 588 | c = juju_test.Conductor(args) | 591 | c = juju_test.Conductor(args) |
260 | 589 | c.juju_version = juju_test.JujuVersion(major=1, minor=10, patch=0) | 592 | c.juju_version = juju_test.JujuVersion(major=1, minor=10, patch=0) |
261 | @@ -623,7 +626,7 @@ | |||
262 | 623 | pyyml_parsed = yaml.safe_load(pyyml_output) | 626 | pyyml_parsed = yaml.safe_load(pyyml_output) |
263 | 624 | mstatus.return_value = pyyml_parsed | 627 | mstatus.return_value = pyyml_parsed |
264 | 625 | 628 | ||
266 | 626 | juju_env='testing' | 629 | juju_env = 'testing' |
267 | 627 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') | 630 | args = Arguments(tests='dummy', juju_env=juju_env, logdir='/tmp') |
268 | 628 | c = juju_test.Conductor(args) | 631 | c = juju_test.Conductor(args) |
269 | 629 | c.juju_version = juju_test.JujuVersion(major=0, minor=7, patch=0) | 632 | c.juju_version = juju_test.JujuVersion(major=0, minor=7, patch=0) |
Reviewers: mp+200921_ code.launchpad. net,
Message:
Please take a look.
Description:
Added support for substrate parsing in TestCfg
https:/ /code.launchpad .net/~marcocepp i/charm- tools/test- cfg/+merge/ 200921
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/49160046/
Affected files (+52, -21 lines): bundles. py generate. py update. py juju_test. py
A [revision details]
M charmtools/
M charmtools/
M charmtools/test.py
M charmtools/
M tests/test_
Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: <email address hidden>
+New revision: <email address hidden>
Index: charmtools/ bundles. py bundles. py' bundles. py 2013-12-20 14:06:43 +0000 bundles. py 2014-01-08 22:43:34 +0000
=== modified file 'charmtools/
--- charmtools/
+++ charmtools/
@@ -2,7 +2,6 @@
import yaml
import glob
import json
-import requests
from linter import Linter
from charmworldlib import bundle as cw_bundle
Index: charmtools/ generate. py generate. py' generate. py 2013-12-12 17:20:39 +0000 generate. py 2014-01-08 22:43:34 +0000 www.gnu. org/licenses/>.
=== modified file 'charmtools/
--- charmtools/
+++ charmtools/
@@ -16,7 +16,6 @@
# along with this program. If not, see <http://
import os
-import sys
import shutil
import argparse
Index: charmtools/test.py test.py'
=== modified file 'charmtools/
--- charmtools/test.py 2013-12-21 12:59:08 +0000
+++ charmtools/test.py 2014-01-08 22:43:34 +0000
@@ -3,7 +3,6 @@
import os
import sys
-import uuid
import yaml
import time
import glob
@@ -12,7 +11,6 @@
import argparse
import subprocess
-from tempfile import mkdtemp
from datetime import timedelta
from contextlib import contextmanager
@@ -44,6 +42,10 @@
pass
+class SubstrateMismat ch(Exception) : Exception) :
self. value = value
self. destroy( self.juju_ env)
except DestroyUnreliable:
self. log.warn( 'Unable to destroy bootstrap, trying again')
try:
self.destroy( self.juju_ env)
except: self.conductor. args.timeout) :
output = subprocess. check_output( self.test, env=self.env) debug(output)
self.log. debug(' Killed by timeout after %s seconds',
self.conductor .args.timeout)
self. archive_ logs()
except OrchestraError, e:
+ pass
+
+
class TimeoutError(
def __init__(self, value="Timed Out"):
@@ -114,7 +116,7 @@
- sleep(2)
+ time.sleep(2)
@@ -258,6 +260,7 @@
try:
with timeout(
+ self.log.
except TimeoutError, e:
@@ -279,7 +282,7 @@
try:
- juju.log.error(e)
+ self.log.error(e)
if error: 'Unable to query juju status')
raise error
@@ -293,7 +296,7 @@
raise OrchestraError(
services = status['services']
- machines = status['machines']
+...