Merge ~chad.smith/cloud-init:ubuntu/devel into cloud-init:ubuntu/devel
- Git
- lp:~chad.smith/cloud-init
- ubuntu/devel
- Merge into ubuntu/devel
Proposed by
Chad Smith
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Merged at revision: | e4ea57a37ee1834199ba06235a75b12f2cd0f99f | ||||||||
Proposed branch: | ~chad.smith/cloud-init:ubuntu/devel | ||||||||
Merge into: | cloud-init:ubuntu/devel | ||||||||
Diff against target: |
666 lines (+278/-63) 19 files modified
HACKING.rst (+8/-0) cloudinit/cmd/status.py (+5/-2) cloudinit/cmd/tests/test_status.py (+18/-3) cloudinit/config/cc_power_state_change.py (+1/-0) cloudinit/config/cc_rh_subscription.py (+2/-3) cloudinit/distros/freebsd.py (+3/-8) cloudinit/util.py (+4/-0) debian/changelog (+11/-0) doc/rtd/topics/boot.rst (+10/-3) doc/rtd/topics/capabilities.rst (+153/-7) doc/rtd/topics/debugging.rst (+1/-0) doc/rtd/topics/modules.rst (+2/-0) tests/cloud_tests/collect.py (+7/-0) tests/cloud_tests/platforms/lxd/instance.py (+19/-24) tests/cloud_tests/testcases.yaml (+21/-6) tests/cloud_tests/testcases/base.py (+4/-2) tests/cloud_tests/verify.py (+1/-1) tests/unittests/test_ds_identify.py (+5/-3) tools/ds-identify (+3/-1) |
||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Scott Moser | Pending | ||
Review via email: mp+337088@code.launchpad.net |
Commit message
Description of the change
Sync latest cloud-init master to Bionic for release
To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Server Team CI bot (server-team-bot) wrote : | # |
PASSED: Continuous integration, rev:e4ea57a37ee
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
SUCCESS: Ubuntu LTS: Build
SUCCESS: Ubuntu LTS: Integration
SUCCESS: MAAS Compatability Testing
IN_PROGRESS: Declarative: Post Actions
Click here to trigger a rebuild:
https:/
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/HACKING.rst b/HACKING.rst |
2 | index 93e3f42..3bb555c 100644 |
3 | --- a/HACKING.rst |
4 | +++ b/HACKING.rst |
5 | @@ -16,6 +16,14 @@ Do these things once |
6 | When prompted for 'Project contact' or 'Canonical Project Manager' enter |
7 | 'Scott Moser'. |
8 | |
9 | +* Configure git with your email and name for commit messages. |
10 | + |
11 | + Your name will appear in commit messages and will also be used in |
12 | + changelogs or release notes. Give yourself credit!:: |
13 | + |
14 | + git config user.name "Your Name" |
15 | + git config user.email "Your Email" |
16 | + |
17 | * Clone the upstream `repository`_ on Launchpad:: |
18 | |
19 | git clone https://git.launchpad.net/cloud-init |
20 | diff --git a/cloudinit/cmd/status.py b/cloudinit/cmd/status.py |
21 | index 3e5d0d0..d7aaee9 100644 |
22 | --- a/cloudinit/cmd/status.py |
23 | +++ b/cloudinit/cmd/status.py |
24 | @@ -93,6 +93,8 @@ def _is_cloudinit_disabled(disable_file, paths): |
25 | elif not os.path.exists(os.path.join(paths.run_dir, 'enabled')): |
26 | is_disabled = True |
27 | reason = 'Cloud-init disabled by cloud-init-generator' |
28 | + else: |
29 | + reason = 'Cloud-init enabled by systemd cloud-init-generator' |
30 | return (is_disabled, reason) |
31 | |
32 | |
33 | @@ -127,10 +129,11 @@ def _get_status_details(paths): |
34 | status_detail = value |
35 | elif isinstance(value, dict): |
36 | errors.extend(value.get('errors', [])) |
37 | + start = value.get('start') or 0 |
38 | finished = value.get('finished') or 0 |
39 | - if finished == 0: |
40 | + if finished == 0 and start != 0: |
41 | status = STATUS_RUNNING |
42 | - event_time = max(value.get('start', 0), finished) |
43 | + event_time = max(start, finished) |
44 | if event_time > latest_event: |
45 | latest_event = event_time |
46 | if errors: |
47 | diff --git a/cloudinit/cmd/tests/test_status.py b/cloudinit/cmd/tests/test_status.py |
48 | index 6d4a11e..a7c0a91 100644 |
49 | --- a/cloudinit/cmd/tests/test_status.py |
50 | +++ b/cloudinit/cmd/tests/test_status.py |
51 | @@ -93,6 +93,19 @@ class TestStatus(CiTestCase): |
52 | self.assertTrue(is_disabled, 'expected disabled cloud-init') |
53 | self.assertEqual('Cloud-init disabled by cloud-init-generator', reason) |
54 | |
55 | + def test__is_cloudinit_disabled_false_when_enabled_in_systemd(self): |
56 | + '''Report enabled when systemd generator creates the enabled file.''' |
57 | + enabled_file = os.path.join(self.paths.run_dir, 'enabled') |
58 | + write_file(enabled_file, '') |
59 | + (is_disabled, reason) = wrap_and_call( |
60 | + 'cloudinit.cmd.status', |
61 | + {'uses_systemd': True, |
62 | + 'get_cmdline': 'something ignored'}, |
63 | + status._is_cloudinit_disabled, self.disable_file, self.paths) |
64 | + self.assertFalse(is_disabled, 'expected enabled cloud-init') |
65 | + self.assertEqual( |
66 | + 'Cloud-init enabled by systemd cloud-init-generator', reason) |
67 | + |
68 | def test_status_returns_not_run(self): |
69 | '''When status.json does not exist yet, return 'not run'.''' |
70 | self.assertFalse( |
71 | @@ -137,8 +150,9 @@ class TestStatus(CiTestCase): |
72 | self.assertEqual(expected, m_stdout.getvalue()) |
73 | |
74 | def test_status_returns_running(self): |
75 | - '''Report running when status file exists but isn't finished.''' |
76 | - write_json(self.status_file, {'v1': {'init': {'finished': None}}}) |
77 | + '''Report running when status exists with an unfinished stage.''' |
78 | + write_json(self.status_file, |
79 | + {'v1': {'init': {'start': 1, 'finished': None}}}) |
80 | cmdargs = myargs(long=False, wait=False) |
81 | with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout: |
82 | retcode = wrap_and_call( |
83 | @@ -338,7 +352,8 @@ class TestStatus(CiTestCase): |
84 | |
85 | def test_status_main(self): |
86 | '''status.main can be run as a standalone script.''' |
87 | - write_json(self.status_file, {'v1': {'init': {'finished': None}}}) |
88 | + write_json(self.status_file, |
89 | + {'v1': {'init': {'start': 1, 'finished': None}}}) |
90 | with self.assertRaises(SystemExit) as context_manager: |
91 | with mock.patch('sys.stdout', new_callable=StringIO) as m_stdout: |
92 | wrap_and_call( |
93 | diff --git a/cloudinit/config/cc_power_state_change.py b/cloudinit/config/cc_power_state_change.py |
94 | index eba58b0..4da3a58 100644 |
95 | --- a/cloudinit/config/cc_power_state_change.py |
96 | +++ b/cloudinit/config/cc_power_state_change.py |
97 | @@ -194,6 +194,7 @@ def doexit(sysexit): |
98 | |
99 | |
100 | def execmd(exe_args, output=None, data_in=None): |
101 | + ret = 1 |
102 | try: |
103 | proc = subprocess.Popen(exe_args, stdin=subprocess.PIPE, |
104 | stdout=output, stderr=subprocess.STDOUT) |
105 | diff --git a/cloudinit/config/cc_rh_subscription.py b/cloudinit/config/cc_rh_subscription.py |
106 | index a9d21e7..530808c 100644 |
107 | --- a/cloudinit/config/cc_rh_subscription.py |
108 | +++ b/cloudinit/config/cc_rh_subscription.py |
109 | @@ -276,9 +276,8 @@ class SubscriptionManager(object): |
110 | cmd = ['attach', '--auto'] |
111 | try: |
112 | return_out, return_err = self._sub_man_cli(cmd) |
113 | - except util.ProcessExecutionError: |
114 | - self.log_warn("Auto-attach failed with: " |
115 | - "{0}]".format(return_err.strip())) |
116 | + except util.ProcessExecutionError as e: |
117 | + self.log_warn("Auto-attach failed with: {0}".format(e)) |
118 | return False |
119 | for line in return_out.split("\n"): |
120 | if line is not "": |
121 | diff --git a/cloudinit/distros/freebsd.py b/cloudinit/distros/freebsd.py |
122 | index bad112f..aa468bc 100644 |
123 | --- a/cloudinit/distros/freebsd.py |
124 | +++ b/cloudinit/distros/freebsd.py |
125 | @@ -116,6 +116,7 @@ class Distro(distros.Distro): |
126 | (out, err) = util.subp(['ifconfig', '-a']) |
127 | ifconfigoutput = [x for x in (out.strip()).splitlines() |
128 | if len(x.split()) > 0] |
129 | + bsddev = 'NOT_FOUND' |
130 | for line in ifconfigoutput: |
131 | m = re.match('^\w+', line) |
132 | if m: |
133 | @@ -347,15 +348,9 @@ class Distro(distros.Distro): |
134 | bymac[Distro.get_interface_mac(n)] = { |
135 | 'name': n, 'up': self.is_up(n), 'downable': None} |
136 | |
137 | + nics_with_addresses = set() |
138 | if check_downable: |
139 | - nics_with_addresses = set() |
140 | - ipv6 = self.get_ipv6() |
141 | - ipv4 = self.get_ipv4() |
142 | - for bytes_out in (ipv6, ipv4): |
143 | - for i in ipv6: |
144 | - nics_with_addresses.update(i) |
145 | - for i in ipv4: |
146 | - nics_with_addresses.update(i) |
147 | + nics_with_addresses = set(self.get_ipv4() + self.get_ipv6()) |
148 | |
149 | for d in bymac.values(): |
150 | d['downable'] = (d['up'] is False or |
151 | diff --git a/cloudinit/util.py b/cloudinit/util.py |
152 | index 9976400..338fb97 100644 |
153 | --- a/cloudinit/util.py |
154 | +++ b/cloudinit/util.py |
155 | @@ -1587,6 +1587,10 @@ def mount_cb(device, callback, data=None, rw=False, mtype=None, sync=True): |
156 | mtypes = list(mtype) |
157 | elif mtype is None: |
158 | mtypes = None |
159 | + else: |
160 | + raise TypeError( |
161 | + 'Unsupported type provided for mtype parameter: {_type}'.format( |
162 | + _type=type(mtype))) |
163 | |
164 | # clean up 'mtype' input a bit based on platform. |
165 | platsys = platform.system().lower() |
166 | diff --git a/debian/changelog b/debian/changelog |
167 | index 8879717..314d8d5 100644 |
168 | --- a/debian/changelog |
169 | +++ b/debian/changelog |
170 | @@ -1,3 +1,14 @@ |
171 | +cloud-init (17.2-30-gf7deaf15-0ubuntu1) bionic; urgency=medium |
172 | + |
173 | + * New upstream snapshot. |
174 | + - docs: Update RTD content for cloud-init subcommands. |
175 | + - OVF: Extend well-known labels to include OVFENV. (LP: #1698669) |
176 | + - Fix potential cases of uninitialized variables. (LP: #1744796) |
177 | + - tests: Collect script output as binary, collect systemd journal, fix lxd. |
178 | + - HACKING.rst: mention setting user name and email via git config. |
179 | + |
180 | + -- Chad Smith <chad.smith@canonical.com> Fri, 02 Feb 2018 09:51:14 -0700 |
181 | + |
182 | cloud-init (17.2-25-gc03bdd3d-0ubuntu1) bionic; urgency=medium |
183 | |
184 | * New upstream snapshot. |
185 | diff --git a/doc/rtd/topics/boot.rst b/doc/rtd/topics/boot.rst |
186 | index 859409a..f2976fd 100644 |
187 | --- a/doc/rtd/topics/boot.rst |
188 | +++ b/doc/rtd/topics/boot.rst |
189 | @@ -1,3 +1,5 @@ |
190 | +.. _boot_stages: |
191 | + |
192 | *********** |
193 | Boot Stages |
194 | *********** |
195 | @@ -74,7 +76,7 @@ Network |
196 | * **systemd service**: ``cloud-init.service`` |
197 | * **runs**: After local stage and configured networking is up. |
198 | * **blocks**: As much of remaining boot as possible. |
199 | - * **modules**: ``init_modules`` |
200 | + * **modules**: ``cloud_init_modules`` in **/etc/cloud/cloud.cfg** |
201 | |
202 | This stage requires all configured networking to be online, as it will fully |
203 | process any user-data that is found. Here, processing means: |
204 | @@ -104,7 +106,7 @@ Config |
205 | * **systemd service**: ``cloud-config.service`` |
206 | * **runs**: After network stage. |
207 | * **blocks**: None. |
208 | - * **modules**: ``config_modules`` |
209 | + * **modules**: ``cloud_config_modules`` in **/etc/cloud/cloud.cfg** |
210 | |
211 | This stage runs config modules only. Modules that do not really have an |
212 | effect on other stages of boot are run here. |
213 | @@ -115,7 +117,7 @@ Final |
214 | * **systemd service**: ``cloud-final.service`` |
215 | * **runs**: As final part of boot (traditional "rc.local") |
216 | * **blocks**: None. |
217 | - * **modules**: ``final_modules`` |
218 | + * **modules**: ``cloud_final_modules`` in **/etc/cloud/cloud.cfg** |
219 | |
220 | This stage runs as late in boot as possible. Any scripts that a user is |
221 | accustomed to running after logging into a system should run correctly here. |
222 | @@ -125,4 +127,9 @@ Things that run here include |
223 | * configuration management plugins (puppet, chef, salt-minion) |
224 | * user-scripts (including ``runcmd``). |
225 | |
226 | +For scripts external to cloud-init looking to wait until cloud-init |
227 | +finished, the ``cloud-init status`` subcommand can help block external |
228 | +scripts until cloud-init is done without having to write your own systemd |
229 | +units dependency chains. See :ref:`cli_status` for more info. |
230 | + |
231 | .. vi: textwidth=78 |
232 | diff --git a/doc/rtd/topics/capabilities.rst b/doc/rtd/topics/capabilities.rst |
233 | index 31eaba5..ae3a0c7 100644 |
234 | --- a/doc/rtd/topics/capabilities.rst |
235 | +++ b/doc/rtd/topics/capabilities.rst |
236 | @@ -1,3 +1,5 @@ |
237 | +.. _capabilities: |
238 | + |
239 | ************ |
240 | Capabilities |
241 | ************ |
242 | @@ -39,17 +41,19 @@ Currently defined feature names include: |
243 | see :ref:`network_config_v2` documentation for examples. |
244 | |
245 | |
246 | -CLI Interface : |
247 | +CLI Interface |
248 | +============= |
249 | |
250 | -``cloud-init features`` will print out each feature supported. If cloud-init |
251 | -does not have the features subcommand, it also does not support any features |
252 | -described in this document. |
253 | + The command line documentation is accessible on any cloud-init |
254 | +installed system: |
255 | |
256 | .. code-block:: bash |
257 | |
258 | % cloud-init --help |
259 | - usage: cloud-init [-h] [--version] [--file FILES] [--debug] [--force] |
260 | - {init,modules,query,single,dhclient-hook,features} ... |
261 | + usage: cloud-init [-h] [--version] [--file FILES] |
262 | + [--debug] [--force] |
263 | + {init,modules,single,dhclient-hook,features,analyze,devel,collect-logs,clean,status} |
264 | + ... |
265 | |
266 | optional arguments: |
267 | -h, --help show this help message and exit |
268 | @@ -61,7 +65,7 @@ described in this document. |
269 | your own risk) |
270 | |
271 | Subcommands: |
272 | - {init,modules,single,dhclient-hook,features,analyze,devel} |
273 | + {init,modules,single,dhclient-hook,features,analyze,devel,collect-logs,clean,status} |
274 | init initializes cloud-init and performs initial modules |
275 | modules activates modules using a given configuration key |
276 | single run a single module |
277 | @@ -69,11 +73,153 @@ described in this document. |
278 | features list defined features |
279 | analyze Devel tool: Analyze cloud-init logs and data |
280 | devel Run development tools |
281 | + collect-logs Collect and tar all cloud-init debug info |
282 | + clean Remove logs and artifacts so cloud-init can re-run. |
283 | + status Report cloud-init status or wait on completion. |
284 | + |
285 | +CLI Subcommand details |
286 | +====================== |
287 | + |
288 | +.. _cli_features: |
289 | + |
290 | +cloud-init features |
291 | +------------------- |
292 | +Print out each feature supported. If cloud-init does not have the |
293 | +features subcommand, it also does not support any features described in |
294 | +this document. |
295 | + |
296 | +.. code-block:: bash |
297 | |
298 | % cloud-init features |
299 | NETWORK_CONFIG_V1 |
300 | NETWORK_CONFIG_V2 |
301 | |
302 | +.. _cli_status: |
303 | + |
304 | +cloud-init status |
305 | +----------------- |
306 | +Report whether cloud-init is running, done, disabled or errored. Exits |
307 | +non-zero if an error is detected in cloud-init. |
308 | + * **--long**: Detailed status information. |
309 | + * **--wait**: Block until cloud-init completes. |
310 | + |
311 | +.. code-block:: bash |
312 | + |
313 | + % cloud-init status --long |
314 | + status: done |
315 | + time: Wed, 17 Jan 2018 20:41:59 +0000 |
316 | + detail: |
317 | + DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud-net][dsmode=net] |
318 | + |
319 | + # Cloud-init running still short versus long options |
320 | + % cloud-init status |
321 | + status: running |
322 | + % cloud-init status --long |
323 | + status: running |
324 | + time: Fri, 26 Jan 2018 21:39:43 +0000 |
325 | + detail: |
326 | + Running in stage: init-local |
327 | + |
328 | +.. _cli_collect_logs: |
329 | + |
330 | +cloud-init collect-logs |
331 | +----------------------- |
332 | +Collect and tar cloud-init generated logs, data files and system |
333 | +information for triage. This subcommand is integrated with apport. |
334 | + |
335 | +**Note**: Ubuntu users can file bugs with `ubuntu-bug cloud-init` to |
336 | +automaticaly attach these logs to a bug report. |
337 | + |
338 | +Logs collected are: |
339 | + |
340 | + * /var/log/cloud-init*log |
341 | + * /run/cloud-init |
342 | + * cloud-init package version |
343 | + * dmesg output |
344 | + * journalctl output |
345 | + * /var/lib/cloud/instance/user-data.txt |
346 | + |
347 | +.. _cli_analyze: |
348 | + |
349 | +cloud-init analyze |
350 | +------------------ |
351 | +Get detailed reports of where cloud-init spends most of its time. See |
352 | +:ref:`boot_time_analysis` for more info. |
353 | + |
354 | + * **blame** Report ordered by most costly operations. |
355 | + * **dump** Machine-readable JSON dump of all cloud-init tracked events. |
356 | + * **show** show time-ordered report of the cost of operations during each |
357 | + boot stage. |
358 | + |
359 | +.. _cli_devel: |
360 | + |
361 | +cloud-init devel |
362 | +---------------- |
363 | +Collection of development tools under active development. These tools will |
364 | +likely be promoted to top-level subcommands when stable. |
365 | + |
366 | + * ``cloud-init devel schema``: A **#cloud-config** format and schema |
367 | + validator. It accepts a cloud-config yaml file and annotates potential |
368 | + schema errors locally without the need for deployment. Schema |
369 | + validation is work in progress and supports a subset of cloud-config |
370 | + modules. |
371 | + |
372 | +.. _cli_clean: |
373 | + |
374 | +cloud-init clean |
375 | +---------------- |
376 | +Remove cloud-init artifacts from /var/lib/cloud and optionally reboot the |
377 | +machine to so cloud-init re-runs all stages as it did on first boot. |
378 | + |
379 | + * **--logs**: Optionally remove /var/log/cloud-init*log files. |
380 | + * **--reboot**: Reboot the system after removing artifacts. |
381 | + |
382 | +.. _cli_init: |
383 | + |
384 | +cloud-init init |
385 | +--------------- |
386 | +Generally run by OS init systems to execute cloud-init's stages |
387 | +*init* and *init-local*. See :ref:`boot_stages` for more info. |
388 | +Can be run on the commandline, but is generally gated to run only once |
389 | +due to semaphores in **/var/lib/cloud/instance/sem/** and |
390 | +**/var/lib/cloud/sem**. |
391 | + |
392 | + * **--local**: Run *init-local* stage instead of *init*. |
393 | + |
394 | +.. _cli_modules: |
395 | + |
396 | +cloud-init modules |
397 | +------------------ |
398 | +Generally run by OS init systems to execute *modules:config* and |
399 | +*modules:final* boot stages. This executes cloud config :ref:`modules` |
400 | +configured to run in the init, config and final stages. The modules are |
401 | +declared to run in various boot stages in the file |
402 | +**/etc/cloud/cloud.cfg** under keys **cloud_init_modules**, |
403 | +**cloud_init_modules** and **cloud_init_modules**. Can be run on the |
404 | +commandline, but each module is gated to run only once due to semaphores |
405 | +in ``/var/lib/cloud/``. |
406 | + |
407 | + * **--mode (init|config|final)**: Run *modules:init*, *modules:config* or |
408 | + *modules:final* cloud-init stages. See :ref:`boot_stages` for more info. |
409 | + |
410 | +.. _cli_single: |
411 | + |
412 | +cloud-init single |
413 | +----------------- |
414 | +Attempt to run a single named cloud config module. The following example |
415 | +re-runs the cc_set_hostname module ignoring the module default frequency |
416 | +of once-per-instance: |
417 | + |
418 | + * **--name**: The cloud-config module name to run |
419 | + * **--frequency**: Optionally override the declared module frequency |
420 | + with one of (always|once-per-instance|once) |
421 | + |
422 | +.. code-block:: bash |
423 | + |
424 | + % cloud-init single --name set_hostname --frequency always |
425 | + |
426 | +**Note**: Mileage may vary trying to re-run each cloud-config module, as |
427 | +some are not idempotent. |
428 | |
429 | .. _Cloud-init: https://launchpad.net/cloud-init |
430 | .. vi: textwidth=78 |
431 | diff --git a/doc/rtd/topics/debugging.rst b/doc/rtd/topics/debugging.rst |
432 | index 4e43dd5..c2b47ed 100644 |
433 | --- a/doc/rtd/topics/debugging.rst |
434 | +++ b/doc/rtd/topics/debugging.rst |
435 | @@ -7,6 +7,7 @@ Overview |
436 | This topic will discuss general approaches for test and debug of cloud-init on |
437 | deployed instances. |
438 | |
439 | +.. _boot_time_analysis: |
440 | |
441 | Boot Time Analysis - cloud-init analyze |
442 | ====================================== |
443 | diff --git a/doc/rtd/topics/modules.rst b/doc/rtd/topics/modules.rst |
444 | index cdb0f41..7b14675 100644 |
445 | --- a/doc/rtd/topics/modules.rst |
446 | +++ b/doc/rtd/topics/modules.rst |
447 | @@ -1,3 +1,5 @@ |
448 | +.. _modules: |
449 | + |
450 | ******* |
451 | Modules |
452 | ******* |
453 | diff --git a/tests/cloud_tests/collect.py b/tests/cloud_tests/collect.py |
454 | index 33acbb1..5ea88e5 100644 |
455 | --- a/tests/cloud_tests/collect.py |
456 | +++ b/tests/cloud_tests/collect.py |
457 | @@ -24,6 +24,13 @@ def collect_script(instance, base_dir, script, script_name): |
458 | (out, err, exit) = instance.run_script( |
459 | script.encode(), rcs=False, |
460 | description='collect: {}'.format(script_name)) |
461 | + if err: |
462 | + LOG.debug("collect script %s had stderr: %s", script_name, err) |
463 | + if not isinstance(out, bytes): |
464 | + raise util.PlatformError( |
465 | + "Collection of '%s' returned type %s, expected bytes: %s" % |
466 | + (script_name, type(out), out)) |
467 | + |
468 | c_util.write_file(os.path.join(base_dir, script_name), out) |
469 | |
470 | |
471 | diff --git a/tests/cloud_tests/platforms/lxd/instance.py b/tests/cloud_tests/platforms/lxd/instance.py |
472 | index 0d697c0..d2d2a1f 100644 |
473 | --- a/tests/cloud_tests/platforms/lxd/instance.py |
474 | +++ b/tests/cloud_tests/platforms/lxd/instance.py |
475 | @@ -6,6 +6,8 @@ import os |
476 | import shutil |
477 | from tempfile import mkdtemp |
478 | |
479 | +from cloudinit.util import subp, ProcessExecutionError |
480 | + |
481 | from ..instances import Instance |
482 | |
483 | |
484 | @@ -29,6 +31,7 @@ class LXDInstance(Instance): |
485 | platform, name, properties, config, features) |
486 | self.tmpd = mkdtemp(prefix="%s-%s" % (type(self).__name__, name)) |
487 | self._setup_console_log() |
488 | + self.name = name |
489 | |
490 | @property |
491 | def pylxd_container(self): |
492 | @@ -55,33 +58,25 @@ class LXDInstance(Instance): |
493 | if env is None: |
494 | env = {} |
495 | |
496 | - if stdin is not None: |
497 | - # pylxd does not support input to execute. |
498 | - # https://github.com/lxc/pylxd/issues/244 |
499 | - # |
500 | - # The solution here is write a tmp file in the container |
501 | - # and then execute a shell that sets it standard in to |
502 | - # be from that file, removes it, and calls the comand. |
503 | - tmpf = self.tmpfile() |
504 | - self.write_data(tmpf, stdin) |
505 | - ncmd = 'exec <"{tmpf}"; rm -f "{tmpf}"; exec "$@"' |
506 | - command = (['sh', '-c', ncmd.format(tmpf=tmpf), 'stdinhack'] + |
507 | - list(command)) |
508 | + env_args = [] |
509 | + if env: |
510 | + env_args = ['env'] + ["%s=%s" for k, v in env.items()] |
511 | |
512 | # ensure instance is running and execute the command |
513 | self.start() |
514 | - # execute returns a ContainerExecuteResult, named tuple |
515 | - # (exit_code, stdout, stderr) |
516 | - res = self.pylxd_container.execute(command, environment=env) |
517 | - |
518 | - # get out, exit and err from pylxd return |
519 | - if not hasattr(res, 'exit_code'): |
520 | - # pylxd 2.1.3 and earlier only return out and err, no exit |
521 | - raise RuntimeError( |
522 | - "No 'exit_code' in pylxd.container.execute return.\n" |
523 | - "pylxd > 2.2 is required.") |
524 | - |
525 | - return res.stdout, res.stderr, res.exit_code |
526 | + |
527 | + # Use cmdline client due to https://github.com/lxc/pylxd/issues/268 |
528 | + exit_code = 0 |
529 | + try: |
530 | + stdout, stderr = subp( |
531 | + ['lxc', 'exec', self.name, '--'] + env_args + list(command), |
532 | + data=stdin, decode=False) |
533 | + except ProcessExecutionError as e: |
534 | + exit_code = e.exit_code |
535 | + stdout = e.stdout |
536 | + stderr = e.stderr |
537 | + |
538 | + return stdout, stderr, exit_code |
539 | |
540 | def read_data(self, remote_path, decode=False): |
541 | """Read data from instance filesystem. |
542 | diff --git a/tests/cloud_tests/testcases.yaml b/tests/cloud_tests/testcases.yaml |
543 | index 7183e01..8e0fb62 100644 |
544 | --- a/tests/cloud_tests/testcases.yaml |
545 | +++ b/tests/cloud_tests/testcases.yaml |
546 | @@ -7,22 +7,37 @@ base_test_data: |
547 | #cloud-config |
548 | collect_scripts: |
549 | cloud-init.log: | |
550 | - #!/bin/bash |
551 | + #!/bin/sh |
552 | cat /var/log/cloud-init.log |
553 | cloud-init-output.log: | |
554 | - #!/bin/bash |
555 | + #!/bin/sh |
556 | cat /var/log/cloud-init-output.log |
557 | instance-id: | |
558 | - #!/bin/bash |
559 | + #!/bin/sh |
560 | cat /run/cloud-init/.instance-id |
561 | result.json: | |
562 | - #!/bin/bash |
563 | + #!/bin/sh |
564 | cat /run/cloud-init/result.json |
565 | status.json: | |
566 | - #!/bin/bash |
567 | + #!/bin/sh |
568 | cat /run/cloud-init/status.json |
569 | cloud-init-version: | |
570 | - #!/bin/bash |
571 | + #!/bin/sh |
572 | dpkg-query -W -f='${Version}' cloud-init |
573 | + system.journal.gz: | |
574 | + #!/bin/sh |
575 | + [ -d /run/systemd ] || { echo "not systemd."; exit 0; } |
576 | + fail() { echo "ERROR:" "$@" 1>&2; exit 1; } |
577 | + journal="" |
578 | + for d in /run/log/journal /var/log/journal; do |
579 | + for f in $d/*/system.journal; do |
580 | + [ -f "$f" ] || continue |
581 | + [ -z "$journal" ] || |
582 | + fail "multiple journal found: $f $journal." |
583 | + journal="$f" |
584 | + done |
585 | + done |
586 | + [ -f "$journal" ] || fail "no journal file found." |
587 | + gzip --to-stdout "$journal" |
588 | |
589 | # vi: ts=4 expandtab |
590 | diff --git a/tests/cloud_tests/testcases/base.py b/tests/cloud_tests/testcases/base.py |
591 | index 1c5b540..20e9595 100644 |
592 | --- a/tests/cloud_tests/testcases/base.py |
593 | +++ b/tests/cloud_tests/testcases/base.py |
594 | @@ -30,12 +30,14 @@ class CloudTestCase(unittest.TestCase): |
595 | raise AssertionError('Key "{}" not in cloud config'.format(name)) |
596 | return self.cloud_config[name] |
597 | |
598 | - def get_data_file(self, name): |
599 | + def get_data_file(self, name, decode=True): |
600 | """Get data file failing test if it is not present.""" |
601 | if name not in self.data: |
602 | raise AssertionError('File "{}" missing from collect data' |
603 | .format(name)) |
604 | - return self.data[name] |
605 | + if not decode: |
606 | + return self.data[name] |
607 | + return self.data[name].decode('utf-8') |
608 | |
609 | def get_instance_id(self): |
610 | """Get recorded instance id.""" |
611 | diff --git a/tests/cloud_tests/verify.py b/tests/cloud_tests/verify.py |
612 | index fc1efcf..2a9fd52 100644 |
613 | --- a/tests/cloud_tests/verify.py |
614 | +++ b/tests/cloud_tests/verify.py |
615 | @@ -29,7 +29,7 @@ def verify_data(base_dir, tests): |
616 | data = {} |
617 | test_dir = os.path.join(base_dir, test_name) |
618 | for script_name in os.listdir(test_dir): |
619 | - with open(os.path.join(test_dir, script_name), 'r') as fp: |
620 | + with open(os.path.join(test_dir, script_name), 'rb') as fp: |
621 | data[script_name] = fp.read() |
622 | |
623 | # get test suite and launch tests |
624 | diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py |
625 | index ad6c5cf..31cc622 100644 |
626 | --- a/tests/unittests/test_ds_identify.py |
627 | +++ b/tests/unittests/test_ds_identify.py |
628 | @@ -338,7 +338,7 @@ class TestDsIdentify(CiTestCase): |
629 | self._test_ds_found('OVF-vmware-customization') |
630 | |
631 | def test_ovf_on_vmware_iso_found_by_cdrom_with_matching_fs_label(self): |
632 | - """OVF is identified when iso9660 cdrom label has ovf-transport.""" |
633 | + """OVF is identified by well-known iso9660 labels.""" |
634 | ovf_cdrom_by_label = copy.deepcopy(VALID_CFG['OVF']) |
635 | # Unset matching cdrom ovf schema content |
636 | ovf_cdrom_by_label['files']['dev/sr0'] = 'No content match' |
637 | @@ -346,10 +346,12 @@ class TestDsIdentify(CiTestCase): |
638 | ovf_cdrom_by_label, rc=RC_NOT_FOUND, policy_dmi="disabled") |
639 | |
640 | # Add recognized labels |
641 | - for valid_fs_label in ['ovf-transport', 'OVF-TRANSPORT']: |
642 | + valid_ovf_labels = ['ovf-transport', 'OVF-TRANSPORT', |
643 | + "OVFENV", "ovfenv"] |
644 | + for valid_ovf_label in valid_ovf_labels: |
645 | ovf_cdrom_by_label['mocks'][0]['out'] = blkid_out([ |
646 | {'DEVNAME': 'sr0', 'TYPE': 'iso9660', |
647 | - 'LABEL': valid_fs_label}]) |
648 | + 'LABEL': valid_ovf_label}]) |
649 | self._check_via_dict( |
650 | ovf_cdrom_by_label, rc=RC_FOUND, dslist=['OVF', DS_NONE]) |
651 | |
652 | diff --git a/tools/ds-identify b/tools/ds-identify |
653 | index 374c3ad..cd26824 100755 |
654 | --- a/tools/ds-identify |
655 | +++ b/tools/ds-identify |
656 | @@ -664,7 +664,9 @@ is_cdrom_ovf() { |
657 | esac |
658 | |
659 | # fast path known 'OVF' labels |
660 | - [ "$label" = "OVF-TRANSPORT" -o "$label" = "ovf-transport" ] && return 0 |
661 | + case "$label" in |
662 | + OVF-TRANSPORT|ovf-transport|OVFENV|ovfenv) return 0;; |
663 | + esac |
664 | |
665 | # explicitly skip known labels of other types. rd_rdfe is azure. |
666 | case "$label" in |
PASSED: Continuous integration, rev:54d70c81669 6155e0b7f719607 5d6dea167d3917 /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 755/
https:/
Executed test runs:
SUCCESS: Checkout
SUCCESS: Unit & Style Tests
SUCCESS: Ubuntu LTS: Build
SUCCESS: Ubuntu LTS: Integration
SUCCESS: MAAS Compatability Testing
IN_PROGRESS: Declarative: Post Actions
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 755/rebuild
https:/