Merge lp:~ericsnowcurrently/landscape-charm/fix-1610413-collect-inner-model into lp:~landscape/landscape-charm/tools
- fix-1610413-collect-inner-model
- Merge into tools
Proposed by
Eric Snow
Status: | Rejected |
---|---|
Rejected by: | Eric Snow |
Proposed branch: | lp:~ericsnowcurrently/landscape-charm/fix-1610413-collect-inner-model |
Merge into: | lp:~landscape/landscape-charm/tools |
Prerequisite: | lp:~ericsnowcurrently/landscape-charm/tools-unit-tests-for-script |
Diff against target: |
818 lines (+351/-140) (has conflicts) 2 files modified
collect-logs (+108/-53) test_collect-logs.py (+243/-87) Text conflict in collect-logs |
To merge this branch: | bzr merge lp:~ericsnowcurrently/landscape-charm/fix-1610413-collect-inner-model |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Landscape | Pending | ||
Review via email: mp+303086@code.launchpad.net |
This proposal supersedes a proposal from 2016-08-17.
Commit message
Description of the change
Make collect-logs work with Juju 2.
Testing instructions:
1. Deploy landscape
2. install juju-2.0 on the landscape-server/0 unit
3. enable the "juju-2.0" feature flag
4. autopilot
5. run collect-logs
To post a comment you must log in.
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'collect-logs' |
2 | --- collect-logs 2016-08-17 14:14:30 +0000 |
3 | +++ collect-logs 2016-08-17 14:14:30 +0000 |
4 | @@ -2,6 +2,7 @@ |
5 | |
6 | from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter |
7 | import errno |
8 | +import functools |
9 | import logging |
10 | import multiprocessing |
11 | import os |
12 | @@ -25,16 +26,24 @@ |
13 | "/var/lib/juju/containers/juju-*-lxc-template"] |
14 | LANDSCAPE_JUJU_HOME = "/var/lib/landscape/juju-homes" |
15 | |
16 | - |
17 | -def juju_status(): |
18 | +JUJU1 = "juju" |
19 | +# XXX This is going to break once juju-2.1 happens. |
20 | +# See https://bugs.launchpad.net/juju-core/+bug/1613864. |
21 | +JUJU2 = "juju-2.0" |
22 | +JUJU = JUJU1 |
23 | + |
24 | + |
25 | +def juju_status(juju): |
26 | """Return a juju status structure.""" |
27 | - cmd = ["juju", "status", "--format=yaml"] |
28 | + cmd = [juju, "status", "--format=yaml"] |
29 | output = check_output(cmd).decode("utf-8").strip() |
30 | return yaml.load(output) |
31 | |
32 | |
33 | -def get_units(status=juju_status()): |
34 | +def get_units(juju, status=None): |
35 | """Return a list with all units.""" |
36 | + if status is None: |
37 | + status = juju_status(juju) |
38 | units = [] |
39 | if "services" in status: |
40 | applications = status["services"] |
41 | @@ -52,12 +61,12 @@ |
42 | return units |
43 | |
44 | |
45 | -def _create_ps_output_file(unit): |
46 | +def _create_ps_output_file(juju, unit): |
47 | """List running processes and redirect them to a file.""" |
48 | ps_cmd = "ps fauxww | sudo tee /var/log/ps-fauxww.txt" |
49 | try: |
50 | log.info("Collecting ps output on unit {}".format(unit)) |
51 | - check_output(["juju", "ssh", unit, ps_cmd], stderr=STDOUT) |
52 | + check_output([juju, "ssh", unit, ps_cmd], stderr=STDOUT) |
53 | except CalledProcessError as e: |
54 | log.warning( |
55 | "Failed to collect running processes on unit {}".format(unit)) |
56 | @@ -65,7 +74,7 @@ |
57 | log.warning(e.returncode) |
58 | |
59 | |
60 | -def _create_log_tarball(unit): |
61 | +def _create_log_tarball(juju, unit): |
62 | exclude = " ".join(["--exclude=%s" % x for x in EXCLUDED]) |
63 | logs = "$(sudo sh -c \"ls -1d %s 2>/dev/null\")" % " ".join(LOGS) |
64 | # note, tar commands can fail since we are backing up log files |
65 | @@ -80,7 +89,7 @@ |
66 | tar_cmd, exclude, logsuffix, logs) |
67 | try: |
68 | log.info("Creating tarball on unit {}".format(unit)) |
69 | - check_output(["juju", "ssh", unit, cmd], stderr=STDOUT) |
70 | + check_output([juju, "ssh", unit, cmd], stderr=STDOUT) |
71 | except CalledProcessError as e: |
72 | log.warning( |
73 | "Failed to create remote log tarball on unit {}".format(unit)) |
74 | @@ -88,7 +97,7 @@ |
75 | log.warning(e.returncode) |
76 | |
77 | |
78 | -def collect_logs(): |
79 | +def collect_logs(juju=JUJU): |
80 | """ |
81 | Remotely, on each unit, create a tarball with the requested log files |
82 | or directories, if they exist. If a requested log does not exist on a |
83 | @@ -96,19 +105,19 @@ |
84 | After each tarball is created, it's downloaded to the current directory |
85 | and expanded, and the tarball is then deleted. |
86 | """ |
87 | - units = get_units() |
88 | + units = get_units(juju) |
89 | # include bootstrap |
90 | units.append("0") |
91 | |
92 | log.info("Collecting running processes for all units including bootstrap") |
93 | - map(_create_ps_output_file, units) |
94 | + map((lambda u: _create_ps_output_file(juju, u)), units) |
95 | |
96 | log.info("Creating remote tarball in parallel for units %s" % ( |
97 | ",".join(units))) |
98 | - map(_create_log_tarball, units) |
99 | + map((lambda u: _create_log_tarball(juju, u)), units) |
100 | log.info("Downloading logs from units") |
101 | |
102 | - _mp_map(download_log_from_unit, units) |
103 | + _mp_map(functools.partial(download_log_from_unit, juju), units) |
104 | |
105 | |
106 | def _mp_map(func, args): |
107 | @@ -129,6 +138,7 @@ |
108 | return units[0] |
109 | |
110 | |
111 | +<<<<<<< TREE |
112 | def disable_ssh_proxy(landscape_unit): |
113 | """ |
114 | Workaround for #1607076: disable the proxy-ssh juju environment setting |
115 | @@ -148,77 +158,117 @@ |
116 | log.warning("Error was:\n{}".format(e.output)) |
117 | |
118 | def collect_inner_logs(): |
119 | +======= |
120 | +def find_inner_juju(juju, landscape_unit): |
121 | + """Return the juju dir and binary path, if any.""" |
122 | + # Identify the most recent juju "home" that landscape is using. |
123 | + cmd = "sudo ls -rt {}/".format(LANDSCAPE_JUJU_HOME) |
124 | + try: |
125 | + output = check_output(["juju", "ssh", landscape_unit, cmd]).strip() |
126 | + except CalledProcessError: |
127 | + return None, None |
128 | + if output.startswith("sudo: "): |
129 | + _, _, output = output.partition("\r\n") |
130 | + models = [m for m in output.split() if m and m.isdigit()] |
131 | + if not models: |
132 | + return None, None |
133 | + model = models[-1] |
134 | + juju_dir = os.path.join(LANDSCAPE_JUJU_HOME, model) |
135 | + |
136 | + # Try Juju 2. |
137 | + juju_env = "JUJU_DATA={}".format(juju_dir) |
138 | + cmd = "sudo {} {} status".format(juju_env, JUJU2) |
139 | + if call([juju, "ssh", landscape_unit, cmd]) == 0: |
140 | + log.info("using Juju 2 for inner model") |
141 | + return juju_env, JUJU2 |
142 | + |
143 | + # Try Juju 1. |
144 | + juju_env = "JUJU_HOME={}".format(juju_dir) |
145 | + cmd = "sudo {} {} status".format(juju_env, JUJU1) |
146 | + if call([juju, "ssh", landscape_unit, cmd]) == 0: |
147 | + log.info("using Juju 1 for inner model") |
148 | + return juju_env, JUJU1 |
149 | + |
150 | + # We didn't find an inner model. |
151 | + return None, None |
152 | + |
153 | + |
154 | +def collect_inner_logs(juju=JUJU): |
155 | +>>>>>>> MERGE-SOURCE |
156 | """Collect logs from an inner landscape[-server]/0 unit.""" |
157 | - units = get_units() |
158 | + units = get_units(juju) |
159 | landscape_unit = get_landscape_unit(units) |
160 | if not landscape_unit: |
161 | log.info("No landscape[-server]/N found, skipping") |
162 | return |
163 | - log.info("Found landscape unit %s" % landscape_unit) |
164 | + log.info("Found landscape unit {}".format(landscape_unit)) |
165 | |
166 | - # Make sure that there *is* an inner model. |
167 | - poke_inner_env = ( |
168 | - "sudo JUJU_HOME=%s/`sudo ls -rt %s/ | tail -1` juju status" % |
169 | - (LANDSCAPE_JUJU_HOME, LANDSCAPE_JUJU_HOME)) |
170 | - try: |
171 | - check_output(["juju", "ssh", landscape_unit, poke_inner_env]) |
172 | - except CalledProcessError: |
173 | - log.info("No active inner environment found on %s, skipping" % |
174 | - landscape_unit) |
175 | + # Look up the inner model. |
176 | + juju_env, inner_juju = find_inner_juju(juju, landscape_unit) |
177 | + if inner_juju is None: |
178 | + log.info(("No active inner environment found on {}, skipping" |
179 | + ).format(landscape_unit)) |
180 | return |
181 | <<<<<<< TREE |
182 | disable_ssh_proxy(landscape_unit) |
183 | + call(["juju", "scp", PRG, "%s:%s" % (landscape_unit, collect_logs)]) |
184 | + call(["juju", "ssh", landscape_unit, "sudo rm -rf /tmp/inner-logs.tar.*"]) |
185 | + log.info("Collecting Logs on inner environment") |
186 | + check_call( |
187 | + ["juju", "ssh", landscape_unit, "sudo -u landscape %s" % collect_run]) |
188 | ======= |
189 | |
190 | # Prepare to get the logs from the inner model. |
191 | collect_logs = "/tmp/collect-logs" |
192 | ->>>>>>> MERGE-SOURCE |
193 | - call(["juju", "scp", PRG, "%s:%s" % (landscape_unit, collect_logs)]) |
194 | - call(["juju", "ssh", landscape_unit, "sudo rm -rf /tmp/inner-logs.tar.*"]) |
195 | + tarball = "/tmp/inner-logs.tar.gz" |
196 | + check_call([juju, "scp", |
197 | + PRG, |
198 | + "{}:{}".format(landscape_unit, collect_logs)]) |
199 | + check_call([juju, "ssh", landscape_unit, |
200 | + "sudo rm -rf /tmp/inner-logs.tar.*"]) |
201 | |
202 | # Collect the logs for the inner model. |
203 | - log.info("Collecting Logs on inner environment") |
204 | - collect_run = ( |
205 | - "JUJU_HOME=%s/`sudo ls -rt %s/ | tail -1`" |
206 | - " %s /tmp/inner-logs.tar.gz" % ( |
207 | - LANDSCAPE_JUJU_HOME, LANDSCAPE_JUJU_HOME, collect_logs)) |
208 | - check_call(["juju", "ssh", |
209 | + log.info("Collecting logs on inner environment") |
210 | + cmd = ("{} {} --inner --juju {} {}" |
211 | + ).format(juju_env, collect_logs, inner_juju, tarball) |
212 | + check_call([juju, "ssh", |
213 | landscape_unit, |
214 | - "sudo -u landscape %s" % collect_run, |
215 | + "sudo -u landscape {}".format(cmd), |
216 | ]) |
217 | |
218 | # Copy the inner logs into a local directory. |
219 | +>>>>>>> MERGE-SOURCE |
220 | log.info("Copying inner environment back") |
221 | + source = "{}:{}".format(landscape_unit, tarball) |
222 | + cwd = os.getcwd() |
223 | + target = os.path.join(cwd, os.path.basename(tarball)) |
224 | try: |
225 | - check_call(["juju", "scp", |
226 | - "%s:/tmp/inner-logs.tar.gz" % landscape_unit, |
227 | - ".", |
228 | - ]) |
229 | - cwd = os.getcwd() |
230 | + check_call([juju, "scp", source, target]) |
231 | + |
232 | inner_dir = "landscape-0-inner-logs" |
233 | os.mkdir(inner_dir) |
234 | os.chdir(inner_dir) |
235 | try: |
236 | - check_call(["tar", "-zxf", "%s/inner-logs.tar.gz" % cwd]) |
237 | + check_call(["tar", "-zxf", target]) |
238 | finally: |
239 | os.chdir(cwd) |
240 | finally: |
241 | try: |
242 | - os.remove("inner-logs.tar.gz") |
243 | + os.remove(target) |
244 | except OSError as e: |
245 | if e.errno != errno.ENOENT: |
246 | log.warning( |
247 | - "failed to remove inner logs tarball: {}".format(err)) |
248 | - |
249 | - |
250 | -def download_log_from_unit(unit): |
251 | + "failed to remove inner logs tarball: {}".format(e)) |
252 | + |
253 | + |
254 | +def download_log_from_unit(juju, unit): |
255 | log.info("Downloading tarball from unit %s" % unit) |
256 | unit_filename = unit.replace("/", "-") |
257 | if unit == "0": |
258 | unit_filename = "bootstrap" |
259 | try: |
260 | remote_filename = "logs_%s.tar.gz" % unit_filename |
261 | - call(["juju", "scp", "%s:/tmp/%s" % (unit, remote_filename), "."]) |
262 | + call([juju, "scp", "%s:/tmp/%s" % (unit, remote_filename), "."]) |
263 | os.mkdir(unit_filename) |
264 | call(["tar", "-C", unit_filename, "-xzf", remote_filename]) |
265 | os.unlink(remote_filename) |
266 | @@ -267,13 +317,17 @@ |
267 | "inner autopilot cloud is detected, include that.") |
268 | parser = ArgumentParser(description=description, |
269 | formatter_class=ArgumentDefaultsHelpFormatter) |
270 | + parser.add_argument("--inner", action="store_true", default=False, |
271 | + help="Collect logs for an inner model.") |
272 | + parser.add_argument("--juju", default=JUJU, |
273 | + help="The Juju binary to use.") |
274 | parser.add_argument("tarfile", help="Full path to tarfile to create.") |
275 | parser.add_argument("extrafiles", help="Optional full path to extra " |
276 | "logfiles to include, space separated", nargs="*") |
277 | return parser |
278 | |
279 | |
280 | -def main(tarfile, extrafiles): |
281 | +def main(tarfile, extrafiles, juju=JUJU, inner=False): |
282 | # we need the absolute path because we will be changing |
283 | # the cwd |
284 | tmpdir = mkdtemp() |
285 | @@ -281,11 +335,12 @@ |
286 | # logs are collected inside a temporary directory |
287 | os.chdir(tmpdir) |
288 | try: |
289 | - collect_logs() |
290 | - try: |
291 | - collect_inner_logs() |
292 | - except: |
293 | - log.warning("Collecting inner logs failed, continuing") |
294 | + collect_logs(juju) |
295 | + if not inner: |
296 | + try: |
297 | + collect_inner_logs(juju) |
298 | + except: |
299 | + log.warning("Collecting inner logs failed, continuing") |
300 | # we create the final tarball outside of tmpdir to we can |
301 | # add the extrafiles to the tarball root |
302 | os.chdir(cwd) |
303 | @@ -302,4 +357,4 @@ |
304 | parser = get_option_parser() |
305 | args = parser.parse_args(sys.argv[1:]) |
306 | tarfile = os.path.abspath(args.tarfile) |
307 | - main(tarfile, args.extrafiles) |
308 | + main(tarfile, args.extrafiles, args.juju, args.inner) |
309 | |
310 | === modified file 'test_collect-logs.py' |
311 | --- test_collect-logs.py 2016-08-17 14:14:30 +0000 |
312 | +++ test_collect-logs.py 2016-08-17 14:14:30 +0000 |
313 | @@ -92,22 +92,35 @@ |
314 | |
315 | script.main(tarfile, extrafiles) |
316 | |
317 | - script.collect_logs.assert_called_once_with() |
318 | - script.collect_inner_logs.assert_called_once_with() |
319 | + script.collect_logs.assert_called_once_with("juju") |
320 | + script.collect_inner_logs.assert_called_once_with("juju") |
321 | script.bundle_logs.assert_called_once_with( |
322 | self.tempdir, tarfile, extrafiles) |
323 | self.assertFalse(os.path.exists(self.tempdir)) |
324 | |
325 | def test_in_correct_directories(self): |
326 | - script.collect_logs.side_effect = lambda: self.assert_cwd(self.tempdir) |
327 | + script.collect_logs.side_effect = ( |
328 | + lambda _: self.assert_cwd(self.tempdir)) |
329 | script.collect_inner_logs.side_effect = ( |
330 | - lambda: self.assert_cwd(self.tempdir)) |
331 | + lambda _: self.assert_cwd(self.tempdir)) |
332 | script.bundle_logs.side_effect = lambda *a: self.assert_cwd(self.cwd) |
333 | tarfile = "/tmp/logs.tgz" |
334 | extrafiles = ["spam.py"] |
335 | |
336 | script.main(tarfile, extrafiles) |
337 | |
338 | + def test_inner(self): |
339 | + tarfile = "/tmp/logs.tgz" |
340 | + extrafiles = ["spam.py"] |
341 | + |
342 | + script.main(tarfile, extrafiles, inner=True) |
343 | + |
344 | + script.collect_logs.assert_called_once_with("juju") |
345 | + script.collect_inner_logs.assert_not_called() |
346 | + script.bundle_logs.assert_called_once_with( |
347 | + self.tempdir, tarfile, extrafiles) |
348 | + self.assertFalse(os.path.exists(self.tempdir)) |
349 | + |
350 | def test_cleanup(self): |
351 | tarfile = "/tmp/logs.tgz" |
352 | extrafiles = ["spam.py"] |
353 | @@ -124,7 +137,7 @@ |
354 | with self.assertRaises(FakeError): |
355 | script.main(tarfile, extrafiles) |
356 | |
357 | - script.collect_logs.assert_called_once_with() |
358 | + script.collect_logs.assert_called_once_with("juju") |
359 | script.collect_inner_logs.assert_not_called() |
360 | script.bundle_logs.assert_not_called() |
361 | self.assertFalse(os.path.exists(self.tempdir)) |
362 | @@ -136,8 +149,8 @@ |
363 | |
364 | script.main(tarfile, extrafiles) |
365 | |
366 | - script.collect_logs.assert_called_once_with() |
367 | - script.collect_inner_logs.assert_called_once_with() |
368 | + script.collect_logs.assert_called_once_with("juju") |
369 | + script.collect_inner_logs.assert_called_once_with("juju") |
370 | script.bundle_logs.assert_called_once_with( |
371 | self.tempdir, tarfile, extrafiles) |
372 | self.assertFalse(os.path.exists(self.tempdir)) |
373 | @@ -150,8 +163,8 @@ |
374 | with self.assertRaises(FakeError): |
375 | script.main(tarfile, extrafiles) |
376 | |
377 | - script.collect_logs.assert_called_once_with() |
378 | - script.collect_inner_logs.assert_called_once_with() |
379 | + script.collect_logs.assert_called_once_with("juju") |
380 | + script.collect_inner_logs.assert_called_once_with("juju") |
381 | script.bundle_logs.assert_called_once_with( |
382 | self.tempdir, tarfile, extrafiles) |
383 | self.assertFalse(os.path.exists(self.tempdir)) |
384 | @@ -192,9 +205,9 @@ |
385 | def test_success(self): |
386 | script.call.side_effect = self._call_side_effect |
387 | |
388 | - script.collect_logs() |
389 | + script.collect_logs("juju") |
390 | |
391 | - script.get_units.assert_called_once_with() |
392 | + script.get_units.assert_called_once_with("juju") |
393 | expected = [] |
394 | units = self.units + ["0"] |
395 | # for _create_ps_output_file() |
396 | @@ -246,9 +259,9 @@ |
397 | script.get_units.side_effect = FakeError() |
398 | |
399 | with self.assertRaises(FakeError): |
400 | - script.collect_logs() |
401 | + script.collect_logs("juju") |
402 | |
403 | - script.get_units.assert_called_once_with() |
404 | + script.get_units.assert_called_once_with("juju") |
405 | script.check_output.assert_not_called() |
406 | script.call.assert_not_called() |
407 | |
408 | @@ -258,9 +271,9 @@ |
409 | ] |
410 | |
411 | with self.assertRaises(FakeError): |
412 | - script.collect_logs() |
413 | + script.collect_logs("juju") |
414 | |
415 | - script.get_units.assert_called_once_with() |
416 | + script.get_units.assert_called_once_with("juju") |
417 | self.assertEqual(script.check_output.call_count, 2) |
418 | script.call.assert_not_called() |
419 | |
420 | @@ -276,9 +289,9 @@ |
421 | return self._call_side_effect(cmd) |
422 | script.call.side_effect = call_side_effect |
423 | |
424 | - script.collect_logs() |
425 | + script.collect_logs("juju") |
426 | |
427 | - script.get_units.assert_called_once_with() |
428 | + script.get_units.assert_called_once_with("juju") |
429 | units = self.units + ["0"] |
430 | self.assertEqual(script.check_output.call_count, len(units) * 2) |
431 | self.assertEqual(script.call.call_count, len(units) * 2 - 1) |
432 | @@ -306,6 +319,8 @@ |
433 | "haproxy/0", |
434 | ] |
435 | script.get_units.return_value = self.units[:] |
436 | + script.check_output.return_value = "0\n" |
437 | + script.call.return_value = 0 |
438 | |
439 | os.chdir(self.tempdir) |
440 | |
441 | @@ -313,50 +328,110 @@ |
442 | self.assert_cwd(self.tempdir) |
443 | self.assertFalse(os.path.exists("inner-logs.tar.gz")) |
444 | |
445 | - def test_success(self): |
446 | - def check_call_side_effect(cmd): |
447 | - if script.check_call.call_count == 2: |
448 | - self.assert_cwd(self.tempdir) |
449 | - self._touch_tempfile("inner-logs.tar.gz") |
450 | - elif script.check_call.call_count == 3: |
451 | - cwd = os.path.join(self.tempdir, "landscape-0-inner-logs") |
452 | - self.assert_cwd(cwd) |
453 | - return None |
454 | - script.check_call.side_effect = check_call_side_effect |
455 | - |
456 | - script.collect_inner_logs() |
457 | - |
458 | - # get_units() |
459 | - script.get_units.assert_called_once_with() |
460 | - # check_output() |
461 | - cmd = ("sudo JUJU_HOME=/var/lib/landscape/juju-homes/" |
462 | - "`sudo ls -rt /var/lib/landscape/juju-homes/ | tail -1`" |
463 | - " juju status") |
464 | - script.check_output.assert_called_once_with( |
465 | - ["juju", "ssh", "landscape-server/0", cmd]) |
466 | - # call() |
467 | - expected = [ |
468 | - mock.call(["juju", "scp", |
469 | - os.path.join(os.path.dirname(__file__), "collect-logs"), |
470 | - "landscape-server/0:/tmp/collect-logs", |
471 | - ]), |
472 | - mock.call(["juju", "ssh", |
473 | - "landscape-server/0", |
474 | - "sudo rm -rf /tmp/inner-logs.tar.*", |
475 | - ]), |
476 | - ] |
477 | - self.assertEqual(script.call.call_count, len(expected)) |
478 | - script.call.assert_has_calls(expected, any_order=True) |
479 | - # check_call() |
480 | - cmd = ("sudo -u landscape" |
481 | - " JUJU_HOME=/var/lib/landscape/juju-homes/" |
482 | - "`sudo ls -rt /var/lib/landscape/juju-homes/ | tail -1`" |
483 | - " /tmp/collect-logs /tmp/inner-logs.tar.gz") |
484 | - expected = [ |
485 | - mock.call(["juju", "ssh", "landscape-server/0", cmd]), |
486 | - mock.call(["juju", "scp", |
487 | - "landscape-server/0:/tmp/inner-logs.tar.gz", |
488 | - ".", |
489 | + def test_juju_2(self): |
490 | + def check_call_side_effect(cmd): |
491 | + if script.check_call.call_count == 4: |
492 | + self.assert_cwd(self.tempdir) |
493 | + self._touch_tempfile("inner-logs.tar.gz") |
494 | + elif script.check_call.call_count == 5: |
495 | + cwd = os.path.join(self.tempdir, "landscape-0-inner-logs") |
496 | + self.assert_cwd(cwd) |
497 | + return None |
498 | + script.check_call.side_effect = check_call_side_effect |
499 | + |
500 | + script.collect_inner_logs("juju") |
501 | + |
502 | + # get_units() |
503 | + script.get_units.assert_called_once_with("juju") |
504 | + # check_output() |
505 | + script.check_output.assert_called_once_with( |
506 | + ["juju", "ssh", "landscape-server/0", |
507 | + "sudo ls -rt /var/lib/landscape/juju-homes/"]) |
508 | + # call() |
509 | + expected = [ |
510 | + mock.call(["juju", "ssh", "landscape-server/0", |
511 | + ("sudo JUJU_DATA=/var/lib/landscape/juju-homes/0 " |
512 | + "juju-2.0 status"), |
513 | + ]), |
514 | + ] |
515 | + self.assertEqual(script.call.call_count, len(expected)) |
516 | + script.call.assert_has_calls(expected, any_order=True) |
517 | + # check_call() |
518 | + cmd = ("sudo -u landscape" |
519 | + " JUJU_DATA=/var/lib/landscape/juju-homes/0" |
520 | + " /tmp/collect-logs --inner --juju juju-2.0" |
521 | + " /tmp/inner-logs.tar.gz") |
522 | + expected = [ |
523 | + mock.call(["juju", "scp", |
524 | + os.path.join(os.path.dirname(__file__), "collect-logs"), |
525 | + "landscape-server/0:/tmp/collect-logs", |
526 | + ]), |
527 | + mock.call(["juju", "ssh", |
528 | + "landscape-server/0", |
529 | + "sudo rm -rf /tmp/inner-logs.tar.*", |
530 | + ]), |
531 | + mock.call(["juju", "ssh", "landscape-server/0", cmd]), |
532 | + mock.call(["juju", "scp", |
533 | + "landscape-server/0:/tmp/inner-logs.tar.gz", |
534 | + os.path.join(self.tempdir, "inner-logs.tar.gz"), |
535 | + ]), |
536 | + mock.call(["tar", "-zxf", self.tempdir + "/inner-logs.tar.gz"]), |
537 | + ] |
538 | + self.assertEqual(script.check_call.call_count, len(expected)) |
539 | + script.check_call.assert_has_calls(expected, any_order=True) |
540 | + self.assert_clean() |
541 | + |
542 | + def test_juju_1(self): |
543 | + def check_call_side_effect(cmd): |
544 | + if script.check_call.call_count == 4: |
545 | + self.assert_cwd(self.tempdir) |
546 | + self._touch_tempfile("inner-logs.tar.gz") |
547 | + elif script.check_call.call_count == 5: |
548 | + cwd = os.path.join(self.tempdir, "landscape-0-inner-logs") |
549 | + self.assert_cwd(cwd) |
550 | + return None |
551 | + script.check_call.side_effect = check_call_side_effect |
552 | + script.call.side_effect = [1, 0] |
553 | + |
554 | + script.collect_inner_logs("juju") |
555 | + |
556 | + # get_units() |
557 | + script.get_units.assert_called_once_with("juju") |
558 | + # check_output() |
559 | + script.check_output.assert_called_once_with( |
560 | + ["juju", "ssh", "landscape-server/0", |
561 | + "sudo ls -rt /var/lib/landscape/juju-homes/"]) |
562 | + # call() |
563 | + expected = [ |
564 | + mock.call(["juju", "ssh", "landscape-server/0", |
565 | + ("sudo JUJU_DATA=/var/lib/landscape/juju-homes/0 " |
566 | + "juju-2.0 status"), |
567 | + ]), |
568 | + mock.call(["juju", "ssh", "landscape-server/0", |
569 | + ("sudo JUJU_HOME=/var/lib/landscape/juju-homes/0 " |
570 | + "juju status"), |
571 | + ]), |
572 | + ] |
573 | + self.assertEqual(script.call.call_count, len(expected)) |
574 | + script.call.assert_has_calls(expected, any_order=True) |
575 | + # check_call() |
576 | + cmd = ("sudo -u landscape" |
577 | + " JUJU_HOME=/var/lib/landscape/juju-homes/0" |
578 | + " /tmp/collect-logs --inner --juju juju" |
579 | + " /tmp/inner-logs.tar.gz") |
580 | + expected = [ |
581 | + mock.call(["juju", "scp", |
582 | + os.path.join(os.path.dirname(__file__), "collect-logs"), |
583 | + "landscape-server/0:/tmp/collect-logs", |
584 | + ]), |
585 | + mock.call(["juju", "ssh", |
586 | + "landscape-server/0", |
587 | + "sudo rm -rf /tmp/inner-logs.tar.*", |
588 | + ]), |
589 | + mock.call(["juju", "ssh", "landscape-server/0", cmd]), |
590 | + mock.call(["juju", "scp", |
591 | + "landscape-server/0:/tmp/inner-logs.tar.gz", |
592 | + os.path.join(self.tempdir, "inner-logs.tar.gz"), |
593 | ]), |
594 | mock.call(["tar", "-zxf", self.tempdir + "/inner-logs.tar.gz"]), |
595 | ] |
596 | @@ -368,21 +443,19 @@ |
597 | self.units[0] = "landscape/0" |
598 | script.get_units.return_value = self.units[:] |
599 | |
600 | - script.collect_inner_logs() |
601 | + script.collect_inner_logs("juju") |
602 | |
603 | - cmd = ("sudo JUJU_HOME=/var/lib/landscape/juju-homes/" |
604 | - "`sudo ls -rt /var/lib/landscape/juju-homes/ | tail -1`" |
605 | - " juju status") |
606 | script.check_output.assert_called_once_with( |
607 | - ["juju", "ssh", "landscape/0", cmd]) |
608 | + ["juju", "ssh", "landscape/0", |
609 | + "sudo ls -rt /var/lib/landscape/juju-homes/"]) |
610 | self.assert_clean() |
611 | |
612 | def test_no_units(self): |
613 | script.get_units.return_value = [] |
614 | |
615 | - script.collect_inner_logs() |
616 | + script.collect_inner_logs("juju") |
617 | |
618 | - script.get_units.assert_called_once_with() |
619 | + script.get_units.assert_called_once_with("juju") |
620 | script.check_output.assert_not_called() |
621 | script.call.assert_not_called() |
622 | script.check_call.assert_not_called() |
623 | @@ -392,9 +465,23 @@ |
624 | del self.units[0] |
625 | script.get_units.return_value = self.units[:] |
626 | |
627 | - script.collect_inner_logs() |
628 | - |
629 | - script.get_units.assert_called_once_with() |
630 | + script.collect_inner_logs("juju") |
631 | + |
632 | + script.get_units.assert_called_once_with("juju") |
633 | + script.check_output.assert_not_called() |
634 | + script.call.assert_not_called() |
635 | + script.check_call.assert_not_called() |
636 | + self.assert_clean() |
637 | + |
638 | + def test_no_juju_homes(self): |
639 | + script.get_units.return_value = [] |
640 | + script.check_output.return_value = "" |
641 | + |
642 | + script.collect_inner_logs("juju") |
643 | + |
644 | + script.get_units.assert_called_once_with("juju") |
645 | + |
646 | + script.get_units.assert_called_once_with("juju") |
647 | script.check_output.assert_not_called() |
648 | script.call.assert_not_called() |
649 | script.check_call.assert_not_called() |
650 | @@ -404,7 +491,7 @@ |
651 | script.get_units.side_effect = FakeError() |
652 | |
653 | with self.assertRaises(FakeError): |
654 | - script.collect_inner_logs() |
655 | + script.collect_inner_logs("juju") |
656 | |
657 | self.assertEqual(script.get_units.call_count, 1) |
658 | script.check_output.assert_not_called() |
659 | @@ -417,7 +504,7 @@ |
660 | script.check_output.side_effect = FakeError() |
661 | |
662 | with self.assertRaises(FakeError): |
663 | - script.collect_inner_logs() |
664 | + script.collect_inner_logs("juju") |
665 | |
666 | self.assertEqual(script.get_units.call_count, 1) |
667 | self.assertEqual(script.check_output.call_count, 1) |
668 | @@ -426,11 +513,11 @@ |
669 | self.assert_cwd(self.tempdir) |
670 | self.assert_clean() |
671 | |
672 | - def test_call_failure_1(self): |
673 | + def test_call_juju2_failure(self): |
674 | script.call.side_effect = FakeError() |
675 | |
676 | with self.assertRaises(FakeError): |
677 | - script.collect_inner_logs() |
678 | + script.collect_inner_logs("juju") |
679 | |
680 | self.assertEqual(script.get_units.call_count, 1) |
681 | self.assertEqual(script.check_output.call_count, 1) |
682 | @@ -439,13 +526,51 @@ |
683 | self.assert_cwd(self.tempdir) |
684 | self.assert_clean() |
685 | |
686 | - def test_call_failure_2(self): |
687 | - script.call.side_effect = [None, |
688 | + def test_call_juju1_failure(self): |
689 | + script.call.side_effect = [1, |
690 | FakeError(), |
691 | ] |
692 | |
693 | with self.assertRaises(FakeError): |
694 | - script.collect_inner_logs() |
695 | + script.collect_inner_logs("juju") |
696 | + |
697 | + self.assertEqual(script.get_units.call_count, 1) |
698 | + self.assertEqual(script.check_output.call_count, 1) |
699 | + self.assertEqual(script.call.call_count, 2) |
700 | + script.check_call.assert_not_called() |
701 | + self.assert_cwd(self.tempdir) |
702 | + self.assert_clean() |
703 | + |
704 | + def test_call_juju2_nonzero_return(self): |
705 | + script.call.side_effect = [1, |
706 | + mock.DEFAULT, |
707 | + ] |
708 | + |
709 | + script.collect_inner_logs("juju") |
710 | + |
711 | + self.assertEqual(script.get_units.call_count, 1) |
712 | + self.assertEqual(script.check_output.call_count, 1) |
713 | + self.assertEqual(script.call.call_count, 2) |
714 | + self.assertEqual(script.check_call.call_count, 5) |
715 | + self.assert_clean() |
716 | + |
717 | + def test_call_juju1_nonzero_return(self): |
718 | + script.call.side_effect = [mock.DEFAULT, |
719 | + 1, |
720 | + ] |
721 | + |
722 | + script.collect_inner_logs("juju") |
723 | + |
724 | + self.assertEqual(script.get_units.call_count, 1) |
725 | + self.assertEqual(script.check_output.call_count, 1) |
726 | + self.assertEqual(script.call.call_count, 1) |
727 | + self.assertEqual(script.check_call.call_count, 5) |
728 | + self.assert_clean() |
729 | + |
730 | + def test_call_all_nonzero_return(self): |
731 | + script.call.return_value = 1 |
732 | + |
733 | + script.collect_inner_logs("juju") |
734 | |
735 | self.assertEqual(script.get_units.call_count, 1) |
736 | self.assertEqual(script.check_output.call_count, 1) |
737 | @@ -457,11 +582,11 @@ |
738 | script.check_call.side_effect = FakeError() |
739 | |
740 | with self.assertRaises(FakeError): |
741 | - script.collect_inner_logs() |
742 | + script.collect_inner_logs("juju") |
743 | |
744 | self.assertEqual(script.get_units.call_count, 1) |
745 | self.assertEqual(script.check_output.call_count, 1) |
746 | - self.assertEqual(script.call.call_count, 2) |
747 | + self.assertEqual(script.call.call_count, 1) |
748 | self.assertEqual(script.check_call.call_count, 1) |
749 | self.assert_clean() |
750 | |
751 | @@ -471,31 +596,62 @@ |
752 | ] |
753 | |
754 | with self.assertRaises(FakeError): |
755 | - script.collect_inner_logs() |
756 | + script.collect_inner_logs("juju") |
757 | |
758 | self.assertEqual(script.get_units.call_count, 1) |
759 | self.assertEqual(script.check_output.call_count, 1) |
760 | - self.assertEqual(script.call.call_count, 2) |
761 | + self.assertEqual(script.call.call_count, 1) |
762 | self.assertEqual(script.check_call.call_count, 2) |
763 | self.assert_clean() |
764 | |
765 | def test_check_call_failure_3(self): |
766 | + script.check_call.side_effect = [None, |
767 | + None, |
768 | + FakeError(), |
769 | + ] |
770 | + |
771 | + with self.assertRaises(FakeError): |
772 | + script.collect_inner_logs("juju") |
773 | + |
774 | + self.assertEqual(script.get_units.call_count, 1) |
775 | + self.assertEqual(script.check_output.call_count, 1) |
776 | + self.assertEqual(script.call.call_count, 1) |
777 | + self.assertEqual(script.check_call.call_count, 3) |
778 | + self.assert_clean() |
779 | + |
780 | + def test_check_call_failure_4(self): |
781 | + script.check_call.side_effect = [None, |
782 | + None, |
783 | + None, |
784 | + FakeError(), |
785 | + ] |
786 | + |
787 | + with self.assertRaises(FakeError): |
788 | + script.collect_inner_logs("juju") |
789 | + |
790 | + self.assertEqual(script.get_units.call_count, 1) |
791 | + self.assertEqual(script.check_output.call_count, 1) |
792 | + self.assertEqual(script.call.call_count, 1) |
793 | + self.assertEqual(script.check_call.call_count, 4) |
794 | + self.assert_clean() |
795 | + |
796 | + def test_check_call_failure_5(self): |
797 | def check_call_side_effect(cmd): |
798 | - if script.check_call.call_count == 1: |
799 | + if script.check_call.call_count in (1, 2, 3): |
800 | return None |
801 | - if script.check_call.call_count == 2: |
802 | + if script.check_call.call_count == 4: |
803 | self._touch_tempfile("inner-logs.tar.gz") |
804 | return None |
805 | raise FakeError() |
806 | script.check_call.side_effect = check_call_side_effect |
807 | |
808 | with self.assertRaises(FakeError): |
809 | - script.collect_inner_logs() |
810 | + script.collect_inner_logs("juju") |
811 | |
812 | self.assertEqual(script.get_units.call_count, 1) |
813 | self.assertEqual(script.check_output.call_count, 1) |
814 | - self.assertEqual(script.call.call_count, 2) |
815 | - self.assertEqual(script.check_call.call_count, 3) |
816 | + self.assertEqual(script.call.call_count, 1) |
817 | + self.assertEqual(script.check_call.call_count, 5) |
818 | self.assert_clean() |
819 | |
820 |