Merge ~smoser/curtin:ubuntu/devel-20180607 into curtin:ubuntu/devel
- Git
- lp:~smoser/curtin
- ubuntu/devel-20180607
- Merge into ubuntu/devel
Status: | Merged |
---|---|
Merged at revision: | b78e920506bdd55e374a8337910301fe10a704f7 |
Proposed branch: | ~smoser/curtin:ubuntu/devel-20180607 |
Merge into: | curtin:ubuntu/devel |
Diff against target: |
560 lines (+234/-38) 15 files modified
curtin/commands/curthooks.py (+2/-2) curtin/commands/extract.py (+1/-1) curtin/commands/install.py (+16/-5) curtin/url_helper.py (+1/-1) curtin/util.py (+9/-4) debian/changelog (+16/-0) tests/unittests/test_commands_collect_logs.py (+26/-14) tests/unittests/test_commands_extract.py (+72/-0) tests/unittests/test_commands_install.py (+40/-0) tests/unittests/test_util.py (+1/-1) tests/vmtests/__init__.py (+1/-1) tests/vmtests/image_sync.py (+1/-1) tools/curtainer (+21/-6) tools/vmtest-sync-images (+0/-1) tox.ini (+27/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ryan Harper (community) | Approve | ||
Server Team CI bot | continuous-integration | Approve | |
Review via email: mp+347635@code.launchpad.net |
Commit message
+curtin (18.1-25-
+
+ * New upstream snapshot.
+ - Fix WorkingDir class to support already existing target directory.
+ (LP: #1775622)
+ - Fix extraction of local filesystem image. (LP: #1775630)
+ - Fix tip-pyflakes imported but unused call to util.get_
+ - subp: update return value of subp with combine_
+ - tox: add a xenial environments, default envlist changes.
+ - tests: Fix race on utcnow during timestamped curtin-log dir creation
+ (LP: #1772481)
+ - curtainer: patch source version from --source.
+ - pyflakes: fix unused variable references identified by pyflakes 2.0.0.
+
+ -- Scott Moser <email address hidden> Thu, 07 Jun 2018 14:59:20 -0400
Description of the change
Server Team CI bot (server-team-bot) wrote : | # |
Preview Diff
1 | diff --git a/curtin/commands/curthooks.py b/curtin/commands/curthooks.py |
2 | index d45c3a8..a514560 100644 |
3 | --- a/curtin/commands/curthooks.py |
4 | +++ b/curtin/commands/curthooks.py |
5 | @@ -292,7 +292,7 @@ def setup_grub(cfg, target): |
6 | storage_cfg_odict = None |
7 | try: |
8 | storage_cfg_odict = extract_storage_ordered_dict(cfg) |
9 | - except ValueError as e: |
10 | + except ValueError: |
11 | pass |
12 | |
13 | if storage_cfg_odict: |
14 | @@ -324,7 +324,7 @@ def setup_grub(cfg, target): |
15 | try: |
16 | (blockdev, part) = block.get_blockdev_for_partition(maybepart) |
17 | blockdevs.add(blockdev) |
18 | - except ValueError as e: |
19 | + except ValueError: |
20 | # if there is no syspath for this device such as a lvm |
21 | # or raid device, then a ValueError is raised here. |
22 | LOG.debug("failed to find block device for %s", maybepart) |
23 | diff --git a/curtin/commands/extract.py b/curtin/commands/extract.py |
24 | index 69a9d18..ec7a791 100644 |
25 | --- a/curtin/commands/extract.py |
26 | +++ b/curtin/commands/extract.py |
27 | @@ -59,7 +59,7 @@ def extract_root_tgz_url(url, target): |
28 | def extract_root_fsimage_url(url, target): |
29 | path = _path_from_file_url(url) |
30 | if path != url or os.path.isfile(path): |
31 | - return _extract_root_fsimage(path(url), target) |
32 | + return _extract_root_fsimage(path, target) |
33 | |
34 | wfp = tempfile.NamedTemporaryFile(suffix=".img", delete=False) |
35 | wfp.close() |
36 | diff --git a/curtin/commands/install.py b/curtin/commands/install.py |
37 | index a8c4cf9..9e5406c 100644 |
38 | --- a/curtin/commands/install.py |
39 | +++ b/curtin/commands/install.py |
40 | @@ -111,12 +111,22 @@ class WorkingDir(object): |
41 | def __init__(self, config): |
42 | top_d = tempfile.mkdtemp() |
43 | state_d = os.path.join(top_d, 'state') |
44 | + scratch_d = os.path.join(top_d, 'scratch') |
45 | + for p in (state_d, scratch_d): |
46 | + os.mkdir(p) |
47 | + |
48 | target_d = config.get('install', {}).get('target') |
49 | if not target_d: |
50 | target_d = os.path.join(top_d, 'target') |
51 | - scratch_d = os.path.join(top_d, 'scratch') |
52 | - for p in (state_d, target_d, scratch_d): |
53 | - os.mkdir(p) |
54 | + try: |
55 | + util.ensure_dir(target_d) |
56 | + except OSError as e: |
57 | + raise ValueError( |
58 | + "Unable to create target directory '%s': %s" % |
59 | + (target_d, e)) |
60 | + if os.listdir(target_d) != []: |
61 | + raise ValueError( |
62 | + "Provided target dir '%s' was not empty." % target_d) |
63 | |
64 | netconf_f = os.path.join(state_d, 'network_config') |
65 | netstate_f = os.path.join(state_d, 'network_state') |
66 | @@ -429,6 +439,7 @@ def cmd_install(args): |
67 | |
68 | writeline_and_stdout(logfile, INSTALL_START_MSG) |
69 | args.reportstack.post_files = post_files |
70 | + workingd = None |
71 | try: |
72 | workingd = WorkingDir(cfg) |
73 | dd_images = util.get_dd_images(cfg.get('sources', {})) |
74 | @@ -469,12 +480,12 @@ def cmd_install(args): |
75 | raise e |
76 | finally: |
77 | log_target_path = instcfg.get('save_install_log', SAVE_INSTALL_LOG) |
78 | - if log_target_path: |
79 | + if log_target_path and workingd: |
80 | copy_install_log(logfile, workingd.target, log_target_path) |
81 | |
82 | if instcfg.get('unmount', "") == "disabled": |
83 | LOG.info('Skipping unmount: config disabled target unmounting') |
84 | - else: |
85 | + elif workingd: |
86 | # unmount everything (including iscsi disks) |
87 | util.do_umount(workingd.target, recursive=True) |
88 | |
89 | diff --git a/curtin/url_helper.py b/curtin/url_helper.py |
90 | index d4d43a9..43c5c36 100644 |
91 | --- a/curtin/url_helper.py |
92 | +++ b/curtin/url_helper.py |
93 | @@ -227,7 +227,7 @@ def geturl(url, headers=None, headers_cb=None, exception_cb=None, |
94 | try: |
95 | return _geturl(url=url, headers=headers, headers_cb=headers_cb, |
96 | exception_cb=exception_cb, data=data) |
97 | - except _ReRaisedException as e: |
98 | + except _ReRaisedException: |
99 | raise curexc.exc |
100 | except Exception as e: |
101 | curexc = e |
102 | diff --git a/curtin/util.py b/curtin/util.py |
103 | index de0eb88..7d06c09 100644 |
104 | --- a/curtin/util.py |
105 | +++ b/curtin/util.py |
106 | @@ -103,10 +103,11 @@ def _subp(args, data=None, rcs=None, env=None, capture=False, |
107 | (out, err) = sp.communicate(data) |
108 | |
109 | # Just ensure blank instead of none. |
110 | - if not out and capture: |
111 | - out = b'' |
112 | - if not err and capture: |
113 | - err = b'' |
114 | + if capture or combine_capture: |
115 | + if not out: |
116 | + out = b'' |
117 | + if not err: |
118 | + err = b'' |
119 | if decode: |
120 | def ldecode(data, m='utf-8'): |
121 | if not isinstance(data, bytes): |
122 | @@ -206,6 +207,8 @@ def subp(*args, **kwargs): |
123 | boolean indicating if stderr should be redirected to stdout. When True, |
124 | interleaved stderr and stdout will be returned as the first element of |
125 | a tuple. |
126 | + if combine_capture is True, then output is captured independent of |
127 | + the value of capture. |
128 | :param log_captured: |
129 | boolean indicating if output should be logged on capture. If |
130 | True, then stderr and stdout will be logged at DEBUG level. If |
131 | @@ -521,6 +524,8 @@ def do_umount(mountpoint, recursive=False): |
132 | |
133 | |
134 | def ensure_dir(path, mode=None): |
135 | + if path == "": |
136 | + path = "." |
137 | try: |
138 | os.makedirs(path) |
139 | except OSError as e: |
140 | diff --git a/debian/changelog b/debian/changelog |
141 | index d7e9a49..dfd5560 100644 |
142 | --- a/debian/changelog |
143 | +++ b/debian/changelog |
144 | @@ -1,3 +1,19 @@ |
145 | +curtin (18.1-25-g9d0e557e-0ubuntu1) cosmic; urgency=medium |
146 | + |
147 | + * New upstream snapshot. |
148 | + - Fix WorkingDir class to support already existing target directory. |
149 | + (LP: #1775622) |
150 | + - Fix extraction of local filesystem image. (LP: #1775630) |
151 | + - Fix tip-pyflakes imported but unused call to util.get_platform_arch |
152 | + - subp: update return value of subp with combine_capture=True. |
153 | + - tox: add a xenial environments, default envlist changes. |
154 | + - tests: Fix race on utcnow during timestamped curtin-log dir creation |
155 | + (LP: #1772481) |
156 | + - curtainer: patch source version from --source. |
157 | + - pyflakes: fix unused variable references identified by pyflakes 2.0.0. |
158 | + |
159 | + -- Scott Moser <smoser@ubuntu.com> Thu, 07 Jun 2018 14:59:20 -0400 |
160 | + |
161 | curtin (18.1-17-gae48e86f-0ubuntu1) cosmic; urgency=medium |
162 | |
163 | * New upstream snapshot. |
164 | diff --git a/tests/unittests/test_commands_collect_logs.py b/tests/unittests/test_commands_collect_logs.py |
165 | index bab36ae..6b958f4 100644 |
166 | --- a/tests/unittests/test_commands_collect_logs.py |
167 | +++ b/tests/unittests/test_commands_collect_logs.py |
168 | @@ -56,11 +56,12 @@ class TestCollectLogs(CiTestCase): |
169 | write_file(savefile, 'install:\n log_file: /tmp/savefile.log\n') |
170 | packdir = self.tmp_path('configs', _dir=self.new_root) |
171 | ensure_dir(packdir) |
172 | - date = datetime.utcnow().strftime('%Y-%m-%d-%H-%M') |
173 | unusedcfg = os.path.join(packdir, 'config-001.yaml') |
174 | write_file(unusedcfg, 'install:\n log_file: /tmp/unused.log\n') |
175 | - curtin_config = self.tmp_path( |
176 | - 'curtin-logs-%s/curtin-config' % date, _dir=self.tmpdir) |
177 | + utcnow = datetime.utcnow() |
178 | + datestr = utcnow.strftime('%Y-%m-%d-%H-%M') |
179 | + tardir = self.tmp_path('curtin-logs-%s' % datestr, _dir=self.tmpdir) |
180 | + curtin_config = self.tmp_path('curtin-config', _dir=tardir) |
181 | |
182 | self.assertEqual( |
183 | '/curtin/configs', collect_logs.CURTIN_PACK_CONFIG_DIR) |
184 | @@ -72,8 +73,10 @@ class TestCollectLogs(CiTestCase): |
185 | new=packdir, autospec=None) |
186 | self.add_patch('shutil.rmtree', 'm_rmtree') |
187 | with mock.patch('sys.stderr'): |
188 | - with self.assertRaises(SystemExit) as context_manager: |
189 | - collect_logs.collect_logs_main(FakeArgs('my.tar')) |
190 | + with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: |
191 | + with self.assertRaises(SystemExit) as context_manager: |
192 | + m_dt.utcnow.return_value = utcnow |
193 | + collect_logs.collect_logs_main(FakeArgs('my.tar')) |
194 | self.assertEqual('0', str(context_manager.exception)) |
195 | expected_cfg = {'install': {'log_file': '/tmp/savefile.log'}} |
196 | with open(curtin_config, 'r') as f: |
197 | @@ -83,8 +86,9 @@ class TestCollectLogs(CiTestCase): |
198 | """collect_logs_main sources all configs from /curtin/configs dir.""" |
199 | savefile = self.tmp_path('absentinstall.log', _dir=self.new_root) |
200 | packdir = self.tmp_path('configs', _dir=self.new_root) |
201 | - date = datetime.utcnow().strftime('%Y-%m-%d-%H-%M') |
202 | - tardir = self.tmp_path('curtin-logs-%s' % date, _dir=self.tmpdir) |
203 | + utcnow = datetime.utcnow() |
204 | + datestr = utcnow.strftime('%Y-%m-%d-%H-%M') |
205 | + tardir = self.tmp_path('curtin-logs-%s' % datestr, _dir=self.tmpdir) |
206 | ensure_dir(packdir) |
207 | cfg1 = os.path.join(packdir, 'config-001.yaml') |
208 | cfg2 = os.path.join(packdir, 'config-002.yaml') |
209 | @@ -101,8 +105,10 @@ class TestCollectLogs(CiTestCase): |
210 | new=packdir, autospec=None) |
211 | self.add_patch('shutil.rmtree', 'm_rmtree') |
212 | with mock.patch('sys.stderr'): |
213 | - with self.assertRaises(SystemExit) as context_manager: |
214 | - collect_logs.collect_logs_main(FakeArgs('my.tar')) |
215 | + with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: |
216 | + with self.assertRaises(SystemExit) as context_manager: |
217 | + m_dt.utcnow.return_value = utcnow |
218 | + collect_logs.collect_logs_main(FakeArgs('my.tar')) |
219 | self.assertEqual('0', str(context_manager.exception)) |
220 | self.assertEqual(['config-001.yaml', 'config-002.yaml'], |
221 | sorted(os.listdir(packdir))) |
222 | @@ -232,8 +238,8 @@ class TestCreateTar(CiTestCase): |
223 | def setUp(self): |
224 | super(TestCreateTar, self).setUp() |
225 | self.new_root = self.tmp_dir() |
226 | - date = datetime.utcnow().strftime('%Y-%m-%d-%H-%M') |
227 | - self.tardir = 'curtin-logs-%s' % date |
228 | + self.utcnow = datetime.utcnow() |
229 | + self.tardir = 'curtin-logs-%s' % self.utcnow.strftime('%Y-%m-%d-%H-%M') |
230 | self.add_patch( |
231 | 'curtin.commands.collect_logs._collect_system_info', 'm_sys_info') |
232 | self.tmpdir = self.tmp_path('mytemp', _dir=self.new_root) |
233 | @@ -247,7 +253,9 @@ class TestCreateTar(CiTestCase): |
234 | self.add_patch('curtin.util.subp', 'mock_subp') |
235 | self.mock_subp.return_value = ('', '') |
236 | with mock.patch('sys.stderr'): |
237 | - collect_logs.create_log_tarfile(tarfile, config={}) |
238 | + with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: |
239 | + m_dt.utcnow.return_value = self.utcnow |
240 | + collect_logs.create_log_tarfile(tarfile, config={}) |
241 | self.assertIn( |
242 | mock.call(['tar', '-cvf', tarfile, self.tardir], |
243 | capture=True), |
244 | @@ -264,7 +272,9 @@ class TestCreateTar(CiTestCase): |
245 | self.add_patch('curtin.util.subp', 'mock_subp') |
246 | self.mock_subp.return_value = ('', '') |
247 | with mock.patch('sys.stderr'): |
248 | - collect_logs.create_log_tarfile(tarfile, config={}) |
249 | + with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: |
250 | + m_dt.utcnow.return_value = self.utcnow |
251 | + collect_logs.create_log_tarfile(tarfile, config={}) |
252 | self.assertIn( |
253 | mock.call(['tar', '-cvf', tarfile, self.tardir], |
254 | capture=True), |
255 | @@ -311,7 +321,9 @@ class TestCreateTar(CiTestCase): |
256 | 'maas': {'consumer_key': 'ckey', |
257 | 'token_key': 'tkey', 'token_secret': 'tsecret'}}} |
258 | with mock.patch('sys.stderr'): |
259 | - collect_logs.create_log_tarfile(tarfile, config=config) |
260 | + with mock.patch('curtin.commands.collect_logs.datetime') as m_dt: |
261 | + m_dt.utcnow.return_value = self.utcnow |
262 | + collect_logs.create_log_tarfile(tarfile, config=config) |
263 | self.assertEqual( |
264 | [mock.call(self.tardir, ['ckey', 'tkey', 'tsecret'])], |
265 | self.m_redact.call_args_list) |
266 | diff --git a/tests/unittests/test_commands_extract.py b/tests/unittests/test_commands_extract.py |
267 | new file mode 100644 |
268 | index 0000000..e604d7f |
269 | --- /dev/null |
270 | +++ b/tests/unittests/test_commands_extract.py |
271 | @@ -0,0 +1,72 @@ |
272 | +# This file is part of curtin. See LICENSE file for copyright and license info. |
273 | +import os |
274 | + |
275 | +from .helpers import CiTestCase |
276 | + |
277 | +from curtin import util |
278 | +from curtin.commands.extract import extract_root_fsimage_url |
279 | + |
280 | + |
281 | +class TestExtractRootFsImageUrl(CiTestCase): |
282 | + """Test extract_root_fsimage_url.""" |
283 | + def _fake_download(self, url, path): |
284 | + self.downloads.append(os.path.abspath(path)) |
285 | + with open(path, "w") as fp: |
286 | + fp.write("fake content from " + url + "\n") |
287 | + |
288 | + def setUp(self): |
289 | + super(TestExtractRootFsImageUrl, self).setUp() |
290 | + self.downloads = [] |
291 | + self.add_patch("curtin.commands.extract.url_helper.download", |
292 | + "m_download", side_effect=self._fake_download) |
293 | + self.add_patch("curtin.commands.extract._extract_root_fsimage", |
294 | + "m__extract_root_fsimage") |
295 | + |
296 | + def test_relative_file_url(self): |
297 | + """extract_root_fsimage_url supports relative file:// urls.""" |
298 | + tmpd = self.tmp_dir() |
299 | + target = self.tmp_path("target_d", tmpd) |
300 | + startdir = os.getcwd() |
301 | + try: |
302 | + fname = "my.img" |
303 | + util.write_file(fname, fname + " data\n") |
304 | + extract_root_fsimage_url("file://" + fname, target) |
305 | + finally: |
306 | + os.chdir(startdir) |
307 | + self.assertEqual(1, self.m__extract_root_fsimage.call_count) |
308 | + self.assertEqual(0, self.m_download.call_count) |
309 | + |
310 | + def test_absolute_file_url(self): |
311 | + """extract_root_fsimage_url supports absolute file:/// urls.""" |
312 | + tmpd = self.tmp_dir() |
313 | + target = self.tmp_path("target_d", tmpd) |
314 | + fpath = self.tmp_path("my.img", tmpd) |
315 | + util.write_file(fpath, fpath + " data\n") |
316 | + extract_root_fsimage_url("file://" + fpath, target) |
317 | + self.assertEqual(1, self.m__extract_root_fsimage.call_count) |
318 | + self.assertEqual(0, self.m_download.call_count) |
319 | + |
320 | + def test_http_url(self): |
321 | + """extract_root_fsimage_url supports http:// urls.""" |
322 | + tmpd = self.tmp_dir() |
323 | + target = self.tmp_path("target_d", tmpd) |
324 | + myurl = "http://bogus.example.com/my.img" |
325 | + extract_root_fsimage_url(myurl, target) |
326 | + self.assertEqual(1, self.m__extract_root_fsimage.call_count) |
327 | + self.assertEqual(1, self.m_download.call_count) |
328 | + # ensure the file got cleaned up. |
329 | + self.assertEqual(1, len(self.downloads)) |
330 | + self.assertEqual([], [f for f in self.downloads if os.path.exists(f)]) |
331 | + |
332 | + def test_file_path_not_url(self): |
333 | + """extract_root_fsimage_url supports normal file path without file:.""" |
334 | + tmpd = self.tmp_dir() |
335 | + target = self.tmp_path("target_d", tmpd) |
336 | + fpath = self.tmp_path("my.img", tmpd) |
337 | + util.write_file(fpath, fpath + " data\n") |
338 | + extract_root_fsimage_url(os.path.abspath(fpath), target) |
339 | + self.assertEqual(1, self.m__extract_root_fsimage.call_count) |
340 | + self.assertEqual(0, self.m_download.call_count) |
341 | + |
342 | + |
343 | +# vi: ts=4 expandtab syntax=python |
344 | diff --git a/tests/unittests/test_commands_install.py b/tests/unittests/test_commands_install.py |
345 | index 47f4497..9a64a79 100644 |
346 | --- a/tests/unittests/test_commands_install.py |
347 | +++ b/tests/unittests/test_commands_install.py |
348 | @@ -189,3 +189,43 @@ class TestCmdInstall(CiTestCase): |
349 | self.assertEqual( |
350 | [mock.call(self.logfile, target_dir, '/root/curtin-install.log')], |
351 | self.m_copy_log.call_args_list) |
352 | + |
353 | + |
354 | +class TestWorkingDir(CiTestCase): |
355 | + def test_target_dir_may_exist(self): |
356 | + """WorkingDir supports existing empty target directory.""" |
357 | + tmp_d = self.tmp_dir() |
358 | + work_d = self.tmp_path("work_d", tmp_d) |
359 | + target_d = self.tmp_path("target_d", tmp_d) |
360 | + ensure_dir(work_d) |
361 | + ensure_dir(target_d) |
362 | + with mock.patch("curtin.commands.install.tempfile.mkdtemp", |
363 | + return_value=work_d) as m_mkdtemp: |
364 | + workingdir = install.WorkingDir({'install': {'target': target_d}}) |
365 | + self.assertEqual(1, m_mkdtemp.call_count) |
366 | + self.assertEqual(target_d, workingdir.target) |
367 | + self.assertEqual(target_d, workingdir.env().get('TARGET_MOUNT_POINT')) |
368 | + |
369 | + def test_target_dir_with_content_raises_error(self): |
370 | + """WorkingDir raises ValueError on populated target_d.""" |
371 | + tmp_d = self.tmp_dir() |
372 | + work_d = self.tmp_path("work_d", tmp_d) |
373 | + target_d = self.tmp_path("target_d", tmp_d) |
374 | + ensure_dir(work_d) |
375 | + ensure_dir(target_d) |
376 | + write_file(self.tmp_path("somefile.txt", target_d), "sometext") |
377 | + with mock.patch("curtin.commands.install.tempfile.mkdtemp", |
378 | + return_value=work_d): |
379 | + with self.assertRaises(ValueError): |
380 | + install.WorkingDir({'install': {'target': target_d}}) |
381 | + |
382 | + def test_target_dir_by_default_is_under_workd(self): |
383 | + """WorkingDir does not require target in config.""" |
384 | + tmp_d = self.tmp_dir() |
385 | + work_d = self.tmp_path("work_d", tmp_d) |
386 | + ensure_dir(work_d) |
387 | + with mock.patch("curtin.commands.install.tempfile.mkdtemp", |
388 | + return_value=work_d) as m_mkdtemp: |
389 | + wd = install.WorkingDir({}) |
390 | + self.assertEqual(1, m_mkdtemp.call_count) |
391 | + self.assertTrue(wd.target.startswith(work_d + "/")) |
392 | diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py |
393 | index 65175c5..483cd5d 100644 |
394 | --- a/tests/unittests/test_util.py |
395 | +++ b/tests/unittests/test_util.py |
396 | @@ -260,7 +260,7 @@ class TestSubp(CiTestCase): |
397 | data = b'hello world' |
398 | (out, err) = util.subp(self.stdin2err, combine_capture=True, |
399 | decode=False, data=data) |
400 | - self.assertIsNone(err) |
401 | + self.assertEqual(err, b'') |
402 | self.assertEqual(out, data) |
403 | |
404 | def test_returns_none_if_no_capture(self): |
405 | diff --git a/tests/vmtests/__init__.py b/tests/vmtests/__init__.py |
406 | index 5c30a83..0c3d17e 100644 |
407 | --- a/tests/vmtests/__init__.py |
408 | +++ b/tests/vmtests/__init__.py |
409 | @@ -1091,7 +1091,7 @@ class VMBaseClass(TestCase): |
410 | # mount output disk |
411 | try: |
412 | cls.collect_output() |
413 | - except Exception as e: |
414 | + except Exception: |
415 | cls.tearDownClass() |
416 | raise |
417 | |
418 | diff --git a/tests/vmtests/image_sync.py b/tests/vmtests/image_sync.py |
419 | index bbe523a..e2cedc1 100644 |
420 | --- a/tests/vmtests/image_sync.py |
421 | +++ b/tests/vmtests/image_sync.py |
422 | @@ -174,7 +174,7 @@ class CurtinVmTestMirror(mirrors.ObjectFilterMirror): |
423 | except IOError as e: |
424 | if e.errno != errno.ENOENT: |
425 | raise |
426 | - except JSONDecodeError as e: |
427 | + except JSONDecodeError: |
428 | jsonfile = os.path.join(self.out_d, dpath) |
429 | sys.stderr.write("Decode error in:\n " |
430 | "content_id=%s\n " |
431 | diff --git a/tools/curtainer b/tools/curtainer |
432 | index ca698c6..466d719 100755 |
433 | --- a/tools/curtainer |
434 | +++ b/tools/curtainer |
435 | @@ -17,10 +17,13 @@ Usage: ${0##*/} [ options ] <image> name |
436 | start a container of image (ubuntu-daily:xenial) and install curtin. |
437 | |
438 | options: |
439 | - --proposed enable proposed |
440 | - --daily enable daily curtin archive |
441 | - --source D grab the source deb, unpack inside, and copy unpacked |
442 | - source out to 'D' |
443 | + --no-patch-version do not patch source dir/curtin/version.py |
444 | + by default, --source will have version.py updated |
445 | + with dpkg's version. |
446 | + --proposed enable proposed |
447 | + --daily enable daily curtin archive |
448 | + --source D grab the source deb, unpack inside, and copy unpacked |
449 | + source out to 'D' |
450 | EOF |
451 | } |
452 | |
453 | @@ -114,7 +117,7 @@ get_source() { |
454 | |
455 | main() { |
456 | local short_opts="hv" |
457 | - local long_opts="help,daily,proposed,source:,verbose" |
458 | + local long_opts="help,daily,no-patch-version,proposed,source:,verbose" |
459 | local getopt_out="" |
460 | getopt_out=$(getopt --name "${0##*/}" \ |
461 | --options "${short_opts}" --long "${long_opts}" -- "$@") && |
462 | @@ -123,13 +126,14 @@ main() { |
463 | |
464 | local cur="" next="" |
465 | local proposed=false daily=false src="" name="" maxwait=30 |
466 | - local eatmydata="eatmydata" getsource="none" |
467 | + local eatmydata="eatmydata" getsource="none" patch_version=true |
468 | |
469 | while [ $# -ne 0 ]; do |
470 | cur="$1"; next="$2"; |
471 | case "$cur" in |
472 | -h|--help) Usage ; exit 0;; |
473 | --source) getsource="$next"; shift;; |
474 | + --no-patch-version) patch_version=false;; |
475 | --proposed) proposed=true;; |
476 | --daily) daily=true;; |
477 | -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; |
478 | @@ -147,6 +151,7 @@ main() { |
479 | if [ "$getsource" != "none" ]; then |
480 | [ ! -e "$getsource" ] || fail "source output '$getsource' exists." |
481 | fi |
482 | + getsource="${getsource%/}" |
483 | |
484 | lxc launch "$src" "$name" || fail "failed lxc launch $src $name" |
485 | CONTAINER=$name |
486 | @@ -218,6 +223,16 @@ main() { |
487 | if [ "$src_ver" != "$pkg_ver" ]; then |
488 | fail "source version ($src_ver) != package version ($pkg_ver)" |
489 | fi |
490 | + if "${patch_version}"; then |
491 | + local verfile="$getsource/curtin/version.py" |
492 | + grep -q "@@PACKAGED_VERSION@@" "$verfile" || |
493 | + fail "failed patching version: " \ |
494 | + "@@PACKAGED_VERSION@@ not found in $verfile" |
495 | + sed -i.curtainer-dist \ |
496 | + "s,@@PACKAGED_VERSION@@,${pkg_ver}," "$verfile" || |
497 | + fail "failed modifying $verfile" |
498 | + debug 1 "patched $verfile pkg version to $pkg_ver." |
499 | + fi |
500 | inside "$name" rm -Rf "$isrcd" || |
501 | fail "failed removal of extract dir" |
502 | debug 1 "put source for curtin at $src_ver in $getsource" |
503 | diff --git a/tools/vmtest-sync-images b/tools/vmtest-sync-images |
504 | index 3d82b62..762702b 100755 |
505 | --- a/tools/vmtest-sync-images |
506 | +++ b/tools/vmtest-sync-images |
507 | @@ -18,7 +18,6 @@ from tests.vmtests import ( |
508 | IMAGE_DIR, IMAGE_SRC_URL, sync_images) |
509 | from tests.vmtests.image_sync import ITEM_NAME_FILTERS |
510 | from tests.vmtests.helpers import (find_arches, find_releases_by_distro) |
511 | -from curtin.util import get_platform_arch |
512 | |
513 | |
514 | def _fmt_list_filter(filter_name, matches): |
515 | diff --git a/tox.ini b/tox.ini |
516 | index c1748c3..6f14381 100644 |
517 | --- a/tox.ini |
518 | +++ b/tox.ini |
519 | @@ -1,7 +1,14 @@ |
520 | [tox] |
521 | minversion = 1.6 |
522 | skipsdist = True |
523 | -envlist = py27, py3, py3-flake8, py3-pylint, py27-pylint, trusty-check, trusty-py27, trusty-py3 |
524 | +envlist = |
525 | + py3-flake8, |
526 | + py27, |
527 | + py3, |
528 | + py3-pylint, |
529 | + py27-pylint, |
530 | + trusty-py27, |
531 | + xenial-py3 |
532 | |
533 | [tox:jenkins] |
534 | downloadcache = ~/cache/pip |
535 | @@ -91,6 +98,25 @@ basepython = python3 |
536 | commands = {envpython} {toxinidir}/tools/noproxy nosetests \ |
537 | {posargs:tests/unittests} |
538 | |
539 | +[testenv:xenial] |
540 | +deps = |
541 | + mock==1.3.0 |
542 | + nose==1.3.7 |
543 | + pyyaml==3.11 |
544 | + oauthlib==1.0.3 |
545 | + |
546 | +[testenv:xenial-py27] |
547 | +basepython = python27 |
548 | +deps = {[testenv:xenial]deps} |
549 | +commands = {envpython} {toxinidir}/tools/noproxy nosetests \ |
550 | + {posargs:tests/unittests} |
551 | + |
552 | +[testenv:xenial-py3] |
553 | +basepython = python3 |
554 | +deps = {[testenv:xenial]deps} |
555 | +commands = {envpython} {toxinidir}/tools/noproxy nosetests \ |
556 | + {posargs:tests/unittests} |
557 | + |
558 | [testenv:tip-pycodestyle] |
559 | commands = {envpython} -m pycodestyle {posargs:curtin/ tests/ tools/} |
560 | deps = pycodestyle |
PASSED: Continuous integration, rev:b78e920506b dd55e374a833791 0301fe10a704f7 /jenkins. ubuntu. com/server/ job/curtin- ci/966/ /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-amd64/ 966 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-arm64/ 966 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-ppc64el/ 966 /jenkins. ubuntu. com/server/ job/curtin- ci/nodes= metal-s390x/ 966
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
Click here to trigger a rebuild: /jenkins. ubuntu. com/server/ job/curtin- ci/966/ rebuild
https:/