Merge lp:~smoser/ubuntu/xenial/curtin/pkg-sru-r437 into lp:~smoser/ubuntu/xenial/curtin/pkg
- Xenial (16.04)
- pkg-sru-r437
- Merge into pkg
Proposed by
Scott Moser
Status: | Merged |
---|---|
Merged at revision: | 58 |
Proposed branch: | lp:~smoser/ubuntu/xenial/curtin/pkg-sru-r437 |
Merge into: | lp:~smoser/ubuntu/xenial/curtin/pkg |
Diff against target: |
1365 lines (+661/-168) 24 files modified
curtin/block/__init__.py (+1/-1) curtin/commands/apt_config.py (+16/-6) curtin/commands/block_meta.py (+1/-2) curtin/commands/curthooks.py (+28/-1) curtin/deps/__init__.py (+11/-2) curtin/util.py (+15/-6) debian/changelog (+20/-0) debian/new-upstream-snapshot (+47/-3) examples/tests/centos_basic.yaml (+13/-0) examples/tests/mirrorboot-msdos-partition.yaml (+82/-0) helpers/list-flash-kernel-packages (+13/-0) tests/unittests/test_apt_source.py (+1/-0) tests/unittests/test_block.py (+2/-0) tests/unittests/test_curthooks.py (+134/-0) tests/vmtests/__init__.py (+83/-102) tests/vmtests/helpers.py (+20/-8) tests/vmtests/image_sync.py (+31/-17) tests/vmtests/releases.py (+38/-10) tests/vmtests/test_apt_config_cmd.py (+4/-0) tests/vmtests/test_centos_basic.py (+42/-0) tests/vmtests/test_mdadm_bcache.py (+39/-0) tests/vmtests/test_raid5_bcache.py (+2/-1) tools/vmtest-sync-images (+15/-6) tools/xkvm (+3/-3) |
To merge this branch: | bzr merge lp:~smoser/ubuntu/xenial/curtin/pkg-sru-r437 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ryan Harper (community) | Approve | ||
Scott Moser | Pending | ||
Review via email: mp+315035@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'curtin/block/__init__.py' |
2 | --- curtin/block/__init__.py 2016-10-03 18:43:46 +0000 |
3 | +++ curtin/block/__init__.py 2017-01-18 16:16:23 +0000 |
4 | @@ -120,7 +120,7 @@ |
5 | """ |
6 | Add number to disk_kname prepending a 'p' if needed |
7 | """ |
8 | - for dev_type in ['nvme', 'mmcblk', 'cciss', 'mpath', 'dm']: |
9 | + for dev_type in ['nvme', 'mmcblk', 'cciss', 'mpath', 'dm', 'md']: |
10 | if disk_kname.startswith(dev_type): |
11 | partition_number = "p%s" % partition_number |
12 | break |
13 | |
14 | === modified file 'curtin/commands/apt_config.py' |
15 | --- curtin/commands/apt_config.py 2016-10-03 18:42:29 +0000 |
16 | +++ curtin/commands/apt_config.py 2017-01-18 16:16:23 +0000 |
17 | @@ -24,6 +24,7 @@ |
18 | import os |
19 | import re |
20 | import sys |
21 | +import time |
22 | import yaml |
23 | |
24 | from curtin.log import LOG |
25 | @@ -402,13 +403,21 @@ |
26 | ent['filename'] += ".list" |
27 | |
28 | if aa_repo_match(source): |
29 | - try: |
30 | - with util.ChrootableTarget( |
31 | - target, sys_resolvconf=True) as in_chroot: |
32 | + with util.ChrootableTarget( |
33 | + target, sys_resolvconf=True) as in_chroot: |
34 | + time_entered = time.time() |
35 | + try: |
36 | in_chroot.subp(["add-apt-repository", source]) |
37 | - except util.ProcessExecutionError: |
38 | - LOG.exception("add-apt-repository failed.") |
39 | - raise |
40 | + except util.ProcessExecutionError: |
41 | + LOG.exception("add-apt-repository failed.") |
42 | + raise |
43 | + finally: |
44 | + # workaround to gnupg >=2.x spawning daemons (LP: #1645680) |
45 | + seconds_since = time.time() - time_entered + 1 |
46 | + in_chroot.subp(['killall', '--wait', '--quiet', |
47 | + '--younger-than', '%ds' % seconds_since, |
48 | + '--regexp', '(dirmngr|gpg-agent)'], |
49 | + rcs=[0, 1]) |
50 | continue |
51 | |
52 | sourcefn = util.target_path(target, ent['filename']) |
53 | @@ -661,6 +670,7 @@ |
54 | """Populate subcommand option parsing for apt-config""" |
55 | populate_one_subcmd(parser, CMD_ARGUMENTS, apt_command) |
56 | |
57 | + |
58 | CONFIG_CLEANERS = { |
59 | 'cloud-init': clean_cloud_init, |
60 | } |
61 | |
62 | === modified file 'curtin/commands/block_meta.py' |
63 | --- curtin/commands/block_meta.py 2016-10-03 18:43:46 +0000 |
64 | +++ curtin/commands/block_meta.py 2017-01-18 16:16:23 +0000 |
65 | @@ -417,8 +417,7 @@ |
66 | try: |
67 | lbs_path = os.path.join(disk_sysfs_path, 'queue', 'logical_block_size') |
68 | with open(lbs_path, 'r') as f: |
69 | - l = f.readline() |
70 | - logical_block_size_bytes = int(l) |
71 | + logical_block_size_bytes = int(f.readline()) |
72 | except: |
73 | logical_block_size_bytes = 512 |
74 | LOG.debug( |
75 | |
76 | === modified file 'curtin/commands/curthooks.py' |
77 | --- curtin/commands/curthooks.py 2016-10-03 18:43:46 +0000 |
78 | +++ curtin/commands/curthooks.py 2017-01-18 16:16:23 +0000 |
79 | @@ -159,6 +159,25 @@ |
80 | in_chroot.subp(['zipl']) |
81 | |
82 | |
83 | +def get_flash_kernel_pkgs(arch=None, uefi=None): |
84 | + if arch is None: |
85 | + arch = util.get_architecture() |
86 | + if uefi is None: |
87 | + uefi = util.is_uefi_bootable() |
88 | + if uefi: |
89 | + return None |
90 | + if not arch.startswith('arm'): |
91 | + return None |
92 | + |
93 | + try: |
94 | + fk_packages, _ = util.subp( |
95 | + ['list-flash-kernel-packages'], capture=True) |
96 | + return fk_packages |
97 | + except util.ProcessExecutionError: |
98 | + # Ignore errors |
99 | + return None |
100 | + |
101 | + |
102 | def install_kernel(cfg, target): |
103 | kernel_cfg = cfg.get('kernel', {'package': None, |
104 | 'fallback-package': "linux-generic", |
105 | @@ -173,6 +192,13 @@ |
106 | mapping = copy.deepcopy(KERNEL_MAPPING) |
107 | config.merge_config(mapping, kernel_cfg.get('mapping', {})) |
108 | |
109 | + # Machines using flash-kernel may need additional dependencies installed |
110 | + # before running. Run those checks in the ephemeral environment so the |
111 | + # target only has required packages installed. See LP:1640519 |
112 | + fk_packages = get_flash_kernel_pkgs() |
113 | + if fk_packages: |
114 | + util.install_packages(fk_packages.split(), target=target) |
115 | + |
116 | if kernel_package: |
117 | util.install_packages([kernel_package], target=target) |
118 | return |
119 | @@ -344,7 +370,8 @@ |
120 | cmd = ['update-initramfs', '-u'] |
121 | if all_kernels: |
122 | cmd.extend(['-k', 'all']) |
123 | - util.subp(cmd, target=target) |
124 | + with util.ChrootableTarget(target) as in_chroot: |
125 | + in_chroot.subp(cmd) |
126 | |
127 | |
128 | def copy_fstab(fstab, target): |
129 | |
130 | === modified file 'curtin/deps/__init__.py' |
131 | --- curtin/deps/__init__.py 2016-03-18 14:16:45 +0000 |
132 | +++ curtin/deps/__init__.py 2017-01-18 16:16:23 +0000 |
133 | @@ -17,8 +17,14 @@ |
134 | import os |
135 | import sys |
136 | |
137 | -from curtin.util import (which, install_packages, lsb_release, |
138 | - ProcessExecutionError) |
139 | +from curtin.util import ( |
140 | + ProcessExecutionError, |
141 | + get_architecture, |
142 | + install_packages, |
143 | + is_uefi_bootable, |
144 | + lsb_release, |
145 | + which, |
146 | +) |
147 | |
148 | REQUIRED_IMPORTS = [ |
149 | # import string to execute, python2 package, python3 package |
150 | @@ -47,6 +53,9 @@ |
151 | REQUIRED_IMPORTS.append( |
152 | ('import oauthlib.oauth1', 'python-oauthlib', 'python3-oauthlib'),) |
153 | |
154 | +if not is_uefi_bootable() and 'arm' in get_architecture(): |
155 | + REQUIRED_EXECUTABLES.append(('flash-kernel', 'flash-kernel')) |
156 | + |
157 | |
158 | class MissingDeps(Exception): |
159 | def __init__(self, message, deps): |
160 | |
161 | === modified file 'curtin/util.py' |
162 | --- curtin/util.py 2016-10-03 18:43:46 +0000 |
163 | +++ curtin/util.py 2017-01-18 16:16:23 +0000 |
164 | @@ -45,6 +45,12 @@ |
165 | except NameError: |
166 | string_types = (str,) |
167 | |
168 | +try: |
169 | + numeric_types = (int, float, long) |
170 | +except NameError: |
171 | + # python3 does not have a long type. |
172 | + numeric_types = (int, float) |
173 | + |
174 | from .log import LOG |
175 | |
176 | _INSTALLED_HELPERS_PATH = '/usr/lib/curtin/helpers' |
177 | @@ -871,14 +877,17 @@ |
178 | |
179 | def bytes2human(size): |
180 | """convert size in bytes to human readable""" |
181 | - if not (isinstance(size, (int, float)) and |
182 | - int(size) == size and |
183 | - int(size) >= 0): |
184 | - raise ValueError('size must be a integral value') |
185 | + if not isinstance(size, numeric_types): |
186 | + raise ValueError('size must be a numeric value, not %s', type(size)) |
187 | + isize = int(size) |
188 | + if isize != size: |
189 | + raise ValueError('size "%s" is not a whole number.' % size) |
190 | + if isize < 0: |
191 | + raise ValueError('size "%d" < 0.' % isize) |
192 | mpliers = {'B': 1, 'K': 2 ** 10, 'M': 2 ** 20, 'G': 2 ** 30, 'T': 2 ** 40} |
193 | unit_order = sorted(mpliers, key=lambda x: -1 * mpliers[x]) |
194 | - unit = next((u for u in unit_order if (size / mpliers[u]) >= 1), 'B') |
195 | - return str(int(size / mpliers[unit])) + unit |
196 | + unit = next((u for u in unit_order if (isize / mpliers[u]) >= 1), 'B') |
197 | + return str(int(isize / mpliers[unit])) + unit |
198 | |
199 | |
200 | def import_module(import_str): |
201 | |
202 | === modified file 'debian/changelog' |
203 | --- debian/changelog 2016-10-03 19:12:33 +0000 |
204 | +++ debian/changelog 2017-01-18 16:16:23 +0000 |
205 | @@ -1,3 +1,23 @@ |
206 | +curtin (0.1.0~bzr437-0ubuntu1~16.04.1) UNRELEASED; urgency=medium |
207 | + |
208 | + * debian/new-upstream-snapshot: change to not use bzr merge-upstream. |
209 | + * New upstream snapshot. |
210 | + - revert: Test Workaround: skip XenialTestNvme for a short time. |
211 | + - Test Workaround: skip XenialTestNvme for a short time. |
212 | + - pep8: fix pep8 errors found with 'make pep8' on zesty. |
213 | + - Workaround failures caused by gpg2 daemons left running in chroot. |
214 | + (LP: #1645680) |
215 | + - Install u-boot-tools when running on a system with u-boot. (LP: #1640519) |
216 | + - block: fix partition kname for raid devices (LP: #1641661) |
217 | + - Fix up tox errors that slipped in and new pycodestyle 2.1.0 complaints. |
218 | + - vmtests: adjust vmtest image sync metadata filenames |
219 | + - vmtests: Add centos support |
220 | + - Disable WilyTestRaid5Bcache vmtest |
221 | + - tools/xkvm: fix --netdev=<bridge> |
222 | + - bytes2human: fix for values larger than 32 bit int on 32 bit python2. |
223 | + |
224 | + -- Scott Moser <smoser@ubuntu.com> Wed, 18 Jan 2017 10:56:59 -0500 |
225 | + |
226 | curtin (0.1.0~bzr425-0ubuntu1~16.04.1) xenial-proposed; urgency=medium |
227 | |
228 | [ Scott Moser ] |
229 | |
230 | === modified file 'debian/new-upstream-snapshot' |
231 | --- debian/new-upstream-snapshot 2016-10-03 17:23:32 +0000 |
232 | +++ debian/new-upstream-snapshot 2017-01-18 16:16:23 +0000 |
233 | @@ -23,7 +23,7 @@ |
234 | print_commit() { |
235 | local subject="$1" author="$2" bugs="$3" aname="" |
236 | aname=${author% <*} |
237 | - echo " - $subject ${aname:+[${aname}]}${bugs:+ (LP: ${bugs})}" |
238 | + echo " - $subject${aname:+ [${aname}]}${bugs:+ (LP: ${bugs})}" |
239 | } |
240 | |
241 | # unfortunately seems like no easy way to get 'Author' unless |
242 | @@ -99,8 +99,52 @@ |
243 | bzr export --format=tgz "--revision=${revno}" "$tarball" "${trunk}" || |
244 | fail "failed exporting bzr in $trunk to $tarball" |
245 | fi |
246 | -bzr merge-upstream "$tarball" "--version=${version}" || |
247 | - fail "failed merge-upstream of $tarball at version=$version" |
248 | +#bzr merge-upstream "$tarball" "--version=${version}" || |
249 | +# fail "failed merge-upstream of $tarball at version=$version" |
250 | +tmpd=$(mktemp -d "${TMPDIR:-/tmp}/curtin.${0##*/}.XXXXXX") |
251 | +trap 'rm -Rf "$tmpd"' EXIT |
252 | +newflist="${tmpd}/new-files" |
253 | +oldflist="${tmpd}/old-files" |
254 | + |
255 | +tar -tf "$tarball" \ |
256 | + --strip-components=1 --exclude="*/debian" > "$newflist.full" || |
257 | + fail "failed tar tf on $tarball" |
258 | +sed 's,^[^/]*/,,' "$newflist.full" > "$newflist" |
259 | + |
260 | +bzr ls --recursive --versioned > "$oldflist.full" || |
261 | + fail "failed bzr ls --recursive" |
262 | +grep -v "^debian/" "$oldflist.full" > "$oldflist" |
263 | + |
264 | +cat "$oldflist" "$newflist" "$newflist" > "$tmpd/all-old" || |
265 | + fail "failed getting all old files" |
266 | +cat "$newflist" "$oldflist" "$oldflist" > "$tmpd/all-new" || |
267 | + fail "failed getting all new" |
268 | + |
269 | +removed="${tmpd}/removed" |
270 | +added="$tmpd/added" |
271 | +sort "$tmpd/all-old" | uniq --uniq > "$removed" |
272 | +sort "$tmpd/all-new" | uniq --uniq > "$added" |
273 | + |
274 | +while read rmfile; do |
275 | + case "$rmfile" in |
276 | + .pc/*) continue;; |
277 | + */) rflag="-r";; |
278 | + *) rflag="";; |
279 | + esac |
280 | + bzr rm $rflag "$rmfile" || fail "failed bzr rm${rflag:+ ${rflag}} $rmfile" |
281 | +done < "$removed" |
282 | + |
283 | +for f in *; do |
284 | + [ "$f" = "debian" ] && continue |
285 | + rm -rf "$f" || fail "failed removing '$f'" |
286 | +done |
287 | + |
288 | +tar --strip-components=1 --exclude "*/debian/*" -xf "$tarball" || |
289 | + fail "failed extraction of $tarball" |
290 | + |
291 | +while read newfile; do |
292 | + bzr add "$newfile" || fail "failed adding '$newfile'" |
293 | +done < "$added" |
294 | |
295 | oldrev=$(($prevno+1)) |
296 | ( cd "$trunk" && bzr log -r "${oldrev}..${revno}" ) > new-changes.log || |
297 | |
298 | === added file 'examples/tests/centos_basic.yaml' |
299 | --- examples/tests/centos_basic.yaml 1970-01-01 00:00:00 +0000 |
300 | +++ examples/tests/centos_basic.yaml 2017-01-18 16:16:23 +0000 |
301 | @@ -0,0 +1,13 @@ |
302 | +showtrace: true |
303 | +hook_commands: |
304 | + builtin: null |
305 | +network: |
306 | + version: 1 |
307 | + config: |
308 | + - type: physical |
309 | + name: interface0 |
310 | + mac_address: "52:54:00:12:34:00" |
311 | + subnets: |
312 | + - type: static |
313 | + address: 10.0.2.15/24 |
314 | + gateway: 10.0.2.2 |
315 | |
316 | === added file 'examples/tests/mirrorboot-msdos-partition.yaml' |
317 | --- examples/tests/mirrorboot-msdos-partition.yaml 1970-01-01 00:00:00 +0000 |
318 | +++ examples/tests/mirrorboot-msdos-partition.yaml 2017-01-18 16:16:23 +0000 |
319 | @@ -0,0 +1,82 @@ |
320 | +showtrace: true |
321 | +storage: |
322 | + version: 1 |
323 | + config: |
324 | + - id: sda |
325 | + type: disk |
326 | + ptable: msdos |
327 | + model: QEMU HARDDISK |
328 | + path: /dev/vdb |
329 | + name: main_disk |
330 | + grub_device: true |
331 | + wipe: superblock |
332 | + - id: sdb |
333 | + type: disk |
334 | + ptable: msdos |
335 | + model: QEMU HARDDISK |
336 | + path: /dev/vdc |
337 | + name: second_disk |
338 | + wipe: superblock |
339 | + - id: sda-part1 |
340 | + name: sda-part1 |
341 | + type: partition |
342 | + size: 5GB |
343 | + number: 1 |
344 | + device: sda |
345 | + uuid: bbfd7fc9-fd0c-4151-99d4-a48c148c46b1 |
346 | + wipe: superblock |
347 | + - id: sdb-part1 |
348 | + name: sdb-part1 |
349 | + type: partition |
350 | + size: 5GB |
351 | + number: 1 |
352 | + device: sdb |
353 | + uuid: b37f57af-52b9-4ffc-98cf-08b7f7f4bed1 |
354 | + wipe: superblock |
355 | + - id: md0 |
356 | + name: md0 |
357 | + type: raid |
358 | + ptable: gpt |
359 | + raidlevel: 1 |
360 | + devices: |
361 | + - sda-part1 |
362 | + - sdb-part1 |
363 | + spare_devices: [] |
364 | + - device: md0 |
365 | + id: md0-part1 |
366 | + name: md0-part1 |
367 | + number: 1 |
368 | + offset: 4194304B |
369 | + size: 2GB |
370 | + type: partition |
371 | + uuid: 4f4fa336-2762-48e4-ae54-9451141665cd |
372 | + wipe: superblock |
373 | + - device: md0 |
374 | + id: md0-part2 |
375 | + name: md0-part2 |
376 | + number: 2 |
377 | + size: 2GB |
378 | + type: partition |
379 | + uuid: c2d21fd3-3cde-4432-8eab-f08594bbe76e |
380 | + wipe: superblock |
381 | + - fstype: ext4 |
382 | + id: md0-part1_format |
383 | + label: '' |
384 | + type: format |
385 | + uuid: c4024546-ad9d-4d85-adfa-c4b22611baa8 |
386 | + volume: md0-part1 |
387 | + - fstype: swap |
388 | + id: md0-part2_format |
389 | + label: '' |
390 | + type: format |
391 | + uuid: f68507ce-6d3d-4087-83e8-d8e531d7ec7d |
392 | + volume: md0-part2 |
393 | + - device: md0-part1_format |
394 | + id: md0-part1_mount |
395 | + options: '' |
396 | + path: / |
397 | + type: mount |
398 | + - device: md0-part2_format |
399 | + id: md0-part2_mount |
400 | + options: '' |
401 | + type: mount |
402 | |
403 | === added file 'helpers/list-flash-kernel-packages' |
404 | --- helpers/list-flash-kernel-packages 1970-01-01 00:00:00 +0000 |
405 | +++ helpers/list-flash-kernel-packages 2017-01-18 16:16:23 +0000 |
406 | @@ -0,0 +1,13 @@ |
407 | +#!/bin/sh -e |
408 | +# Return the list of packages flash-kernel requires for this machine if |
409 | +# supported. If not supported return a non-zero return code. |
410 | + |
411 | +FK_DIR=/usr/share/flash-kernel |
412 | +. ${FK_DIR}/functions |
413 | + |
414 | +machine="$(get_cpuinfo_hardware)" |
415 | +check_supported "${machine}" |
416 | +# get_machine_field gives a non-zero return code when no additional packages |
417 | +# are required. Ignore it so the script succeeds allowing just flash-kernel to |
418 | +# be installed in the target. |
419 | +get_machine_field "${machine}" "Required-Packages" ||: |
420 | |
421 | === modified file 'tests/unittests/test_apt_source.py' |
422 | --- tests/unittests/test_apt_source.py 2016-10-03 18:42:29 +0000 |
423 | +++ tests/unittests/test_apt_source.py 2017-01-18 16:16:23 +0000 |
424 | @@ -58,6 +58,7 @@ |
425 | def __exit__(self, exc_type, exc_value, traceback): |
426 | return |
427 | |
428 | + |
429 | ChrootableTargetStr = "curtin.commands.apt_config.util.ChrootableTarget" |
430 | |
431 | |
432 | |
433 | === modified file 'tests/unittests/test_block.py' |
434 | --- tests/unittests/test_block.py 2016-10-03 18:42:29 +0000 |
435 | +++ tests/unittests/test_block.py 2017-01-18 16:16:23 +0000 |
436 | @@ -302,6 +302,7 @@ |
437 | (('mmcblk0', 1), 'mmcblk0p1'), |
438 | (('cciss!c0d0', 1), 'cciss!c0d0p1'), |
439 | (('dm-0', 1), 'dm-0p1'), |
440 | + (('md0', 1), 'md0p1'), |
441 | (('mpath1', 2), 'mpath1p2')] |
442 | for ((disk_kname, part_number), part_kname) in part_knames: |
443 | self.assertEqual(block.partition_kname(disk_kname, part_number), |
444 | @@ -313,6 +314,7 @@ |
445 | path_knames = [('/dev/sda', 'sda'), |
446 | ('/dev/sda1', 'sda1'), |
447 | ('/dev////dm-0/', 'dm-0'), |
448 | + ('/dev/md0p1', 'md0p1'), |
449 | ('vdb', 'vdb'), |
450 | ('/dev/mmcblk0p1', 'mmcblk0p1'), |
451 | ('/dev/nvme0n0p1', 'nvme0n0p1'), |
452 | |
453 | === added file 'tests/unittests/test_curthooks.py' |
454 | --- tests/unittests/test_curthooks.py 1970-01-01 00:00:00 +0000 |
455 | +++ tests/unittests/test_curthooks.py 2017-01-18 16:16:23 +0000 |
456 | @@ -0,0 +1,134 @@ |
457 | +import os |
458 | +from unittest import TestCase |
459 | +from mock import call, patch |
460 | +import shutil |
461 | +import tempfile |
462 | + |
463 | +from curtin.commands import curthooks |
464 | +from curtin import util |
465 | + |
466 | + |
467 | +class CurthooksBase(TestCase): |
468 | + def setUp(self): |
469 | + super(CurthooksBase, self).setUp() |
470 | + |
471 | + def add_patch(self, target, attr): |
472 | + """Patches specified target object and sets it as attr on test |
473 | + instance also schedules cleanup""" |
474 | + m = patch(target, autospec=True) |
475 | + p = m.start() |
476 | + self.addCleanup(m.stop) |
477 | + setattr(self, attr, p) |
478 | + |
479 | + |
480 | +class TestGetFlashKernelPkgs(CurthooksBase): |
481 | + def setUp(self): |
482 | + super(TestGetFlashKernelPkgs, self).setUp() |
483 | + self.add_patch('curtin.util.subp', 'mock_subp') |
484 | + self.add_patch('curtin.util.get_architecture', 'mock_get_architecture') |
485 | + self.add_patch('curtin.util.is_uefi_bootable', 'mock_is_uefi_bootable') |
486 | + |
487 | + def test__returns_none_when_uefi(self): |
488 | + self.assertIsNone(curthooks.get_flash_kernel_pkgs(uefi=True)) |
489 | + self.assertFalse(self.mock_subp.called) |
490 | + |
491 | + def test__returns_none_when_not_arm(self): |
492 | + self.assertIsNone(curthooks.get_flash_kernel_pkgs('amd64', False)) |
493 | + self.assertFalse(self.mock_subp.called) |
494 | + |
495 | + def test__returns_none_on_error(self): |
496 | + self.mock_subp.side_effect = util.ProcessExecutionError() |
497 | + self.assertIsNone(curthooks.get_flash_kernel_pkgs('arm64', False)) |
498 | + self.mock_subp.assert_called_with( |
499 | + ['list-flash-kernel-packages'], capture=True) |
500 | + |
501 | + def test__returns_flash_kernel_pkgs(self): |
502 | + self.mock_subp.return_value = 'u-boot-tools', '' |
503 | + self.assertEquals( |
504 | + 'u-boot-tools', curthooks.get_flash_kernel_pkgs('arm64', False)) |
505 | + self.mock_subp.assert_called_with( |
506 | + ['list-flash-kernel-packages'], capture=True) |
507 | + |
508 | + def test__calls_get_arch_and_is_uefi_bootable_when_undef(self): |
509 | + curthooks.get_flash_kernel_pkgs() |
510 | + self.mock_get_architecture.assert_called_once_with() |
511 | + self.mock_is_uefi_bootable.assert_called_once_with() |
512 | + |
513 | + |
514 | +class TestCurthooksInstallKernel(CurthooksBase): |
515 | + def setUp(self): |
516 | + super(TestCurthooksInstallKernel, self).setUp() |
517 | + self.add_patch('curtin.util.has_pkg_available', 'mock_haspkg') |
518 | + self.add_patch('curtin.util.install_packages', 'mock_instpkg') |
519 | + self.add_patch( |
520 | + 'curtin.commands.curthooks.get_flash_kernel_pkgs', |
521 | + 'mock_get_flash_kernel_pkgs') |
522 | + |
523 | + self.kernel_cfg = {'kernel': {'package': 'mock-linux-kernel', |
524 | + 'fallback-package': 'mock-fallback', |
525 | + 'mapping': {}}} |
526 | + # Tests don't actually install anything so we just need a name |
527 | + self.target = tempfile.mktemp() |
528 | + |
529 | + def test__installs_flash_kernel_packages_when_needed(self): |
530 | + kernel_package = self.kernel_cfg.get('kernel', {}).get('package', {}) |
531 | + self.mock_get_flash_kernel_pkgs.return_value = 'u-boot-tools' |
532 | + |
533 | + curthooks.install_kernel(self.kernel_cfg, self.target) |
534 | + |
535 | + inst_calls = [ |
536 | + call(['u-boot-tools'], target=self.target), |
537 | + call([kernel_package], target=self.target)] |
538 | + |
539 | + self.mock_instpkg.assert_has_calls(inst_calls) |
540 | + |
541 | + def test__installs_kernel_package(self): |
542 | + kernel_package = self.kernel_cfg.get('kernel', {}).get('package', {}) |
543 | + self.mock_get_flash_kernel_pkgs.return_value = None |
544 | + |
545 | + curthooks.install_kernel(self.kernel_cfg, self.target) |
546 | + |
547 | + self.mock_instpkg.assert_called_with( |
548 | + [kernel_package], target=self.target) |
549 | + |
550 | + |
551 | +class TestUpdateInitramfs(CurthooksBase): |
552 | + def setUp(self): |
553 | + super(TestUpdateInitramfs, self).setUp() |
554 | + self.add_patch('curtin.util.subp', 'mock_subp') |
555 | + self.target = tempfile.mkdtemp() |
556 | + |
557 | + def tearDown(self): |
558 | + shutil.rmtree(self.target) |
559 | + |
560 | + def _mnt_call(self, point): |
561 | + target = os.path.join(self.target, point) |
562 | + return call(['mount', '--bind', '/%s' % point, target]) |
563 | + |
564 | + def test_mounts_and_runs(self): |
565 | + curthooks.update_initramfs(self.target) |
566 | + |
567 | + print('subp calls: %s' % self.mock_subp.mock_calls) |
568 | + subp_calls = [ |
569 | + self._mnt_call('dev'), |
570 | + self._mnt_call('proc'), |
571 | + self._mnt_call('sys'), |
572 | + call(['update-initramfs', '-u'], target=self.target), |
573 | + call(['udevadm', 'settle']), |
574 | + ] |
575 | + self.mock_subp.assert_has_calls(subp_calls) |
576 | + |
577 | + def test_mounts_and_runs_for_all_kernels(self): |
578 | + curthooks.update_initramfs(self.target, True) |
579 | + |
580 | + print('subp calls: %s' % self.mock_subp.mock_calls) |
581 | + subp_calls = [ |
582 | + self._mnt_call('dev'), |
583 | + self._mnt_call('proc'), |
584 | + self._mnt_call('sys'), |
585 | + call(['update-initramfs', '-u', '-k', 'all'], target=self.target), |
586 | + call(['udevadm', 'settle']), |
587 | + ] |
588 | + self.mock_subp.assert_has_calls(subp_calls) |
589 | + |
590 | +# vi: ts=4 expandtab syntax=python |
591 | |
592 | === modified file 'tests/vmtests/__init__.py' |
593 | --- tests/vmtests/__init__.py 2016-10-03 18:43:46 +0000 |
594 | +++ tests/vmtests/__init__.py 2017-01-18 16:16:23 +0000 |
595 | @@ -4,7 +4,6 @@ |
596 | import logging |
597 | import json |
598 | import os |
599 | -import pathlib |
600 | import random |
601 | import re |
602 | import shutil |
603 | @@ -19,14 +18,10 @@ |
604 | |
605 | from .image_sync import query as imagesync_query |
606 | from .image_sync import mirror as imagesync_mirror |
607 | +from .image_sync import (IMAGE_SRC_URL, IMAGE_DIR) |
608 | from .helpers import check_call, TimeoutExpired |
609 | from unittest import TestCase, SkipTest |
610 | |
611 | -IMAGE_SRC_URL = os.environ.get( |
612 | - 'IMAGE_SRC_URL', |
613 | - "http://maas.ubuntu.com/images/ephemeral-v2/daily/streams/v1/index.sjson") |
614 | - |
615 | -IMAGE_DIR = os.environ.get("IMAGE_DIR", "/srv/images") |
616 | try: |
617 | IMAGES_TO_KEEP = int(os.environ.get("IMAGES_TO_KEEP", 1)) |
618 | except ValueError: |
619 | @@ -37,6 +32,7 @@ |
620 | |
621 | DEVNULL = open(os.devnull, 'w') |
622 | KEEP_DATA = {"pass": "none", "fail": "all"} |
623 | +CURTIN_VMTEST_IMAGE_SYNC = os.environ.get("CURTIN_VMTEST_IMAGE_SYNC", False) |
624 | IMAGE_SYNCS = [] |
625 | TARGET_IMAGE_FORMAT = "raw" |
626 | |
627 | @@ -169,20 +165,25 @@ |
628 | return |
629 | |
630 | |
631 | -def get_images(src_url, local_d, release, arch, krel=None, sync=True): |
632 | +def get_images(src_url, local_d, distro, release, arch, krel=None, sync=True, |
633 | + ftypes=None): |
634 | # ensure that the image items (roottar, kernel, initrd) |
635 | # we need for release and arch are available in base_dir. |
636 | # returns updated ftypes dictionary {ftype: item_url} |
637 | - if krel is None: |
638 | - krel = release |
639 | - ftypes = { |
640 | - 'vmtest.root-image': '', |
641 | - 'vmtest.root-tgz': '', |
642 | - 'boot-kernel': '', |
643 | - 'boot-initrd': '' |
644 | - } |
645 | - common_filters = ['release=%s' % release, 'krel=%s' % krel, |
646 | - 'arch=%s' % arch] |
647 | + if not ftypes: |
648 | + ftypes = { |
649 | + 'vmtest.root-image': '', |
650 | + 'vmtest.root-tgz': '', |
651 | + 'boot-kernel': '', |
652 | + 'boot-initrd': '' |
653 | + } |
654 | + elif isinstance(ftypes, (list, tuple)): |
655 | + ftypes = dict().fromkeys(ftypes) |
656 | + |
657 | + common_filters = ['release=%s' % release, |
658 | + 'arch=%s' % arch, 'os=%s' % distro] |
659 | + if krel: |
660 | + common_filters.append('krel=%s' % krel) |
661 | filters = ['ftype~(%s)' % ("|".join(ftypes.keys()))] + common_filters |
662 | |
663 | if sync: |
664 | @@ -208,16 +209,17 @@ |
665 | # try to fix this with a sync |
666 | logger.info(fail_msg + " Attempting to fix with an image sync. (%s)", |
667 | query_str) |
668 | - return get_images(src_url, local_d, release, arch, krel, sync=True) |
669 | + return get_images(src_url, local_d, distro, release, arch, |
670 | + krel=krel, sync=True, ftypes=ftypes) |
671 | elif not results: |
672 | raise ValueError("Nothing found in query: %s" % query_str) |
673 | |
674 | missing = [] |
675 | - expected = sorted(ftypes.keys()) |
676 | found = sorted(f.get('ftype') for f in results) |
677 | - if expected != found: |
678 | - raise ValueError("Query returned unexpected ftypes=%s. " |
679 | - "Expected=%s" % (found, expected)) |
680 | + for ftype in ftypes.keys(): |
681 | + if ftype not in found: |
682 | + raise ValueError("Expected ftype '{}' but not in results" |
683 | + .format(ftype)) |
684 | for item in results: |
685 | ftypes[item['ftype']] = item['item_url'] |
686 | last_item = item |
687 | @@ -235,42 +237,6 @@ |
688 | return version_info, ftypes |
689 | |
690 | |
691 | -class ImageStore: |
692 | - """Local mirror of MAAS images simplestreams data.""" |
693 | - |
694 | - # By default sync on demand. |
695 | - sync = True |
696 | - |
697 | - # images are expected in dirs named <release>/<arch>/YYYYMMDD[.X] |
698 | - image_dir_re = re.compile(r"^[0-9]{4}[01][0-9][0123][0-9]([.][0-9])*$") |
699 | - |
700 | - def __init__(self, source_url, base_dir): |
701 | - """Initialize the ImageStore. |
702 | - |
703 | - source_url is the simplestreams source from where the images will be |
704 | - downloaded. |
705 | - base_dir is the target dir in the filesystem to keep the mirror. |
706 | - """ |
707 | - self.source_url = source_url |
708 | - self.base_dir = base_dir |
709 | - if not os.path.isdir(self.base_dir): |
710 | - os.makedirs(self.base_dir) |
711 | - self.url = pathlib.Path(self.base_dir).as_uri() |
712 | - |
713 | - def get_image(self, release, arch, krel=None): |
714 | - """Return tuple of version info, and paths for root image, |
715 | - kernel, initrd, tarball.""" |
716 | - if krel is None: |
717 | - krel = release |
718 | - ver_info, ftypes = get_images( |
719 | - self.source_url, self.base_dir, release, arch, krel, self.sync) |
720 | - root_image_path = ftypes['vmtest.root-image'] |
721 | - kernel_path = ftypes['boot-kernel'] |
722 | - initrd_path = ftypes['boot-initrd'] |
723 | - tarball = ftypes['vmtest.root-tgz'] |
724 | - return ver_info, (root_image_path, kernel_path, initrd_path, tarball) |
725 | - |
726 | - |
727 | class TempDir(object): |
728 | boot = None |
729 | collect = None |
730 | @@ -356,7 +322,6 @@ |
731 | extra_disks = [] |
732 | extra_kern_args = None |
733 | fstab_expected = {} |
734 | - image_store_class = ImageStore |
735 | boot_cloudconf = None |
736 | install_timeout = INSTALL_TIMEOUT |
737 | interactive = False |
738 | @@ -372,6 +337,30 @@ |
739 | release = None |
740 | arch = None |
741 | krel = None |
742 | + distro = None |
743 | + target_distro = None |
744 | + target_release = None |
745 | + target_krel = None |
746 | + |
747 | + @classmethod |
748 | + def get_test_files(cls): |
749 | + img_verstr, ftypes = get_images( |
750 | + IMAGE_SRC_URL, IMAGE_DIR, cls.distro, cls.release, cls.arch, |
751 | + krel=cls.krel if cls.krel else cls.release, |
752 | + ftypes=('boot-initrd', 'boot-kernel', 'vmtest.root-image')) |
753 | + logger.debug("Install Image %s\n, ftypes: %s\n", img_verstr, ftypes) |
754 | + logger.info("Install Image: %s", img_verstr) |
755 | + if not cls.target_krel and cls.krel: |
756 | + cls.target_krel = cls.krel |
757 | + img_verstr, found = get_images( |
758 | + IMAGE_SRC_URL, IMAGE_DIR, |
759 | + cls.target_distro if cls.target_distro else cls.distro, |
760 | + cls.target_release if cls.target_release else cls.release, |
761 | + cls.arch, krel=cls.target_krel, ftypes=('vmtest.root-tgz',)) |
762 | + logger.debug("Target Tarball %s\n, ftypes: %s\n", img_verstr, found) |
763 | + logger.info("Target Tarball: %s", img_verstr) |
764 | + ftypes.update(found) |
765 | + return ftypes |
766 | |
767 | @classmethod |
768 | def setUpClass(cls): |
769 | @@ -383,27 +372,17 @@ |
770 | |
771 | setup_start = time.time() |
772 | logger.info('Starting setup for testclass: {}'.format(cls.__name__)) |
773 | - # get boot img |
774 | - image_store = cls.image_store_class(IMAGE_SRC_URL, IMAGE_DIR) |
775 | - # Disable sync if env var is set. |
776 | - image_store.sync = get_env_var_bool('CURTIN_VMTEST_IMAGE_SYNC', False) |
777 | - logger.debug("Image sync = %s", image_store.sync) |
778 | - img_verstr, (boot_img, boot_kernel, boot_initrd, tarball) = ( |
779 | - image_store.get_image(cls.release, cls.arch, cls.krel)) |
780 | - logger.debug("Image %s\n boot=%s\n kernel=%s\n initrd=%s\n" |
781 | - " tarball=%s\n", img_verstr, boot_img, boot_kernel, |
782 | - boot_initrd, tarball) |
783 | # set up tempdir |
784 | cls.td = TempDir( |
785 | name=cls.__name__, |
786 | user_data=generate_user_data(collect_scripts=cls.collect_scripts, |
787 | boot_cloudconf=cls.boot_cloudconf)) |
788 | - logger.info('Using tempdir: %s , Image: %s', cls.td.tmpdir, |
789 | - img_verstr) |
790 | + logger.info('Using tempdir: %s', cls.td.tmpdir) |
791 | cls.install_log = os.path.join(cls.td.logs, 'install-serial.log') |
792 | cls.boot_log = os.path.join(cls.td.logs, 'boot-serial.log') |
793 | logger.debug('Install console log: {}'.format(cls.install_log)) |
794 | logger.debug('Boot console log: {}'.format(cls.boot_log)) |
795 | + ftypes = cls.get_test_files() |
796 | |
797 | # if interactive, launch qemu without 'background & wait' |
798 | if cls.interactive: |
799 | @@ -422,8 +401,8 @@ |
800 | cmd.extend(["--append=" + cls.extra_kern_args]) |
801 | |
802 | # publish the root tarball |
803 | - install_src = "PUBURL/" + os.path.basename(tarball) |
804 | - cmd.append("--publish=%s" % tarball) |
805 | + install_src = "PUBURL/" + os.path.basename(ftypes['vmtest.root-tgz']) |
806 | + cmd.append("--publish=%s" % ftypes['vmtest.root-tgz']) |
807 | |
808 | # check for network configuration |
809 | cls.network_state = curtin_net.parse_net_config(cls.conf_file) |
810 | @@ -520,8 +499,9 @@ |
811 | disks = disks * cls.multipath_num_paths |
812 | |
813 | cmd.extend(uefi_flags + netdevs + disks + |
814 | - [boot_img, "--kernel=%s" % boot_kernel, "--initrd=%s" % |
815 | - boot_initrd, "--", "curtin", "-vv", "install"] + |
816 | + [ftypes['vmtest.root-image'], "--kernel=%s" % |
817 | + ftypes['boot-kernel'], "--initrd=%s" % |
818 | + ftypes['boot-initrd'], "--", "curtin", "-vv", "install"] + |
819 | ["--config=%s" % f for f in configs] + |
820 | [install_src]) |
821 | |
822 | @@ -539,8 +519,8 @@ |
823 | raise |
824 | finally: |
825 | if os.path.exists(cls.install_log): |
826 | - with open(cls.install_log, 'rb') as l: |
827 | - content = l.read().decode('utf-8', errors='replace') |
828 | + with open(cls.install_log, 'rb') as lfh: |
829 | + content = lfh.read().decode('utf-8', errors='replace') |
830 | logger.debug('install serial console output:\n%s', content) |
831 | else: |
832 | logger.warn("Boot for install did not produce a console log.") |
833 | @@ -548,8 +528,8 @@ |
834 | logger.debug('') |
835 | try: |
836 | if os.path.exists(cls.install_log): |
837 | - with open(cls.install_log, 'rb') as l: |
838 | - install_log = l.read().decode('utf-8', errors='replace') |
839 | + with open(cls.install_log, 'rb') as lfh: |
840 | + install_log = lfh.read().decode('utf-8', errors='replace') |
841 | errmsg, errors = check_install_log(install_log) |
842 | if errmsg: |
843 | for e in errors: |
844 | @@ -650,8 +630,8 @@ |
845 | raise e |
846 | finally: |
847 | if os.path.exists(cls.boot_log): |
848 | - with open(cls.boot_log, 'rb') as l: |
849 | - content = l.read().decode('utf-8', errors='replace') |
850 | + with open(cls.boot_log, 'rb') as lfh: |
851 | + content = lfh.read().decode('utf-8', errors='replace') |
852 | logger.debug('boot serial console output:\n%s', content) |
853 | else: |
854 | logger.warn("Booting after install not produce" |
855 | @@ -837,21 +817,6 @@ |
856 | separators=(',', ': ')) + "\n") |
857 | |
858 | |
859 | -class PsuedoImageStore(object): |
860 | - def __init__(self, source_url, base_dir): |
861 | - self.source_url = source_url |
862 | - self.base_dir = base_dir |
863 | - |
864 | - def get_image(self, release, arch, krel=None): |
865 | - """Return tuple of version info, and paths for root image, |
866 | - kernel, initrd, tarball.""" |
867 | - names = ['psuedo-root-image', 'psuedo-kernel', 'psuedo-initrd', |
868 | - 'psuedo-tarball'] |
869 | - return ( |
870 | - "psuedo-%s %s/hwe-P 20160101" % (release, arch), |
871 | - [os.path.join(self.base_dir, release, arch, f) for f in names]) |
872 | - |
873 | - |
874 | class PsuedoVMBaseClass(VMBaseClass): |
875 | # This mimics much of the VMBaseClass just with faster setUpClass |
876 | # The tests here will fail only if CURTIN_VMTEST_DEBUG_ALLOW_FAIL |
877 | @@ -859,7 +824,6 @@ |
878 | # during a 'make vmtest' (keeping it running) but not to break test. |
879 | # |
880 | # boot_timeouts is a dict of {'purpose': 'mesg'} |
881 | - image_store_class = PsuedoImageStore |
882 | # boot_results controls what happens when boot_system is called |
883 | # a dictionary with key of the 'purpose' |
884 | # inside each dictionary: |
885 | @@ -883,6 +847,21 @@ |
886 | "LABEL=root / ext4 defaults 0 1"))) |
887 | |
888 | @classmethod |
889 | + def get_test_files(cls): |
890 | + """Return tuple of version info, and paths for root image, |
891 | + kernel, initrd, tarball.""" |
892 | + |
893 | + def get_psuedo_path(name): |
894 | + return os.path.join(IMAGE_DIR, cls.release, cls.arch, name) |
895 | + |
896 | + return { |
897 | + 'vmtest.root-image': get_psuedo_path('psuedo-root-image'), |
898 | + 'boot-kernel': get_psuedo_path('psuedo-kernel'), |
899 | + 'boot-initrd': get_psuedo_path('psuedo-initrd'), |
900 | + 'vmtest.root-tgz': get_psuedo_path('psuedo-root-tgz') |
901 | + } |
902 | + |
903 | + @classmethod |
904 | def boot_system(cls, cmd, console_log, proc_out, timeout, purpose): |
905 | # this is separated for easy override in Psuedo classes |
906 | data = {'timeout_msg': None, 'timeout': 0, |
907 | @@ -1011,15 +990,17 @@ |
908 | collect_post = textwrap.dedent( |
909 | 'tar -C "%s" -cf "%s" .' % (output_dir, output_device)) |
910 | |
911 | - # failsafe poweroff runs on precise only, where power_state does |
912 | + # failsafe poweroff runs on precise and centos only, where power_state does |
913 | # not exist. |
914 | - precise_poweroff = textwrap.dedent("""#!/bin/sh -x |
915 | - [ "$(lsb_release -sc)" = "precise" ] || exit 0; |
916 | - shutdown -P now "Shutting down on precise" |
917 | + failsafe_poweroff = textwrap.dedent("""#!/bin/sh -x |
918 | + [ -e /etc/centos-release -o -e /etc/redhat-release ] && |
919 | + { shutdown -P now "Shutting down on centos"; } |
920 | + [ "$(lsb_release -sc)" = "precise" ] && |
921 | + { shutdown -P now "Shutting down on precise"; } |
922 | """) |
923 | |
924 | scripts = ([collect_prep] + collect_scripts + [collect_post] + |
925 | - [precise_poweroff]) |
926 | + [failsafe_poweroff]) |
927 | |
928 | for part in scripts: |
929 | if not part.startswith("#!"): |
930 | |
931 | === modified file 'tests/vmtests/helpers.py' |
932 | --- tests/vmtests/helpers.py 2016-10-03 18:43:46 +0000 |
933 | +++ tests/vmtests/helpers.py 2017-01-18 16:16:23 +0000 |
934 | @@ -67,6 +67,7 @@ |
935 | |
936 | return 0 |
937 | |
938 | + |
939 | try: |
940 | TimeoutExpired = subprocess.TimeoutExpired |
941 | except AttributeError: |
942 | @@ -99,10 +100,13 @@ |
943 | return Command(cmd, signal).run(**kwargs) |
944 | |
945 | |
946 | -def find_releases(): |
947 | - """Return a sorted list of releases defined in test cases.""" |
948 | - # Use the TestLoader to load all tests cases defined within |
949 | - # tests/vmtests/ and figure out which releases they are testing. |
950 | +def find_releases_by_distro(): |
951 | + """ |
952 | + Returns a dictionary of distros and the distro releases that will be tested |
953 | + """ |
954 | + # Use the TestLoder to load all test cases defined within tests/vmtests/ |
955 | + # and figure out what distros and releases they are testing. Any tests |
956 | + # which are disabled will be excluded. |
957 | loader = TestLoader() |
958 | # dir with the vmtest modules (i.e. tests/vmtests/) |
959 | tests_dir = os.path.dirname(__file__) |
960 | @@ -110,13 +114,21 @@ |
961 | root_dir = os.path.split(os.path.split(tests_dir)[0])[0] |
962 | # Find all test modules defined in curtin/tests/vmtests/ |
963 | module_test_suites = loader.discover(tests_dir, top_level_dir=root_dir) |
964 | - releases = set() |
965 | + # find all distros and releases tested for each distro |
966 | + distros = {} |
967 | for mts in module_test_suites: |
968 | for class_test_suite in mts: |
969 | for test_case in class_test_suite: |
970 | - if getattr(test_case, 'release', ''): |
971 | - releases.add(getattr(test_case, 'release')) |
972 | - return sorted(releases) |
973 | + # skip disabled tests |
974 | + if not getattr(test_case, '__test__', False): |
975 | + continue |
976 | + for (dist, rel) in ( |
977 | + (getattr(test_case, a, None) for a in attrs) |
978 | + for attrs in (('distro', 'release'), |
979 | + ('target_distro', 'target_release'))): |
980 | + if dist and rel: |
981 | + distros[dist] = distros.get(dist, set()).union((rel,)) |
982 | + return {k: sorted(v) for (k, v) in distros.items()} |
983 | |
984 | |
985 | def _parse_ip_a(ip_a): |
986 | |
987 | === modified file 'tests/vmtests/image_sync.py' |
988 | --- tests/vmtests/image_sync.py 2016-10-03 18:00:41 +0000 |
989 | +++ tests/vmtests/image_sync.py 2017-01-18 16:16:23 +0000 |
990 | @@ -22,12 +22,16 @@ |
991 | IMAGE_SRC_URL = os.environ.get( |
992 | 'IMAGE_SRC_URL', |
993 | "http://maas.ubuntu.com/images/ephemeral-v2/daily/streams/v1/index.sjson") |
994 | +IMAGE_DIR = os.environ.get("IMAGE_DIR", "/srv/images") |
995 | |
996 | KEYRING = '/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg' |
997 | -ITEM_NAME_FILTERS = ['ftype~(root-image.gz|boot-initrd|boot-kernel)'] |
998 | +ITEM_NAME_FILTERS = ['ftype~(root-image.gz|boot-initrd|boot-kernel|root-tgz)'] |
999 | FORMAT_JSON = 'JSON' |
1000 | -VMTEST_CONTENT_ID = 'com.ubuntu.maas:daily:v2:download' |
1001 | -VMTEST_JSON_PATH = "streams/v1/vmtest.json" |
1002 | +STREAM_BASE = 'com.ubuntu.maas:daily' |
1003 | +VMTEST_CONTENT_ID_PATH_MAP = { |
1004 | + STREAM_BASE + ":v2:download": "streams/v1/vmtest.json", |
1005 | + STREAM_BASE + ":centos-bases-download": "streams/v1/vmtest-centos.json", |
1006 | +} |
1007 | |
1008 | DEFAULT_OUTPUT_FORMAT = ( |
1009 | "%(release)-7s %(arch)s/%(subarch)s %(version_name)-10s %(item_name)s") |
1010 | @@ -222,7 +226,10 @@ |
1011 | tver_data = products_version_get(target, pedigree) |
1012 | titems = tver_data.get('items') |
1013 | |
1014 | - if ('root-image.gz' in titems and |
1015 | + if not titems or 'root-image.gz' not in titems: |
1016 | + return |
1017 | + |
1018 | + if (titems['root-image.gz']['ftype'] == 'root-image.gz' and |
1019 | not (ri_name in titems and rtgz_name in titems)): |
1020 | # generate the root-image and root-tgz |
1021 | derived_items = generate_root_derived( |
1022 | @@ -231,6 +238,18 @@ |
1023 | for fname, item in derived_items.items(): |
1024 | self.insert_item(item, src, target, pedigree + (fname,), |
1025 | FakeContentSource(item['path'])) |
1026 | + elif (titems['root-image.gz']['ftype'] == 'root-tgz' and |
1027 | + rtgz_name not in titems): |
1028 | + # already have the root tgz, just need to add content as a |
1029 | + # vmtest.root-tgz |
1030 | + # TODO: may need to generate the vmtest.root-image at some point in |
1031 | + # the future if there is a need to use the centos image as an |
1032 | + # ephemeral environment rather than installing centos from |
1033 | + # an ubuntu ephemeral image |
1034 | + self.insert_item( |
1035 | + {'ftype': rtgz_name, 'path': titems['root-image.gz']['path']}, |
1036 | + src, target, pedigree + (rtgz_name,), |
1037 | + FakeContentSource(titems['root-image.gz']['path'])) |
1038 | |
1039 | def get_file_info(self, path): |
1040 | # check and see if we might know checksum and size |
1041 | @@ -262,11 +281,11 @@ |
1042 | self.store.insert_content(path, content) |
1043 | |
1044 | # for our vmtest content id, we want to write |
1045 | - # a vmtest.json in streams/v1/vmtest.json that can be queried |
1046 | + # a json file in streams/v1/<distro>.json that can be queried |
1047 | # even though it will not appear in index |
1048 | - if target['content_id'] == VMTEST_CONTENT_ID: |
1049 | - self.store.insert_content(VMTEST_JSON_PATH, |
1050 | - util.json_dumps(target)) |
1051 | + vmtest_json = VMTEST_CONTENT_ID_PATH_MAP.get(target['content_id']) |
1052 | + if vmtest_json: |
1053 | + self.store.insert_content(vmtest_json, util.json_dumps(target)) |
1054 | |
1055 | def insert_index_entry(self, data, src, pedigree, contentsource): |
1056 | # this is overridden, because the default implementation |
1057 | @@ -377,20 +396,15 @@ |
1058 | def query(mirror, max_items=1, filter_list=None, verbosity=0): |
1059 | if filter_list is None: |
1060 | filter_list = [] |
1061 | - |
1062 | ifilters = filters.get_filters(filter_list) |
1063 | |
1064 | def fpath(path): |
1065 | - # return the full path to a local file in the mirror |
1066 | return os.path.join(mirror, path) |
1067 | |
1068 | - try: |
1069 | - stree = sutil.load_content(util.load_file(fpath(VMTEST_JSON_PATH))) |
1070 | - except OSError: |
1071 | - raise |
1072 | - results = query_ptree(stree, max_num=max_items, ifilters=ifilters, |
1073 | - path2url=fpath) |
1074 | - return results |
1075 | + return next((q for q in ( |
1076 | + query_ptree(sutil.load_content(util.load_file(fpath(path))), |
1077 | + max_num=max_items, ifilters=ifilters, path2url=fpath) |
1078 | + for path in VMTEST_CONTENT_ID_PATH_MAP.values()) if q), None) |
1079 | |
1080 | |
1081 | def main_query(args): |
1082 | |
1083 | === modified file 'tests/vmtests/releases.py' |
1084 | --- tests/vmtests/releases.py 2016-10-03 18:00:41 +0000 |
1085 | +++ tests/vmtests/releases.py 2017-01-18 16:16:23 +0000 |
1086 | @@ -6,47 +6,68 @@ |
1087 | arch = get_platform_arch() |
1088 | |
1089 | |
1090 | -class _PreciseBase(_ReleaseBase): |
1091 | +class _UbuntuBase(_ReleaseBase): |
1092 | + distro = "ubuntu" |
1093 | + |
1094 | + |
1095 | +class _CentosFromUbuntuBase(_UbuntuBase): |
1096 | + # base for installing centos tarballs from ubuntu base |
1097 | + target_distro = "centos" |
1098 | + |
1099 | + |
1100 | +class _Centos70FromXenialBase(_CentosFromUbuntuBase): |
1101 | + # release for boot |
1102 | + release = "xenial" |
1103 | + # release for target |
1104 | + target_release = "centos70" |
1105 | + |
1106 | + |
1107 | +class _Centos66FromXenialBase(_CentosFromUbuntuBase): |
1108 | + release = "xenial" |
1109 | + target_release = "centos66" |
1110 | + |
1111 | + |
1112 | +class _PreciseBase(_UbuntuBase): |
1113 | release = "precise" |
1114 | |
1115 | |
1116 | -class _PreciseHWET(_ReleaseBase): |
1117 | +class _PreciseHWET(_UbuntuBase): |
1118 | release = "precise" |
1119 | krel = "trusty" |
1120 | |
1121 | |
1122 | -class _TrustyBase(_ReleaseBase): |
1123 | +class _TrustyBase(_UbuntuBase): |
1124 | release = "trusty" |
1125 | |
1126 | |
1127 | -class _TrustyHWEU(_ReleaseBase): |
1128 | +class _TrustyHWEU(_UbuntuBase): |
1129 | release = "trusty" |
1130 | krel = "utopic" |
1131 | |
1132 | |
1133 | -class _TrustyHWEV(_ReleaseBase): |
1134 | +class _TrustyHWEV(_UbuntuBase): |
1135 | release = "trusty" |
1136 | krel = "vivid" |
1137 | |
1138 | |
1139 | -class _TrustyHWEW(_ReleaseBase): |
1140 | +class _TrustyHWEW(_UbuntuBase): |
1141 | release = "trusty" |
1142 | krel = "wily" |
1143 | |
1144 | |
1145 | -class _VividBase(_ReleaseBase): |
1146 | +class _VividBase(_UbuntuBase): |
1147 | release = "vivid" |
1148 | |
1149 | |
1150 | -class _WilyBase(_ReleaseBase): |
1151 | +class _WilyBase(_UbuntuBase): |
1152 | release = "wily" |
1153 | |
1154 | |
1155 | -class _XenialBase(_ReleaseBase): |
1156 | +class _XenialBase(_UbuntuBase): |
1157 | release = "xenial" |
1158 | |
1159 | |
1160 | -class _YakketyBase(_ReleaseBase): |
1161 | +class _YakketyBase(_UbuntuBase): |
1162 | release = "yakkety" |
1163 | |
1164 | |
1165 | @@ -62,6 +83,13 @@ |
1166 | xenial = _XenialBase |
1167 | yakkety = _YakketyBase |
1168 | |
1169 | + |
1170 | +class _CentosReleases(object): |
1171 | + centos70fromxenial = _Centos70FromXenialBase |
1172 | + centos66fromxenial = _Centos66FromXenialBase |
1173 | + |
1174 | + |
1175 | base_vm_classes = _Releases |
1176 | +centos_base_vm_classes = _CentosReleases |
1177 | |
1178 | # vi: ts=4 expandtab syntax=python |
1179 | |
1180 | === modified file 'tests/vmtests/test_apt_config_cmd.py' |
1181 | --- tests/vmtests/test_apt_config_cmd.py 2016-10-03 18:42:29 +0000 |
1182 | +++ tests/vmtests/test_apt_config_cmd.py 2017-01-18 16:16:23 +0000 |
1183 | @@ -53,3 +53,7 @@ |
1184 | apt feature Test for Xenial using the standalone command |
1185 | """ |
1186 | __test__ = True |
1187 | + |
1188 | + |
1189 | +class YakketyTestAptConfigCMDCMD(relbase.yakkety, TestAptConfigCMD): |
1190 | + __test__ = True |
1191 | |
1192 | === added file 'tests/vmtests/test_centos_basic.py' |
1193 | --- tests/vmtests/test_centos_basic.py 1970-01-01 00:00:00 +0000 |
1194 | +++ tests/vmtests/test_centos_basic.py 2017-01-18 16:16:23 +0000 |
1195 | @@ -0,0 +1,42 @@ |
1196 | +from . import VMBaseClass |
1197 | +from .releases import centos_base_vm_classes as relbase |
1198 | + |
1199 | +import textwrap |
1200 | + |
1201 | + |
1202 | +# FIXME: should eventually be integrated with the real TestBasic |
1203 | +class CentosTestBasicAbs(VMBaseClass): |
1204 | + __test__ = False |
1205 | + conf_file = "examples/tests/centos_basic.yaml" |
1206 | + extra_kern_args = "BOOTIF=eth0-52:54:00:12:34:00" |
1207 | + collect_scripts = [textwrap.dedent( |
1208 | + """ |
1209 | + cd OUTPUT_COLLECT_D |
1210 | + cat /etc/fstab > fstab |
1211 | + """)] |
1212 | + fstab_expected = { |
1213 | + 'LABEL=cloudimg-rootfs': '/', |
1214 | + } |
1215 | + |
1216 | + def test_dname(self): |
1217 | + pass |
1218 | + |
1219 | + def test_interfacesd_eth0_removed(self): |
1220 | + pass |
1221 | + |
1222 | + def test_output_files_exist(self): |
1223 | + self.output_files_exist(["fstab"]) |
1224 | + |
1225 | + |
1226 | +# FIXME: this naming scheme needs to be replaced |
1227 | +class Centos70FromXenialTestBasic(relbase.centos70fromxenial, |
1228 | + CentosTestBasicAbs): |
1229 | + __test__ = True |
1230 | + |
1231 | + |
1232 | +class Centos66FromXenialTestBasic(relbase.centos66fromxenial, |
1233 | + CentosTestBasicAbs): |
1234 | + __test__ = False |
1235 | + # FIXME: test is disabled because the grub config script in target |
1236 | + # specifies drive using hd(1,0) syntax, which breaks when the |
1237 | + # installation medium is removed. other than this, the install works |
1238 | |
1239 | === modified file 'tests/vmtests/test_mdadm_bcache.py' |
1240 | --- tests/vmtests/test_mdadm_bcache.py 2016-10-03 18:43:46 +0000 |
1241 | +++ tests/vmtests/test_mdadm_bcache.py 2017-01-18 16:16:23 +0000 |
1242 | @@ -182,6 +182,45 @@ |
1243 | __test__ = True |
1244 | |
1245 | |
1246 | +class TestMirrorbootPartitionsAbs(TestMdadmAbs): |
1247 | + # alternative config for more complex setup |
1248 | + conf_file = "examples/tests/mirrorboot-msdos-partition.yaml" |
1249 | + # initialize secondary disk |
1250 | + extra_disks = ['10G'] |
1251 | + disk_to_check = [('main_disk', 1), |
1252 | + ('second_disk', 1), |
1253 | + ('md0', 2)] |
1254 | + |
1255 | + |
1256 | +class TrustyTestMirrorbootPartitions(relbase.trusty, |
1257 | + TestMirrorbootPartitionsAbs): |
1258 | + __test__ = True |
1259 | + |
1260 | + # FIXME(LP: #1523037): dname does not work on trusty |
1261 | + # when dname works on trusty, then we need to re-enable by removing line. |
1262 | + def test_dname(self): |
1263 | + print("test_dname does not work for Trusty") |
1264 | + |
1265 | + def test_ptable(self): |
1266 | + print("test_ptable does not work for Trusty") |
1267 | + |
1268 | + |
1269 | +class TrustyHWEUTestMirrorbootPartitions(relbase.trusty_hwe_u, |
1270 | + TrustyTestMirrorbootPartitions): |
1271 | + # This tests kernel upgrade in target |
1272 | + __test__ = True |
1273 | + |
1274 | + |
1275 | +class XenialTestMirrorbootPartitions(relbase.xenial, |
1276 | + TestMirrorbootPartitionsAbs): |
1277 | + __test__ = True |
1278 | + |
1279 | + |
1280 | +class YakketyTestMirrorbootPartitions(relbase.yakkety, |
1281 | + TestMirrorbootPartitionsAbs): |
1282 | + __test__ = True |
1283 | + |
1284 | + |
1285 | class TestRaid5bootAbs(TestMdadmAbs): |
1286 | # alternative config for more complex setup |
1287 | conf_file = "examples/tests/raid5boot.yaml" |
1288 | |
1289 | === modified file 'tests/vmtests/test_raid5_bcache.py' |
1290 | --- tests/vmtests/test_raid5_bcache.py 2016-10-03 18:43:46 +0000 |
1291 | +++ tests/vmtests/test_raid5_bcache.py 2017-01-18 16:16:23 +0000 |
1292 | @@ -91,7 +91,8 @@ |
1293 | |
1294 | |
1295 | class WilyTestRaid5Bcache(relbase.wily, TestMdadmBcacheAbs): |
1296 | - __test__ = True |
1297 | + # EOL - 2016-07-28 |
1298 | + __test__ = False |
1299 | |
1300 | |
1301 | class XenialTestRaid5Bcache(relbase.xenial, TestMdadmBcacheAbs): |
1302 | |
1303 | === modified file 'tools/vmtest-sync-images' |
1304 | --- tools/vmtest-sync-images 2016-10-03 18:00:41 +0000 |
1305 | +++ tools/vmtest-sync-images 2017-01-18 16:16:23 +0000 |
1306 | @@ -12,12 +12,16 @@ |
1307 | from tests.vmtests import ( |
1308 | IMAGE_DIR, IMAGE_SRC_URL, sync_images) |
1309 | from tests.vmtests.image_sync import ITEM_NAME_FILTERS |
1310 | -from tests.vmtests.helpers import find_releases |
1311 | +from tests.vmtests.helpers import find_releases_by_distro |
1312 | from curtin.util import get_platform_arch |
1313 | |
1314 | DEFAULT_ARCH = get_platform_arch() |
1315 | |
1316 | |
1317 | +def _fmt_list_filter(filter_name, matches): |
1318 | + return '~'.join((filter_name, '|'.join(matches))) |
1319 | + |
1320 | + |
1321 | if __name__ == '__main__': |
1322 | if len(sys.argv) > 1 and sys.argv[1] == "--clean": |
1323 | print("cleaning image dir %s" % IMAGE_DIR) |
1324 | @@ -35,11 +39,16 @@ |
1325 | os.unlink(fpath) |
1326 | |
1327 | arg_releases = [r for r in sys.argv[1:] if r != "--clean"] |
1328 | + arch_filters = ['arch={}'.format(DEFAULT_ARCH)] |
1329 | + filter_sets = [] |
1330 | if len(arg_releases): |
1331 | - releases = arg_releases |
1332 | + filter_sets.append([_fmt_list_filter('release', arg_releases)]) |
1333 | else: |
1334 | - releases = find_releases() |
1335 | - release_filter = 'release~{}'.format('|'.join(releases)) |
1336 | - my_filters = ['arch=' + DEFAULT_ARCH, release_filter] + ITEM_NAME_FILTERS |
1337 | + filter_sets.extend( |
1338 | + (['os={}'.format(distro), _fmt_list_filter('release', rels)] |
1339 | + for (distro, rels) in find_releases_by_distro().items())) |
1340 | + |
1341 | # Sync images. |
1342 | - sync_images(IMAGE_SRC_URL, IMAGE_DIR, filters=my_filters, verbosity=1) |
1343 | + for filter_set in filter_sets: |
1344 | + sync_images(IMAGE_SRC_URL, IMAGE_DIR, verbosity=1, |
1345 | + filters=filter_set + ITEM_NAME_FILTERS + arch_filters) |
1346 | |
1347 | === modified file 'tools/xkvm' |
1348 | --- tools/xkvm 2016-10-03 18:43:46 +0000 |
1349 | +++ tools/xkvm 2017-01-18 16:16:23 +0000 |
1350 | @@ -572,12 +572,12 @@ |
1351 | |
1352 | if [ $need_taps -ne 0 ]; then |
1353 | local missing="" missing_pkgs="" reqs="" req="" pkgs="" pkg="" |
1354 | - for i in "${connections[*]}"; do |
1355 | - [ "$i" = "user" -o -e "/sys/class/net/dev/$i" ] || |
1356 | + for i in "${connections[@]}"; do |
1357 | + [ "$i" = "user" -o -e "/sys/class/net/$i" ] || |
1358 | missing="${missing} $i" |
1359 | done |
1360 | [ -z "$missing" ] || { |
1361 | - error "cannot create connection on ${missing# }." |
1362 | + error "cannot create connection on: ${missing# }." |
1363 | error "bridges do not exist."; |
1364 | return 1; |
1365 | } |
+LGTM