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: | 04abd70b222976007b07afc5b1fa70c0a4de882e | ||||||||||||
Proposed branch: | ~chad.smith/cloud-init:ubuntu/devel | ||||||||||||
Merge into: | cloud-init:ubuntu/devel | ||||||||||||
Diff against target: |
814 lines (+371/-90) 15 files modified
ChangeLog (+52/-0) cloudinit/cmd/tests/test_clean.py (+2/-1) cloudinit/cmd/tests/test_status.py (+2/-1) cloudinit/sources/DataSourceOVF.py (+16/-5) cloudinit/tests/helpers.py (+9/-11) cloudinit/version.py (+1/-1) config/cloud.cfg.tmpl (+2/-0) debian/changelog (+16/-0) tests/cloud_tests/collect.py (+3/-2) tests/cloud_tests/platforms/lxd/instance.py (+106/-26) tests/unittests/test_ds_identify.py (+40/-3) tests/unittests/test_handler/test_schema.py (+7/-5) tools/ds-identify (+34/-19) tools/run-centos (+78/-13) tox.ini (+3/-3) |
||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Server Team CI bot | continuous-integration | Approve | |
Scott Moser | Pending | ||
Review via email: mp+338591@code.launchpad.net |
Commit message
Description of the change
Upstream snapshot for cloud-init master to sync 18.1 release to bionic
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)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/ChangeLog b/ChangeLog | |||
2 | index 31c2dcb..be4c357 100644 | |||
3 | --- a/ChangeLog | |||
4 | +++ b/ChangeLog | |||
5 | @@ -1,3 +1,55 @@ | |||
6 | 1 | 18.1: | ||
7 | 2 | - OVF: Fix VMware support for 64-bit platforms. [Sankar Tanguturi] | ||
8 | 3 | - ds-identify: Fix searching for iso9660 OVF cdroms. (LP: #1749980) | ||
9 | 4 | - SUSE: Fix groups used for ownership of cloud-init.log [Robert Schweikert] | ||
10 | 5 | - ds-identify: check /writable/system-data/ for nocloud seed. | ||
11 | 6 | (LP: #1747070) | ||
12 | 7 | - tests: run nosetests in cloudinit/ directory, fix py26 fallout. | ||
13 | 8 | - tools: run-centos: git clone rather than tar. | ||
14 | 9 | - tests: add support for logs with lxd from snap and future lxd 3. | ||
15 | 10 | (LP: #1745663) | ||
16 | 11 | - EC2: Fix get_instance_id called against cached datasource pickle. | ||
17 | 12 | (LP: #1748354) | ||
18 | 13 | - cli: fix cloud-init status to report running when before result.json | ||
19 | 14 | (LP: #1747965) | ||
20 | 15 | - net: accept network-config in netplan format for renaming interfaces | ||
21 | 16 | (LP: #1709715) | ||
22 | 17 | - Fix ssh keys validation in ssh_util [Tatiana Kholkina] | ||
23 | 18 | - docs: Update RTD content for cloud-init subcommands. | ||
24 | 19 | - OVF: Extend well-known labels to include OVFENV. (LP: #1698669) | ||
25 | 20 | - Fix potential cases of uninitialized variables. (LP: #1744796) | ||
26 | 21 | - tests: Collect script output as binary, collect systemd journal, fix lxd. | ||
27 | 22 | - HACKING.rst: mention setting user name and email via git config. | ||
28 | 23 | - Azure VM Preprovisioning support. [Douglas Jordan] (LP: #1734991) | ||
29 | 24 | - tools/read-version: Fix read-version when in a git worktree. | ||
30 | 25 | - docs: Fix typos in docs and one debug message. [Florian Grignon] | ||
31 | 26 | - btrfs: support resizing if root is mounted ro. | ||
32 | 27 | [Robert Schweikert] (LP: #1734787) | ||
33 | 28 | - OpenNebula: Improve network configuration support. | ||
34 | 29 | [Akihiko Ota] (LP: #1719157, #1716397, #1736750) | ||
35 | 30 | - tests: Fix EC2 Platform to return console output as bytes. | ||
36 | 31 | - tests: Fix attempted use of /run in a test case. | ||
37 | 32 | - GCE: Improvements and changes to ssh key behavior for default user. | ||
38 | 33 | [Max Illfelder] (LP: #1670456, #1707033, #1707037, #1707039) | ||
39 | 34 | - subp: make ProcessExecutionError have expected types in stderr, stdout. | ||
40 | 35 | - tests: when querying ntp server, do not do dns resolution. | ||
41 | 36 | - Recognize uppercase vfat disk labels [James Penick] (LP: #1598783) | ||
42 | 37 | - tests: remove zesty as supported OS to test [Joshua Powers] | ||
43 | 38 | - Do not log warning on config files that represent None. (LP: #1742479) | ||
44 | 39 | - tests: Use git hash pip dependency format for pylxd. | ||
45 | 40 | - tests: add integration requirements text file [Joshua Powers] | ||
46 | 41 | - MAAS: add check_instance_id based off oauth tokens. (LP: #1712680) | ||
47 | 42 | - tests: update apt sources list test [Joshua Powers] | ||
48 | 43 | - tests: clean up image properties [Joshua Powers] | ||
49 | 44 | - tests: rename test ssh keys to avoid appearance of leaking private keys. | ||
50 | 45 | [Joshua Powers] | ||
51 | 46 | - tests: Enable AWS EC2 Integration Testing [Joshua Powers] | ||
52 | 47 | - cli: cloud-init clean handles symlinks (LP: #1741093) | ||
53 | 48 | - SUSE: Add a basic test of network config rendering. [Robert Schweikert] | ||
54 | 49 | - Azure: Only bounce network when necessary. (LP: #1722668) | ||
55 | 50 | - lint: Fix lints seen by pylint version 1.8.1. | ||
56 | 51 | - cli: Fix error in cloud-init modules --mode=init. (LP: #1736600) | ||
57 | 52 | |||
58 | 1 | 17.2: | 53 | 17.2: |
59 | 2 | - ds-identify: failure in NoCloud due to unset variable usage. | 54 | - ds-identify: failure in NoCloud due to unset variable usage. |
60 | 3 | (LP: #1737704) | 55 | (LP: #1737704) |
61 | diff --git a/cloudinit/cmd/tests/test_clean.py b/cloudinit/cmd/tests/test_clean.py | |||
62 | index 6713af4..5a3ec3b 100644 | |||
63 | --- a/cloudinit/cmd/tests/test_clean.py | |||
64 | +++ b/cloudinit/cmd/tests/test_clean.py | |||
65 | @@ -165,10 +165,11 @@ class TestClean(CiTestCase): | |||
66 | 165 | wrap_and_call( | 165 | wrap_and_call( |
67 | 166 | 'cloudinit.cmd.clean', | 166 | 'cloudinit.cmd.clean', |
68 | 167 | {'Init': {'side_effect': self.init_class}, | 167 | {'Init': {'side_effect': self.init_class}, |
69 | 168 | 'sys.exit': {'side_effect': self.sys_exit}, | ||
70 | 168 | 'sys.argv': {'new': ['clean', '--logs']}}, | 169 | 'sys.argv': {'new': ['clean', '--logs']}}, |
71 | 169 | clean.main) | 170 | clean.main) |
72 | 170 | 171 | ||
74 | 171 | self.assertRaisesCodeEqual(0, context_manager.exception.code) | 172 | self.assertEqual(0, context_manager.exception.code) |
75 | 172 | self.assertFalse( | 173 | self.assertFalse( |
76 | 173 | os.path.exists(self.log1), 'Unexpected log {0}'.format(self.log1)) | 174 | os.path.exists(self.log1), 'Unexpected log {0}'.format(self.log1)) |
77 | 174 | 175 | ||
78 | diff --git a/cloudinit/cmd/tests/test_status.py b/cloudinit/cmd/tests/test_status.py | |||
79 | index 4a5a8c0..37a8993 100644 | |||
80 | --- a/cloudinit/cmd/tests/test_status.py | |||
81 | +++ b/cloudinit/cmd/tests/test_status.py | |||
82 | @@ -380,10 +380,11 @@ class TestStatus(CiTestCase): | |||
83 | 380 | wrap_and_call( | 380 | wrap_and_call( |
84 | 381 | 'cloudinit.cmd.status', | 381 | 'cloudinit.cmd.status', |
85 | 382 | {'sys.argv': {'new': ['status']}, | 382 | {'sys.argv': {'new': ['status']}, |
86 | 383 | 'sys.exit': {'side_effect': self.sys_exit}, | ||
87 | 383 | '_is_cloudinit_disabled': (False, ''), | 384 | '_is_cloudinit_disabled': (False, ''), |
88 | 384 | 'Init': {'side_effect': self.init_class}}, | 385 | 'Init': {'side_effect': self.init_class}}, |
89 | 385 | status.main) | 386 | status.main) |
91 | 386 | self.assertRaisesCodeEqual(0, context_manager.exception.code) | 387 | self.assertEqual(0, context_manager.exception.code) |
92 | 387 | self.assertEqual('status: running\n', m_stdout.getvalue()) | 388 | self.assertEqual('status: running\n', m_stdout.getvalue()) |
93 | 388 | 389 | ||
94 | 389 | # vi: ts=4 expandtab syntax=python | 390 | # vi: ts=4 expandtab syntax=python |
95 | diff --git a/cloudinit/sources/DataSourceOVF.py b/cloudinit/sources/DataSourceOVF.py | |||
96 | index 6e62f98..dc914a7 100644 | |||
97 | --- a/cloudinit/sources/DataSourceOVF.py | |||
98 | +++ b/cloudinit/sources/DataSourceOVF.py | |||
99 | @@ -95,11 +95,20 @@ class DataSourceOVF(sources.DataSource): | |||
100 | 95 | "VMware Customization support") | 95 | "VMware Customization support") |
101 | 96 | elif not util.get_cfg_option_bool( | 96 | elif not util.get_cfg_option_bool( |
102 | 97 | self.sys_cfg, "disable_vmware_customization", True): | 97 | self.sys_cfg, "disable_vmware_customization", True): |
108 | 98 | deployPkgPluginPath = search_file("/usr/lib/vmware-tools", | 98 | |
109 | 99 | "libdeployPkgPlugin.so") | 99 | search_paths = ( |
110 | 100 | if not deployPkgPluginPath: | 100 | "/usr/lib/vmware-tools", "/usr/lib64/vmware-tools", |
111 | 101 | deployPkgPluginPath = search_file("/usr/lib/open-vm-tools", | 101 | "/usr/lib/open-vm-tools", "/usr/lib64/open-vm-tools") |
112 | 102 | "libdeployPkgPlugin.so") | 102 | |
113 | 103 | plugin = "libdeployPkgPlugin.so" | ||
114 | 104 | deployPkgPluginPath = None | ||
115 | 105 | for path in search_paths: | ||
116 | 106 | deployPkgPluginPath = search_file(path, plugin) | ||
117 | 107 | if deployPkgPluginPath: | ||
118 | 108 | LOG.debug("Found the customization plugin at %s", | ||
119 | 109 | deployPkgPluginPath) | ||
120 | 110 | break | ||
121 | 111 | |||
122 | 103 | if deployPkgPluginPath: | 112 | if deployPkgPluginPath: |
123 | 104 | # When the VM is powered on, the "VMware Tools" daemon | 113 | # When the VM is powered on, the "VMware Tools" daemon |
124 | 105 | # copies the customization specification file to | 114 | # copies the customization specification file to |
125 | @@ -111,6 +120,8 @@ class DataSourceOVF(sources.DataSource): | |||
126 | 111 | msg="waiting for configuration file", | 120 | msg="waiting for configuration file", |
127 | 112 | func=wait_for_imc_cfg_file, | 121 | func=wait_for_imc_cfg_file, |
128 | 113 | args=("cust.cfg", max_wait)) | 122 | args=("cust.cfg", max_wait)) |
129 | 123 | else: | ||
130 | 124 | LOG.debug("Did not find the customization plugin.") | ||
131 | 114 | 125 | ||
132 | 115 | if vmwareImcConfigFilePath: | 126 | if vmwareImcConfigFilePath: |
133 | 116 | LOG.debug("Found VMware Customization Config File at %s", | 127 | LOG.debug("Found VMware Customization Config File at %s", |
134 | diff --git a/cloudinit/tests/helpers.py b/cloudinit/tests/helpers.py | |||
135 | index 0080c72..41d9a8e 100644 | |||
136 | --- a/cloudinit/tests/helpers.py | |||
137 | +++ b/cloudinit/tests/helpers.py | |||
138 | @@ -173,17 +173,15 @@ class CiTestCase(TestCase): | |||
139 | 173 | dir = self.tmp_dir() | 173 | dir = self.tmp_dir() |
140 | 174 | return os.path.normpath(os.path.abspath(os.path.join(dir, path))) | 174 | return os.path.normpath(os.path.abspath(os.path.join(dir, path))) |
141 | 175 | 175 | ||
153 | 176 | def assertRaisesCodeEqual(self, expected, found): | 176 | def sys_exit(self, code): |
154 | 177 | """Handle centos6 having different context manager for assertRaises. | 177 | """Provide a wrapper around sys.exit for python 2.6 |
155 | 178 | with assertRaises(Exception) as e: | 178 | |
156 | 179 | raise Exception("BOO") | 179 | In 2.6, this code would produce 'cm.exception' with value int(2) |
157 | 180 | 180 | rather than the SystemExit that was raised by sys.exit(2). | |
158 | 181 | centos6 will have e.exception as an integer. | 181 | with assertRaises(SystemExit) as cm: |
159 | 182 | anything nwere will have it as something with a '.code'""" | 182 | sys.exit(2) |
160 | 183 | if isinstance(found, int): | 183 | """ |
161 | 184 | self.assertEqual(expected, found) | 184 | raise SystemExit(code) |
151 | 185 | else: | ||
152 | 186 | self.assertEqual(expected, found.code) | ||
162 | 187 | 185 | ||
163 | 188 | 186 | ||
164 | 189 | class ResourceUsingTestCase(CiTestCase): | 187 | class ResourceUsingTestCase(CiTestCase): |
165 | diff --git a/cloudinit/version.py b/cloudinit/version.py | |||
166 | index be6262d..4a682ad 100644 | |||
167 | --- a/cloudinit/version.py | |||
168 | +++ b/cloudinit/version.py | |||
169 | @@ -4,7 +4,7 @@ | |||
170 | 4 | # | 4 | # |
171 | 5 | # This file is part of cloud-init. See LICENSE file for license information. | 5 | # This file is part of cloud-init. See LICENSE file for license information. |
172 | 6 | 6 | ||
174 | 7 | __VERSION__ = "17.2" | 7 | __VERSION__ = "18.1" |
175 | 8 | 8 | ||
176 | 9 | FEATURES = [ | 9 | FEATURES = [ |
177 | 10 | # supports network config version 1 | 10 | # supports network config version 1 |
178 | diff --git a/config/cloud.cfg.tmpl b/config/cloud.cfg.tmpl | |||
179 | index 32de9c9..fad1184 100644 | |||
180 | --- a/config/cloud.cfg.tmpl | |||
181 | +++ b/config/cloud.cfg.tmpl | |||
182 | @@ -4,6 +4,8 @@ | |||
183 | 4 | 4 | ||
184 | 5 | {% if variant in ["freebsd"] %} | 5 | {% if variant in ["freebsd"] %} |
185 | 6 | syslog_fix_perms: root:wheel | 6 | syslog_fix_perms: root:wheel |
186 | 7 | {% elif variant in ["suse"] %} | ||
187 | 8 | syslog_fix_perms: root:root | ||
188 | 7 | {% endif %} | 9 | {% endif %} |
189 | 8 | # A set of users which may be applied and/or used by various modules | 10 | # A set of users which may be applied and/or used by various modules |
190 | 9 | # when a 'default' entry is found it will reference the 'default_user' | 11 | # when a 'default' entry is found it will reference the 'default_user' |
191 | diff --git a/debian/changelog b/debian/changelog | |||
192 | index abbd5a9..2552bb6 100644 | |||
193 | --- a/debian/changelog | |||
194 | +++ b/debian/changelog | |||
195 | @@ -1,3 +1,19 @@ | |||
196 | 1 | cloud-init (18.1-0ubuntu1) bionic; urgency=medium | ||
197 | 2 | |||
198 | 3 | * New upstream snapshot. | ||
199 | 4 | - release 18.1 (LP: #1751145) | ||
200 | 5 | - OVF: Fix VMware support for 64-bit platforms. [Sankar Tanguturi] | ||
201 | 6 | - ds-identify: Fix searching for iso9660 OVF cdroms. (LP: #1749980) | ||
202 | 7 | - SUSE: Fix groups used for ownership of cloud-init.log [Robert Schweikert] | ||
203 | 8 | - ds-identify: check /writable/system-data/ for nocloud seed. | ||
204 | 9 | (LP: #1747070) | ||
205 | 10 | - tests: run nosetests in cloudinit/ directory, fix py26 fallout. | ||
206 | 11 | - tools: run-centos: git clone rather than tar. | ||
207 | 12 | - tests: add support for logs with lxd from snap and future lxd 3. | ||
208 | 13 | (LP: #1745663) | ||
209 | 14 | |||
210 | 15 | -- Chad Smith <chad.smith@canonical.com> Thu, 22 Feb 2018 15:42:11 -0700 | ||
211 | 16 | |||
212 | 1 | cloud-init (17.2-34-g644048e3-0ubuntu1) bionic; urgency=medium | 17 | cloud-init (17.2-34-g644048e3-0ubuntu1) bionic; urgency=medium |
213 | 2 | 18 | ||
214 | 3 | * New upstream snapshot. | 19 | * New upstream snapshot. |
215 | diff --git a/tests/cloud_tests/collect.py b/tests/cloud_tests/collect.py | |||
216 | index 5ea88e5..d4f9135 100644 | |||
217 | --- a/tests/cloud_tests/collect.py | |||
218 | +++ b/tests/cloud_tests/collect.py | |||
219 | @@ -44,8 +44,9 @@ def collect_console(instance, base_dir): | |||
220 | 44 | LOG.debug('getting console log for %s to %s', instance, logfile) | 44 | LOG.debug('getting console log for %s to %s', instance, logfile) |
221 | 45 | try: | 45 | try: |
222 | 46 | data = instance.console_log() | 46 | data = instance.console_log() |
225 | 47 | except NotImplementedError: | 47 | except NotImplementedError as e: |
226 | 48 | data = b'instance.console_log: not implemented' | 48 | # args[0] is hacky, but thats all I see to get at the message. |
227 | 49 | data = b'NotImplementedError:' + e.args[0].encode() | ||
228 | 49 | with open(logfile, "wb") as fp: | 50 | with open(logfile, "wb") as fp: |
229 | 50 | fp.write(data) | 51 | fp.write(data) |
230 | 51 | 52 | ||
231 | diff --git a/tests/cloud_tests/platforms/lxd/instance.py b/tests/cloud_tests/platforms/lxd/instance.py | |||
232 | index d2d2a1f..0488da5 100644 | |||
233 | --- a/tests/cloud_tests/platforms/lxd/instance.py | |||
234 | +++ b/tests/cloud_tests/platforms/lxd/instance.py | |||
235 | @@ -6,7 +6,9 @@ import os | |||
236 | 6 | import shutil | 6 | import shutil |
237 | 7 | from tempfile import mkdtemp | 7 | from tempfile import mkdtemp |
238 | 8 | 8 | ||
240 | 9 | from cloudinit.util import subp, ProcessExecutionError | 9 | from cloudinit.util import load_yaml, subp, ProcessExecutionError, which |
241 | 10 | from tests.cloud_tests import LOG | ||
242 | 11 | from tests.cloud_tests.util import PlatformError | ||
243 | 10 | 12 | ||
244 | 11 | from ..instances import Instance | 13 | from ..instances import Instance |
245 | 12 | 14 | ||
246 | @@ -15,6 +17,8 @@ class LXDInstance(Instance): | |||
247 | 15 | """LXD container backed instance.""" | 17 | """LXD container backed instance.""" |
248 | 16 | 18 | ||
249 | 17 | platform_name = "lxd" | 19 | platform_name = "lxd" |
250 | 20 | _console_log_method = None | ||
251 | 21 | _console_log_file = None | ||
252 | 18 | 22 | ||
253 | 19 | def __init__(self, platform, name, properties, config, features, | 23 | def __init__(self, platform, name, properties, config, features, |
254 | 20 | pylxd_container): | 24 | pylxd_container): |
255 | @@ -30,8 +34,8 @@ class LXDInstance(Instance): | |||
256 | 30 | super(LXDInstance, self).__init__( | 34 | super(LXDInstance, self).__init__( |
257 | 31 | platform, name, properties, config, features) | 35 | platform, name, properties, config, features) |
258 | 32 | self.tmpd = mkdtemp(prefix="%s-%s" % (type(self).__name__, name)) | 36 | self.tmpd = mkdtemp(prefix="%s-%s" % (type(self).__name__, name)) |
259 | 33 | self._setup_console_log() | ||
260 | 34 | self.name = name | 37 | self.name = name |
261 | 38 | self._setup_console_log() | ||
262 | 35 | 39 | ||
263 | 36 | @property | 40 | @property |
264 | 37 | def pylxd_container(self): | 41 | def pylxd_container(self): |
265 | @@ -39,21 +43,6 @@ class LXDInstance(Instance): | |||
266 | 39 | self._pylxd_container.sync() | 43 | self._pylxd_container.sync() |
267 | 40 | return self._pylxd_container | 44 | return self._pylxd_container |
268 | 41 | 45 | ||
269 | 42 | def _setup_console_log(self): | ||
270 | 43 | logf = os.path.join(self.tmpd, "console.log") | ||
271 | 44 | |||
272 | 45 | # doing this ensures we can read it. Otherwise it ends up root:root. | ||
273 | 46 | with open(logf, "w") as fp: | ||
274 | 47 | fp.write("# %s\n" % self.name) | ||
275 | 48 | |||
276 | 49 | cfg = "lxc.console.logfile=%s" % logf | ||
277 | 50 | orig = self._pylxd_container.config.get('raw.lxc', "") | ||
278 | 51 | if orig: | ||
279 | 52 | orig += "\n" | ||
280 | 53 | self._pylxd_container.config['raw.lxc'] = orig + cfg | ||
281 | 54 | self._pylxd_container.save() | ||
282 | 55 | self._console_log_file = logf | ||
283 | 56 | |||
284 | 57 | def _execute(self, command, stdin=None, env=None): | 46 | def _execute(self, command, stdin=None, env=None): |
285 | 58 | if env is None: | 47 | if env is None: |
286 | 59 | env = {} | 48 | env = {} |
287 | @@ -97,19 +86,80 @@ class LXDInstance(Instance): | |||
288 | 97 | """ | 86 | """ |
289 | 98 | self.pylxd_container.files.put(remote_path, data) | 87 | self.pylxd_container.files.put(remote_path, data) |
290 | 99 | 88 | ||
291 | 89 | @property | ||
292 | 90 | def console_log_method(self): | ||
293 | 91 | if self._console_log_method is not None: | ||
294 | 92 | return self._console_log_method | ||
295 | 93 | |||
296 | 94 | client = which('lxc') | ||
297 | 95 | if not client: | ||
298 | 96 | raise PlatformError("No 'lxc' client.") | ||
299 | 97 | |||
300 | 98 | elif _has_proper_console_support(): | ||
301 | 99 | self._console_log_method = 'show-log' | ||
302 | 100 | elif client.startswith("/snap"): | ||
303 | 101 | self._console_log_method = 'logfile-snap' | ||
304 | 102 | else: | ||
305 | 103 | self._console_log_method = 'logfile-tmp' | ||
306 | 104 | |||
307 | 105 | LOG.debug("Set console log method to %s", self._console_log_method) | ||
308 | 106 | return self._console_log_method | ||
309 | 107 | |||
310 | 108 | def _setup_console_log(self): | ||
311 | 109 | method = self.console_log_method | ||
312 | 110 | if not method.startswith("logfile-"): | ||
313 | 111 | return | ||
314 | 112 | |||
315 | 113 | if method == "logfile-snap": | ||
316 | 114 | log_dir = "/var/snap/lxd/common/consoles" | ||
317 | 115 | if not os.path.exists(log_dir): | ||
318 | 116 | raise PlatformError( | ||
319 | 117 | "Unable to log with snap lxc. Please run:\n" | ||
320 | 118 | " sudo mkdir --mode=1777 -p %s" % log_dir) | ||
321 | 119 | elif method == "logfile-tmp": | ||
322 | 120 | log_dir = "/tmp" | ||
323 | 121 | else: | ||
324 | 122 | raise PlatformError( | ||
325 | 123 | "Unexpected value for console method: %s" % method) | ||
326 | 124 | |||
327 | 125 | # doing this ensures we can read it. Otherwise it ends up root:root. | ||
328 | 126 | log_file = os.path.join(log_dir, self.name) | ||
329 | 127 | with open(log_file, "w") as fp: | ||
330 | 128 | fp.write("# %s\n" % self.name) | ||
331 | 129 | |||
332 | 130 | cfg = "lxc.console.logfile=%s" % log_file | ||
333 | 131 | orig = self._pylxd_container.config.get('raw.lxc', "") | ||
334 | 132 | if orig: | ||
335 | 133 | orig += "\n" | ||
336 | 134 | self._pylxd_container.config['raw.lxc'] = orig + cfg | ||
337 | 135 | self._pylxd_container.save() | ||
338 | 136 | self._console_log_file = log_file | ||
339 | 137 | |||
340 | 100 | def console_log(self): | 138 | def console_log(self): |
341 | 101 | """Console log. | 139 | """Console log. |
342 | 102 | 140 | ||
344 | 103 | @return_value: bytes of this instance’s console | 141 | @return_value: bytes of this instance's console |
345 | 104 | """ | 142 | """ |
354 | 105 | if not os.path.exists(self._console_log_file): | 143 | |
355 | 106 | raise NotImplementedError( | 144 | if self._console_log_file: |
356 | 107 | "Console log '%s' does not exist. If this is a remote " | 145 | if not os.path.exists(self._console_log_file): |
357 | 108 | "lxc, then this is really NotImplementedError. If it is " | 146 | raise NotImplementedError( |
358 | 109 | "A local lxc, then this is a RuntimeError." | 147 | "Console log '%s' does not exist. If this is a remote " |
359 | 110 | "https://github.com/lxc/lxd/issues/1129") | 148 | "lxc, then this is really NotImplementedError. If it is " |
360 | 111 | with open(self._console_log_file, "rb") as fp: | 149 | "A local lxc, then this is a RuntimeError." |
361 | 112 | return fp.read() | 150 | "https://github.com/lxc/lxd/issues/1129") |
362 | 151 | with open(self._console_log_file, "rb") as fp: | ||
363 | 152 | return fp.read() | ||
364 | 153 | |||
365 | 154 | try: | ||
366 | 155 | stdout, stderr = subp( | ||
367 | 156 | ['lxc', 'console', '--show-log', self.name], decode=False) | ||
368 | 157 | return stdout | ||
369 | 158 | except ProcessExecutionError as e: | ||
370 | 159 | raise PlatformError( | ||
371 | 160 | "console log", | ||
372 | 161 | "Console log failed [%d]: stdout=%s stderr=%s" % ( | ||
373 | 162 | e.exit_code, e.stdout, e.stderr)) | ||
374 | 113 | 163 | ||
375 | 114 | def reboot(self, wait=True): | 164 | def reboot(self, wait=True): |
376 | 115 | """Reboot instance.""" | 165 | """Reboot instance.""" |
377 | @@ -146,7 +196,37 @@ class LXDInstance(Instance): | |||
378 | 146 | if self.platform.container_exists(self.name): | 196 | if self.platform.container_exists(self.name): |
379 | 147 | raise OSError('container {} was not properly removed' | 197 | raise OSError('container {} was not properly removed' |
380 | 148 | .format(self.name)) | 198 | .format(self.name)) |
381 | 199 | if self._console_log_file and os.path.exists(self._console_log_file): | ||
382 | 200 | os.unlink(self._console_log_file) | ||
383 | 149 | shutil.rmtree(self.tmpd) | 201 | shutil.rmtree(self.tmpd) |
384 | 150 | super(LXDInstance, self).destroy() | 202 | super(LXDInstance, self).destroy() |
385 | 151 | 203 | ||
386 | 204 | |||
387 | 205 | def _has_proper_console_support(): | ||
388 | 206 | stdout, _ = subp(['lxc', 'info']) | ||
389 | 207 | info = load_yaml(stdout) | ||
390 | 208 | reason = None | ||
391 | 209 | if 'console' not in info.get('api_extensions', []): | ||
392 | 210 | reason = "LXD server does not support console api extension" | ||
393 | 211 | else: | ||
394 | 212 | dver = info.get('environment', {}).get('driver_version', "") | ||
395 | 213 | if dver.startswith("2.") or dver.startwith("1."): | ||
396 | 214 | reason = "LXD Driver version not 3.x+ (%s)" % dver | ||
397 | 215 | else: | ||
398 | 216 | try: | ||
399 | 217 | stdout, stderr = subp(['lxc', 'console', '--help'], | ||
400 | 218 | decode=False) | ||
401 | 219 | if not (b'console' in stdout and b'log' in stdout): | ||
402 | 220 | reason = "no '--log' in lxc console --help" | ||
403 | 221 | except ProcessExecutionError as e: | ||
404 | 222 | reason = "no 'console' command in lxc client" | ||
405 | 223 | |||
406 | 224 | if reason: | ||
407 | 225 | LOG.debug("no console-support: %s", reason) | ||
408 | 226 | return False | ||
409 | 227 | else: | ||
410 | 228 | LOG.debug("console-support looks good") | ||
411 | 229 | return True | ||
412 | 230 | |||
413 | 231 | |||
414 | 152 | # vi: ts=4 expandtab | 232 | # vi: ts=4 expandtab |
415 | diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py | |||
416 | index 31cc622..9be3f96 100644 | |||
417 | --- a/tests/unittests/test_ds_identify.py | |||
418 | +++ b/tests/unittests/test_ds_identify.py | |||
419 | @@ -337,6 +337,16 @@ class TestDsIdentify(CiTestCase): | |||
420 | 337 | """OVF is identified when vmware customization is enabled.""" | 337 | """OVF is identified when vmware customization is enabled.""" |
421 | 338 | self._test_ds_found('OVF-vmware-customization') | 338 | self._test_ds_found('OVF-vmware-customization') |
422 | 339 | 339 | ||
423 | 340 | def test_ovf_on_vmware_iso_found_open_vm_tools_64(self): | ||
424 | 341 | """OVF is identified when open-vm-tools installed in /usr/lib64.""" | ||
425 | 342 | cust64 = copy.deepcopy(VALID_CFG['OVF-vmware-customization']) | ||
426 | 343 | p32 = 'usr/lib/vmware-tools/plugins/vmsvc/libdeployPkgPlugin.so' | ||
427 | 344 | open64 = 'usr/lib64/open-vm-tools/plugins/vmsvc/libdeployPkgPlugin.so' | ||
428 | 345 | cust64['files'][open64] = cust64['files'][p32] | ||
429 | 346 | del cust64['files'][p32] | ||
430 | 347 | return self._check_via_dict( | ||
431 | 348 | cust64, RC_FOUND, dslist=[cust64.get('ds'), DS_NONE]) | ||
432 | 349 | |||
433 | 340 | def test_ovf_on_vmware_iso_found_by_cdrom_with_matching_fs_label(self): | 350 | def test_ovf_on_vmware_iso_found_by_cdrom_with_matching_fs_label(self): |
434 | 341 | """OVF is identified by well-known iso9660 labels.""" | 351 | """OVF is identified by well-known iso9660 labels.""" |
435 | 342 | ovf_cdrom_by_label = copy.deepcopy(VALID_CFG['OVF']) | 352 | ovf_cdrom_by_label = copy.deepcopy(VALID_CFG['OVF']) |
436 | @@ -350,8 +360,10 @@ class TestDsIdentify(CiTestCase): | |||
437 | 350 | "OVFENV", "ovfenv"] | 360 | "OVFENV", "ovfenv"] |
438 | 351 | for valid_ovf_label in valid_ovf_labels: | 361 | for valid_ovf_label in valid_ovf_labels: |
439 | 352 | ovf_cdrom_by_label['mocks'][0]['out'] = blkid_out([ | 362 | ovf_cdrom_by_label['mocks'][0]['out'] = blkid_out([ |
440 | 363 | {'DEVNAME': 'sda1', 'TYPE': 'ext4', 'LABEL': 'rootfs'}, | ||
441 | 353 | {'DEVNAME': 'sr0', 'TYPE': 'iso9660', | 364 | {'DEVNAME': 'sr0', 'TYPE': 'iso9660', |
443 | 354 | 'LABEL': valid_ovf_label}]) | 365 | 'LABEL': valid_ovf_label}, |
444 | 366 | {'DEVNAME': 'vda1', 'TYPE': 'ntfs', 'LABEL': 'data'}]) | ||
445 | 355 | self._check_via_dict( | 367 | self._check_via_dict( |
446 | 356 | ovf_cdrom_by_label, rc=RC_FOUND, dslist=['OVF', DS_NONE]) | 368 | ovf_cdrom_by_label, rc=RC_FOUND, dslist=['OVF', DS_NONE]) |
447 | 357 | 369 | ||
448 | @@ -359,6 +371,14 @@ class TestDsIdentify(CiTestCase): | |||
449 | 359 | """NoCloud is found with iso9660 filesystem on non-cdrom disk.""" | 371 | """NoCloud is found with iso9660 filesystem on non-cdrom disk.""" |
450 | 360 | self._test_ds_found('NoCloud') | 372 | self._test_ds_found('NoCloud') |
451 | 361 | 373 | ||
452 | 374 | def test_nocloud_seed(self): | ||
453 | 375 | """Nocloud seed directory.""" | ||
454 | 376 | self._test_ds_found('NoCloud-seed') | ||
455 | 377 | |||
456 | 378 | def test_nocloud_seed_ubuntu_core_writable(self): | ||
457 | 379 | """Nocloud seed directory ubuntu core writable""" | ||
458 | 380 | self._test_ds_found('NoCloud-seed-ubuntu-core') | ||
459 | 381 | |||
460 | 362 | 382 | ||
461 | 363 | def blkid_out(disks=None): | 383 | def blkid_out(disks=None): |
462 | 364 | """Convert a list of disk dictionaries into blkid content.""" | 384 | """Convert a list of disk dictionaries into blkid content.""" |
463 | @@ -454,6 +474,22 @@ VALID_CFG = { | |||
464 | 454 | 'dev/vdb': 'pretend iso content for cidata\n', | 474 | 'dev/vdb': 'pretend iso content for cidata\n', |
465 | 455 | } | 475 | } |
466 | 456 | }, | 476 | }, |
467 | 477 | 'NoCloud-seed': { | ||
468 | 478 | 'ds': 'NoCloud', | ||
469 | 479 | 'files': { | ||
470 | 480 | os.path.join(P_SEED_DIR, 'nocloud', 'user-data'): 'ud\n', | ||
471 | 481 | os.path.join(P_SEED_DIR, 'nocloud', 'meta-data'): 'md\n', | ||
472 | 482 | } | ||
473 | 483 | }, | ||
474 | 484 | 'NoCloud-seed-ubuntu-core': { | ||
475 | 485 | 'ds': 'NoCloud', | ||
476 | 486 | 'files': { | ||
477 | 487 | os.path.join('writable/system-data', P_SEED_DIR, | ||
478 | 488 | 'nocloud-net', 'user-data'): 'ud\n', | ||
479 | 489 | os.path.join('writable/system-data', P_SEED_DIR, | ||
480 | 490 | 'nocloud-net', 'meta-data'): 'md\n', | ||
481 | 491 | } | ||
482 | 492 | }, | ||
483 | 457 | 'OpenStack': { | 493 | 'OpenStack': { |
484 | 458 | 'ds': 'OpenStack', | 494 | 'ds': 'OpenStack', |
485 | 459 | 'files': {P_PRODUCT_NAME: 'OpenStack Nova\n'}, | 495 | 'files': {P_PRODUCT_NAME: 'OpenStack Nova\n'}, |
486 | @@ -489,8 +525,9 @@ VALID_CFG = { | |||
487 | 489 | 'mocks': [ | 525 | 'mocks': [ |
488 | 490 | {'name': 'blkid', 'ret': 0, | 526 | {'name': 'blkid', 'ret': 0, |
489 | 491 | 'out': blkid_out( | 527 | 'out': blkid_out( |
492 | 492 | [{'DEVNAME': 'vda1', 'TYPE': 'vfat', 'PARTUUID': uuid4()}, | 528 | [{'DEVNAME': 'sr0', 'TYPE': 'iso9660', 'LABEL': ''}, |
493 | 493 | {'DEVNAME': 'sr0', 'TYPE': 'iso9660', 'LABEL': ''}]) | 529 | {'DEVNAME': 'sr1', 'TYPE': 'iso9660', 'LABEL': 'ignoreme'}, |
494 | 530 | {'DEVNAME': 'vda1', 'TYPE': 'vfat', 'PARTUUID': uuid4()}]), | ||
495 | 494 | }, | 531 | }, |
496 | 495 | MOCK_VIRT_IS_VMWARE, | 532 | MOCK_VIRT_IS_VMWARE, |
497 | 496 | ], | 533 | ], |
498 | diff --git a/tests/unittests/test_handler/test_schema.py b/tests/unittests/test_handler/test_schema.py | |||
499 | index 648573f..df67a0e 100644 | |||
500 | --- a/tests/unittests/test_handler/test_schema.py | |||
501 | +++ b/tests/unittests/test_handler/test_schema.py | |||
502 | @@ -336,11 +336,13 @@ class MainTest(CiTestCase): | |||
503 | 336 | 336 | ||
504 | 337 | def test_main_missing_args(self): | 337 | def test_main_missing_args(self): |
505 | 338 | """Main exits non-zero and reports an error on missing parameters.""" | 338 | """Main exits non-zero and reports an error on missing parameters.""" |
511 | 339 | with mock.patch('sys.argv', ['mycmd']): | 339 | with mock.patch('sys.exit', side_effect=self.sys_exit): |
512 | 340 | with mock.patch('sys.stderr', new_callable=StringIO) as m_stderr: | 340 | with mock.patch('sys.argv', ['mycmd']): |
513 | 341 | with self.assertRaises(SystemExit) as context_manager: | 341 | with mock.patch('sys.stderr', new_callable=StringIO) as \ |
514 | 342 | main() | 342 | m_stderr: |
515 | 343 | self.assertEqual('1', str(context_manager.exception)) | 343 | with self.assertRaises(SystemExit) as context_manager: |
516 | 344 | main() | ||
517 | 345 | self.assertEqual(1, context_manager.exception.code) | ||
518 | 344 | self.assertEqual( | 346 | self.assertEqual( |
519 | 345 | 'Expected either --config-file argument or --doc\n', | 347 | 'Expected either --config-file argument or --doc\n', |
520 | 346 | m_stderr.getvalue()) | 348 | m_stderr.getvalue()) |
521 | diff --git a/tools/ds-identify b/tools/ds-identify | |||
522 | index cd26824..ec368d5 100755 | |||
523 | --- a/tools/ds-identify | |||
524 | +++ b/tools/ds-identify | |||
525 | @@ -186,7 +186,8 @@ block_dev_with_label() { | |||
526 | 186 | read_fs_info() { | 186 | read_fs_info() { |
527 | 187 | cached "${DI_BLKID_OUTPUT}" && return 0 | 187 | cached "${DI_BLKID_OUTPUT}" && return 0 |
528 | 188 | # do not rely on links in /dev/disk which might not be present yet. | 188 | # do not rely on links in /dev/disk which might not be present yet. |
530 | 189 | # note that older blkid versions do not report DEVNAME in 'export' output. | 189 | # Note that blkid < 2.22 (centos6, trusty) do not output DEVNAME. |
531 | 190 | # that means that DI_ISO9660_DEVS will not be set. | ||
532 | 190 | if is_container; then | 191 | if is_container; then |
533 | 191 | # blkid will in a container, or at least currently in lxd | 192 | # blkid will in a container, or at least currently in lxd |
534 | 192 | # not provide useful information. | 193 | # not provide useful information. |
535 | @@ -203,21 +204,26 @@ read_fs_info() { | |||
536 | 203 | DI_ISO9660_DEVS="$UNAVAILABLE:error" | 204 | DI_ISO9660_DEVS="$UNAVAILABLE:error" |
537 | 204 | return $ret | 205 | return $ret |
538 | 205 | } | 206 | } |
543 | 206 | IFS="$CR" | 207 | # 'set --' will collapse multiple consecutive entries in IFS for |
544 | 207 | set -- $out | 208 | # whitespace characters (\n, tab, " ") so we cannot rely on getting |
545 | 208 | IFS="$oifs" | 209 | # empty lines in "$@" below. |
546 | 209 | for line in "$@" ""; do | 210 | IFS="$CR"; set -- $out; IFS="$oifs" |
547 | 211 | |||
548 | 212 | for line in "$@"; do | ||
549 | 210 | case "${line}" in | 213 | case "${line}" in |
551 | 211 | DEVNAME=*) dev=${line#DEVNAME=};; | 214 | DEVNAME=*) |
552 | 215 | [ -n "$dev" -a "$ftype" = "iso9660" ] && | ||
553 | 216 | isodevs="${isodevs} ${dev}=$label" | ||
554 | 217 | ftype=""; dev=""; label=""; | ||
555 | 218 | dev=${line#DEVNAME=};; | ||
556 | 212 | LABEL=*) label="${line#LABEL=}"; | 219 | LABEL=*) label="${line#LABEL=}"; |
557 | 213 | labels="${labels}${line#LABEL=}${delim}";; | 220 | labels="${labels}${line#LABEL=}${delim}";; |
558 | 214 | TYPE=*) ftype=${line#TYPE=};; | 221 | TYPE=*) ftype=${line#TYPE=};; |
559 | 215 | "") if [ "$ftype" = "iso9660" ]; then | ||
560 | 216 | isodevs="${isodevs} ${dev}=$label" | ||
561 | 217 | fi | ||
562 | 218 | ftype=""; devname=""; label=""; | ||
563 | 219 | esac | 222 | esac |
564 | 220 | done | 223 | done |
565 | 224 | [ -n "$dev" -a "$ftype" = "iso9660" ] && | ||
566 | 225 | isodevs="${isodevs} ${dev}=$label" | ||
567 | 226 | |||
568 | 221 | DI_FS_LABELS="${labels%${delim}}" | 227 | DI_FS_LABELS="${labels%${delim}}" |
569 | 222 | DI_ISO9660_DEVS="${isodevs# }" | 228 | DI_ISO9660_DEVS="${isodevs# }" |
570 | 223 | } | 229 | } |
571 | @@ -470,6 +476,16 @@ check_seed_dir() { | |||
572 | 470 | return 0 | 476 | return 0 |
573 | 471 | } | 477 | } |
574 | 472 | 478 | ||
575 | 479 | check_writable_seed_dir() { | ||
576 | 480 | # ubuntu core bind-mounts /writable/system-data/var/lib/cloud | ||
577 | 481 | # over the top of /var/lib/cloud, but the mount might not be done yet. | ||
578 | 482 | local wdir="/writable/system-data" | ||
579 | 483 | [ -d "${PATH_ROOT}$wdir" ] || return 1 | ||
580 | 484 | local sdir="${PATH_ROOT}$wdir${PATH_VAR_LIB_CLOUD#${PATH_ROOT}}" | ||
581 | 485 | local PATH_VAR_LIB_CLOUD="$sdir" | ||
582 | 486 | check_seed_dir "$@" | ||
583 | 487 | } | ||
584 | 488 | |||
585 | 473 | probe_floppy() { | 489 | probe_floppy() { |
586 | 474 | cached "${STATE_FLOPPY_PROBED}" && return "${STATE_FLOPPY_PROBED}" | 490 | cached "${STATE_FLOPPY_PROBED}" && return "${STATE_FLOPPY_PROBED}" |
587 | 475 | local fpath=/dev/floppy | 491 | local fpath=/dev/floppy |
588 | @@ -569,6 +585,7 @@ dscheck_NoCloud() { | |||
589 | 569 | esac | 585 | esac |
590 | 570 | for d in nocloud nocloud-net; do | 586 | for d in nocloud nocloud-net; do |
591 | 571 | check_seed_dir "$d" meta-data user-data && return ${DS_FOUND} | 587 | check_seed_dir "$d" meta-data user-data && return ${DS_FOUND} |
592 | 588 | check_writable_seed_dir "$d" meta-data user-data && return ${DS_FOUND} | ||
593 | 572 | done | 589 | done |
594 | 573 | if has_fs_with_label "${fslabel}"; then | 590 | if has_fs_with_label "${fslabel}"; then |
595 | 574 | return ${DS_FOUND} | 591 | return ${DS_FOUND} |
596 | @@ -633,8 +650,9 @@ ovf_vmware_guest_customization() { | |||
597 | 633 | 650 | ||
598 | 634 | # we have to have the plugin to do vmware customization | 651 | # we have to have the plugin to do vmware customization |
599 | 635 | local found="" pkg="" pre="${PATH_ROOT}/usr/lib" | 652 | local found="" pkg="" pre="${PATH_ROOT}/usr/lib" |
600 | 653 | local ppath="plugins/vmsvc/libdeployPkgPlugin.so" | ||
601 | 636 | for pkg in vmware-tools open-vm-tools; do | 654 | for pkg in vmware-tools open-vm-tools; do |
603 | 637 | if [ -f "$pre/$pkg/plugins/vmsvc/libdeployPkgPlugin.so" ]; then | 655 | if [ -f "$pre/$pkg/$ppath" -o -f "${pre}64/$pkg/$ppath" ]; then |
604 | 638 | found="$pkg"; break; | 656 | found="$pkg"; break; |
605 | 639 | fi | 657 | fi |
606 | 640 | done | 658 | done |
607 | @@ -685,15 +703,12 @@ dscheck_OVF() { | |||
608 | 685 | # Azure provides ovf. Skip false positive by dis-allowing. | 703 | # Azure provides ovf. Skip false positive by dis-allowing. |
609 | 686 | is_azure_chassis && return $DS_NOT_FOUND | 704 | is_azure_chassis && return $DS_NOT_FOUND |
610 | 687 | 705 | ||
611 | 688 | local isodevs="${DI_ISO9660_DEVS}" | ||
612 | 689 | case "$isodevs" in | ||
613 | 690 | ""|$UNAVAILABLE:*) return ${DS_NOT_FOUND};; | ||
614 | 691 | esac | ||
615 | 692 | |||
616 | 693 | # DI_ISO9660_DEVS is <device>=label, like /dev/sr0=OVF-TRANSPORT | 706 | # DI_ISO9660_DEVS is <device>=label, like /dev/sr0=OVF-TRANSPORT |
620 | 694 | for tok in $isodevs; do | 707 | if [ "${DI_ISO9660_DEVS#${UNAVAILABLE}:}" = "${DI_ISO9660_DEVS}" ]; then |
621 | 695 | is_cdrom_ovf "${tok%%=*}" "${tok#*=}" && return $DS_FOUND | 708 | for tok in ${DI_ISO9660_DEVS}; do |
622 | 696 | done | 709 | is_cdrom_ovf "${tok%%=*}" "${tok#*=}" && return $DS_FOUND |
623 | 710 | done | ||
624 | 711 | fi | ||
625 | 697 | 712 | ||
626 | 698 | if ovf_vmware_guest_customization; then | 713 | if ovf_vmware_guest_customization; then |
627 | 699 | return ${DS_FOUND} | 714 | return ${DS_FOUND} |
628 | diff --git a/tools/run-centos b/tools/run-centos | |||
629 | index d58ef3e..cb241ee 100755 | |||
630 | --- a/tools/run-centos | |||
631 | +++ b/tools/run-centos | |||
632 | @@ -23,6 +23,9 @@ Usage: ${0##*/} [ options ] version | |||
633 | 23 | 23 | ||
634 | 24 | options: | 24 | options: |
635 | 25 | -a | --artifact keep .rpm artifacts | 25 | -a | --artifact keep .rpm artifacts |
636 | 26 | --dirty apply local changes before running tests. | ||
637 | 27 | If not provided, a clean checkout of branch is tested. | ||
638 | 28 | Inside container, changes are in local-changes.diff. | ||
639 | 26 | -k | --keep keep container after tests | 29 | -k | --keep keep container after tests |
640 | 27 | -r | --rpm build .rpm | 30 | -r | --rpm build .rpm |
641 | 28 | -s | --srpm build .src.rpm | 31 | -s | --srpm build .src.rpm |
642 | @@ -80,25 +83,84 @@ inside() { | |||
643 | 80 | inject_cloud_init(){ | 83 | inject_cloud_init(){ |
644 | 81 | # take current cloud-init git dir and put it inside $name at | 84 | # take current cloud-init git dir and put it inside $name at |
645 | 82 | # ~$user/cloud-init. | 85 | # ~$user/cloud-init. |
649 | 83 | local name="$1" user="$2" top_d="" dname="" pstat="" | 86 | local name="$1" user="$2" dirty="$3" |
650 | 84 | top_d=$(git rev-parse --show-toplevel) || { | 87 | local changes="" top_d="" dname="cloud-init" pstat="" |
651 | 85 | errorrc "Failed to get git top level in $PWD"; | 88 | local gitdir="" commitish="" |
652 | 89 | gitdir=$(git rev-parse --git-dir) || { | ||
653 | 90 | errorrc "Failed to get git dir in $PWD"; | ||
654 | 86 | return | 91 | return |
655 | 87 | } | 92 | } |
659 | 88 | dname=$(basename "${top_d}") || return | 93 | local t=${gitdir%/*} |
660 | 89 | debug 1 "collecting ${top_d} ($dname) into user $user in $name." | 94 | case "$t" in |
661 | 90 | tar -C "${top_d}/.." -cpf - "$dname" | | 95 | */worktrees) |
662 | 96 | if [ -f "${t%worktrees}/config" ]; then | ||
663 | 97 | gitdir="${t%worktrees}" | ||
664 | 98 | fi | ||
665 | 99 | esac | ||
666 | 100 | |||
667 | 101 | # attempt to get branch name. | ||
668 | 102 | commitish=$(git rev-parse --abbrev-ref HEAD) || { | ||
669 | 103 | errorrc "Failed git rev-parse --abbrev-ref HEAD" | ||
670 | 104 | return | ||
671 | 105 | } | ||
672 | 106 | if [ "$commitish" = "HEAD" ]; then | ||
673 | 107 | # detached head | ||
674 | 108 | commitish=$(git rev-parse HEAD) || { | ||
675 | 109 | errorrc "failed git rev-parse HEAD" | ||
676 | 110 | return | ||
677 | 111 | } | ||
678 | 112 | fi | ||
679 | 113 | |||
680 | 114 | local local_changes=false | ||
681 | 115 | if ! git diff --quiet "$commitish"; then | ||
682 | 116 | # there are local changes not committed. | ||
683 | 117 | local_changes=true | ||
684 | 118 | if [ "$dirty" = "false" ]; then | ||
685 | 119 | error "WARNING: You had uncommitted changes. Those changes will " | ||
686 | 120 | error "be put into 'local-changes.diff' inside the container. " | ||
687 | 121 | error "To test these changes you must pass --dirty." | ||
688 | 122 | fi | ||
689 | 123 | fi | ||
690 | 124 | |||
691 | 125 | debug 1 "collecting ${gitdir} ($dname) into user $user in $name." | ||
692 | 126 | tar -C "${gitdir}" -cpf - . | | ||
693 | 91 | inside_as "$name" "$user" sh -ec ' | 127 | inside_as "$name" "$user" sh -ec ' |
694 | 92 | dname=$1 | 128 | dname=$1 |
695 | 129 | commitish=$2 | ||
696 | 93 | rm -Rf "$dname" | 130 | rm -Rf "$dname" |
697 | 131 | mkdir -p $dname/.git | ||
698 | 132 | cd $dname/.git | ||
699 | 94 | tar -xpf - | 133 | tar -xpf - |
702 | 95 | [ "$dname" = "cloud-init" ] || mv "$dname" cloud-init' \ | 134 | cd .. |
703 | 96 | extract "$dname" | 135 | git config core.bare false |
704 | 136 | out=$(git checkout $commitish 2>&1) || | ||
705 | 137 | { echo "failed git checkout $commitish: $out" 1>&2; exit 1; } | ||
706 | 138 | out=$(git checkout . 2>&1) || | ||
707 | 139 | { echo "failed git checkout .: $out" 1>&2; exit 1; } | ||
708 | 140 | ' extract "$dname" "$commitish" | ||
709 | 97 | [ "${PIPESTATUS[*]}" = "0 0" ] || { | 141 | [ "${PIPESTATUS[*]}" = "0 0" ] || { |
711 | 98 | error "Failed to push tarball of '$top_d' into $name" \ | 142 | error "Failed to push tarball of '$gitdir' into $name" \ |
712 | 99 | " for user $user (dname=$dname)" | 143 | " for user $user (dname=$dname)" |
713 | 100 | return 1 | 144 | return 1 |
714 | 101 | } | 145 | } |
715 | 146 | |||
716 | 147 | echo "local_changes=$local_changes dirty=$dirty" | ||
717 | 148 | if [ "$local_changes" = "true" ]; then | ||
718 | 149 | git diff "$commitish" | | ||
719 | 150 | inside_as "$name" "$user" sh -exc ' | ||
720 | 151 | cd "$1" | ||
721 | 152 | if [ "$2" = "true" ]; then | ||
722 | 153 | git apply | ||
723 | 154 | else | ||
724 | 155 | cat > local-changes.diff | ||
725 | 156 | fi | ||
726 | 157 | ' insert_changes "$dname" "$dirty" | ||
727 | 158 | [ "${PIPESTATUS[*]}" = "0 0" ] || { | ||
728 | 159 | error "Failed to apply local changes." | ||
729 | 160 | return 1 | ||
730 | 161 | } | ||
731 | 162 | fi | ||
732 | 163 | |||
733 | 102 | return 0 | 164 | return 0 |
734 | 103 | } | 165 | } |
735 | 104 | 166 | ||
736 | @@ -179,7 +241,7 @@ delete_container() { | |||
737 | 179 | 241 | ||
738 | 180 | main() { | 242 | main() { |
739 | 181 | local short_opts="ahkrsuv" | 243 | local short_opts="ahkrsuv" |
741 | 182 | local long_opts="artifact,help,keep,rpm,srpm,unittest,verbose" | 244 | local long_opts="artifact,dirty,help,keep,rpm,srpm,unittest,verbose" |
742 | 183 | local getopt_out="" | 245 | local getopt_out="" |
743 | 184 | getopt_out=$(getopt --name "${0##*/}" \ | 246 | getopt_out=$(getopt --name "${0##*/}" \ |
744 | 185 | --options "${short_opts}" --long "${long_opts}" -- "$@") && | 247 | --options "${short_opts}" --long "${long_opts}" -- "$@") && |
745 | @@ -188,11 +250,13 @@ main() { | |||
746 | 188 | 250 | ||
747 | 189 | local cur="" next="" | 251 | local cur="" next="" |
748 | 190 | local artifact="" keep="" rpm="" srpm="" unittest="" version="" | 252 | local artifact="" keep="" rpm="" srpm="" unittest="" version="" |
749 | 253 | local dirty=false | ||
750 | 191 | 254 | ||
751 | 192 | while [ $# -ne 0 ]; do | 255 | while [ $# -ne 0 ]; do |
752 | 193 | cur="${1:-}"; next="${2:-}"; | 256 | cur="${1:-}"; next="${2:-}"; |
753 | 194 | case "$cur" in | 257 | case "$cur" in |
754 | 195 | -a|--artifact) artifact=1;; | 258 | -a|--artifact) artifact=1;; |
755 | 259 | --dirty) dirty=true;; | ||
756 | 196 | -h|--help) Usage ; exit 0;; | 260 | -h|--help) Usage ; exit 0;; |
757 | 197 | -k|--keep) KEEP=true;; | 261 | -k|--keep) KEEP=true;; |
758 | 198 | -r|--rpm) rpm=1;; | 262 | -r|--rpm) rpm=1;; |
759 | @@ -231,7 +295,7 @@ main() { | |||
760 | 231 | inside "$name" useradd "$user" | 295 | inside "$name" useradd "$user" |
761 | 232 | 296 | ||
762 | 233 | debug 1 "inserting cloud-init" | 297 | debug 1 "inserting cloud-init" |
764 | 234 | inject_cloud_init "$name" "$user" || { | 298 | inject_cloud_init "$name" "$user" "$dirty" || { |
765 | 235 | errorrc "FAIL: injecting cloud-init into $name failed." | 299 | errorrc "FAIL: injecting cloud-init into $name failed." |
766 | 236 | return | 300 | return |
767 | 237 | } | 301 | } |
768 | @@ -244,12 +308,13 @@ main() { | |||
769 | 244 | 308 | ||
770 | 245 | local errors=0 | 309 | local errors=0 |
771 | 246 | inside_as_cd "$name" "$user" "$cdir" \ | 310 | inside_as_cd "$name" "$user" "$cdir" \ |
773 | 247 | sh -ec "git checkout .; git status" || | 311 | sh -ec "git status" || |
774 | 248 | { errorrc "git checkout failed."; errors=$(($errors+1)); } | 312 | { errorrc "git checkout failed."; errors=$(($errors+1)); } |
775 | 249 | 313 | ||
776 | 250 | if [ -n "$unittest" ]; then | 314 | if [ -n "$unittest" ]; then |
777 | 251 | debug 1 "running unit tests." | 315 | debug 1 "running unit tests." |
779 | 252 | inside_as_cd "$name" "$user" "$cdir" nosetests tests/unittests || | 316 | inside_as_cd "$name" "$user" "$cdir" \ |
780 | 317 | nosetests tests/unittests cloudinit || | ||
781 | 253 | { errorrc "nosetests failed."; errors=$(($errors+1)); } | 318 | { errorrc "nosetests failed."; errors=$(($errors+1)); } |
782 | 254 | fi | 319 | fi |
783 | 255 | 320 | ||
784 | diff --git a/tox.ini b/tox.ini | |||
785 | index bb74853..1f990af 100644 | |||
786 | --- a/tox.ini | |||
787 | +++ b/tox.ini | |||
788 | @@ -45,7 +45,7 @@ deps = -r{toxinidir}/test-requirements.txt | |||
789 | 45 | 45 | ||
790 | 46 | [testenv:py26] | 46 | [testenv:py26] |
791 | 47 | deps = -r{toxinidir}/test-requirements.txt | 47 | deps = -r{toxinidir}/test-requirements.txt |
793 | 48 | commands = nosetests {posargs:tests/unittests} | 48 | commands = nosetests {posargs:tests/unittests cloudinit} |
794 | 49 | setenv = | 49 | setenv = |
795 | 50 | LC_ALL = C | 50 | LC_ALL = C |
796 | 51 | 51 | ||
797 | @@ -83,7 +83,7 @@ deps = | |||
798 | 83 | 83 | ||
799 | 84 | [testenv:centos6] | 84 | [testenv:centos6] |
800 | 85 | basepython = python2.6 | 85 | basepython = python2.6 |
802 | 86 | commands = nosetests {posargs:tests/unittests} | 86 | commands = nosetests {posargs:tests/unittests cloudinit} |
803 | 87 | deps = | 87 | deps = |
804 | 88 | # requirements | 88 | # requirements |
805 | 89 | argparse==1.2.1 | 89 | argparse==1.2.1 |
806 | @@ -98,7 +98,7 @@ deps = | |||
807 | 98 | 98 | ||
808 | 99 | [testenv:opensusel42] | 99 | [testenv:opensusel42] |
809 | 100 | basepython = python2.7 | 100 | basepython = python2.7 |
811 | 101 | commands = nosetests {posargs:tests/unittests} | 101 | commands = nosetests {posargs:tests/unittests cloudinit} |
812 | 102 | deps = | 102 | deps = |
813 | 103 | # requirements | 103 | # requirements |
814 | 104 | argparse==1.3.0 | 104 | argparse==1.3.0 |
PASSED: Continuous integration, rev:04abd70b222 976007b07afc5b1 fa70c0a4de882e /jenkins. ubuntu. com/server/ job/cloud- init-ci/ 785/
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/ 785/rebuild
https:/