Merge lp:~raharper/ubuntu/xenial/curtin/pkg-sru-revno399 into lp:~smoser/ubuntu/xenial/curtin/pkg
- Xenial (16.04)
- pkg-sru-revno399
- Merge into pkg
Proposed by
Ryan Harper
Status: | Merged | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Merged at revision: | 51 | ||||||||||||||||
Proposed branch: | lp:~raharper/ubuntu/xenial/curtin/pkg-sru-revno399 | ||||||||||||||||
Merge into: | lp:~smoser/ubuntu/xenial/curtin/pkg | ||||||||||||||||
Diff against target: |
2457 lines (+1095/-323) 35 files modified
curtin/block/__init__.py (+9/-3) curtin/commands/block_meta.py (+7/-2) curtin/commands/curthooks.py (+19/-3) curtin/commands/net_meta.py (+39/-28) curtin/net/__init__.py (+25/-5) curtin/reporter/handlers.py (+4/-13) curtin/util.py (+56/-0) debian/changelog (+19/-0) examples/tests/basic_network.yaml (+6/-0) examples/tests/basic_scsi.yaml (+72/-0) examples/tests/bonding_network.yaml (+2/-0) examples/tests/multipath.yaml (+38/-0) examples/tests/simple.yaml (+3/-0) helpers/common (+14/-6) tests/unittests/test_net.py (+49/-1) tests/unittests/test_reporter.py (+23/-2) tests/vmtests/__init__.py (+121/-58) tests/vmtests/helpers.py (+169/-0) tests/vmtests/image_sync.py (+16/-2) tests/vmtests/releases.py (+5/-0) tests/vmtests/test_basic.py (+121/-4) tests/vmtests/test_bcache_basic.py (+4/-0) tests/vmtests/test_bonding.py (+6/-44) tests/vmtests/test_lvm.py (+4/-4) tests/vmtests/test_mdadm_bcache.py (+24/-24) tests/vmtests/test_multipath.py (+63/-0) tests/vmtests/test_network.py (+19/-57) tests/vmtests/test_nvme.py (+4/-4) tests/vmtests/test_raid5_bcache.py (+8/-4) tests/vmtests/test_simple.py (+40/-0) tests/vmtests/test_uefi_basic.py (+8/-8) tools/jenkins-runner (+10/-0) tools/launch (+74/-44) tools/vmtest-sync-images (+5/-1) tools/xkvm (+9/-6) |
||||||||||||||||
To merge this branch: | bzr merge lp:~raharper/ubuntu/xenial/curtin/pkg-sru-revno399 | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Scott Moser | Approve | ||
Review via email: mp+299841@code.launchpad.net |
Commit message
Description of the change
SRU'ing revno399 into Xenial
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-05-10 16:13:29 +0000 |
3 | +++ curtin/block/__init__.py 2016-07-12 16:34:37 +0000 |
4 | @@ -356,6 +356,7 @@ |
5 | cmd.append('--replace-whitespace') |
6 | try: |
7 | (out, err) = util.subp(cmd, capture=True) |
8 | + LOG.debug("scsi_id output raw:\n%s\nerror:\n%s", out, err) |
9 | scsi_wwid = out.rstrip('\n') |
10 | return scsi_wwid |
11 | except util.ProcessExecutionError as e: |
12 | @@ -474,9 +475,14 @@ |
13 | """ |
14 | # Get all volumes in /dev/disk/by-id/ containing the serial string. The |
15 | # string specified can be either in the short or long serial format |
16 | - disks = list(filter(lambda x: serial in x, os.listdir("/dev/disk/by-id/"))) |
17 | + # hack, some serials have spaces, udev usually converts ' ' -> '_' |
18 | + serial_udev = serial.replace(' ', '_') |
19 | + LOG.info('Processing serial %s via udev to %s', serial, serial_udev) |
20 | + |
21 | + disks = list(filter(lambda x: serial_udev in x, |
22 | + os.listdir("/dev/disk/by-id/"))) |
23 | if not disks or len(disks) < 1: |
24 | - raise ValueError("no disk with serial '%s' found" % serial) |
25 | + raise ValueError("no disk with serial '%s' found" % serial_udev) |
26 | |
27 | # Sort by length and take the shortest path name, as the longer path names |
28 | # will be the partitions on the disk. Then use os.path.realpath to |
29 | @@ -486,7 +492,7 @@ |
30 | |
31 | if not os.path.exists(path): |
32 | raise ValueError("path '%s' to block device for disk with serial '%s' \ |
33 | - does not exist" % (path, serial)) |
34 | + does not exist" % (path, serial_udev)) |
35 | return path |
36 | |
37 | |
38 | |
39 | === modified file 'curtin/commands/block_meta.py' |
40 | --- curtin/commands/block_meta.py 2016-05-10 16:13:29 +0000 |
41 | +++ curtin/commands/block_meta.py 2016-07-12 16:34:37 +0000 |
42 | @@ -379,9 +379,14 @@ |
43 | if vol.get('serial'): |
44 | volume_path = block.lookup_disk(vol.get('serial')) |
45 | elif vol.get('path'): |
46 | - volume_path = vol.get('path') |
47 | + # resolve any symlinks to the dev_kname so sys/class/block access |
48 | + # is valid. ie, there are no udev generated values in sysfs |
49 | + volume_path = os.path.realpath(vol.get('path')) |
50 | + elif vol.get('wwn'): |
51 | + by_wwn = '/dev/disk/by-id/wwn-%s' % vol.get('wwn') |
52 | + volume_path = os.path.realpath(by_wwn) |
53 | else: |
54 | - raise ValueError("serial number or path to block dev must be \ |
55 | + raise ValueError("serial, wwn or path to block dev must be \ |
56 | specified to identify disk") |
57 | |
58 | elif vol.get('type') == "lvm_partition": |
59 | |
60 | === modified file 'curtin/commands/curthooks.py' |
61 | --- curtin/commands/curthooks.py 2016-06-03 13:50:09 +0000 |
62 | +++ curtin/commands/curthooks.py 2016-07-12 16:34:37 +0000 |
63 | @@ -238,7 +238,7 @@ |
64 | |
65 | def install_kernel(cfg, target): |
66 | kernel_cfg = cfg.get('kernel', {'package': None, |
67 | - 'fallback-package': None, |
68 | + 'fallback-package': "linux-generic", |
69 | 'mapping': {}}) |
70 | if kernel_cfg is not None: |
71 | kernel_package = kernel_cfg.get('package') |
72 | @@ -270,7 +270,7 @@ |
73 | LOG.warn("Couldn't detect kernel package to install for %s." |
74 | % kernel) |
75 | if kernel_fallback is not None: |
76 | - util.install_packages([kernel_fallback]) |
77 | + util.install_packages([kernel_fallback], target=target) |
78 | return |
79 | |
80 | package = "linux-{flavor}{map_suffix}".format( |
81 | @@ -638,6 +638,21 @@ |
82 | LOG.info("Detected multipath devices. Installing support via %s", mppkgs) |
83 | |
84 | util.install_packages(mppkgs, target=target) |
85 | + replace_spaces = True |
86 | + try: |
87 | + # check in-target version |
88 | + pkg_ver = util.get_package_version('multipath-tools', target=target) |
89 | + LOG.debug("get_package_version:\n%s", pkg_ver) |
90 | + LOG.debug("multipath version is %s (major=%s minor=%s micro=%s)", |
91 | + pkg_ver['semantic_version'], pkg_ver['major'], |
92 | + pkg_ver['minor'], pkg_ver['micro']) |
93 | + # multipath-tools versions < 0.5.0 do _NOT_ want whitespace replaced |
94 | + # i.e. 0.4.X in Trusty. |
95 | + if pkg_ver['semantic_version'] < 500: |
96 | + replace_spaces = False |
97 | + except Exception as e: |
98 | + LOG.warn("failed reading multipath-tools version, " |
99 | + "assuming it wants no spaces in wwids: %s", e) |
100 | |
101 | multipath_cfg_path = os.path.sep.join([target, '/etc/multipath.conf']) |
102 | multipath_bind_path = os.path.sep.join([target, '/etc/multipath/bindings']) |
103 | @@ -658,7 +673,8 @@ |
104 | if mpbindings or not os.path.isfile(multipath_bind_path): |
105 | # we do assume that get_devices_for_mp()[0] is / |
106 | target_dev = block.get_devices_for_mp(target)[0] |
107 | - wwid = block.get_scsi_wwid(target_dev) |
108 | + wwid = block.get_scsi_wwid(target_dev, |
109 | + replace_whitespace=replace_spaces) |
110 | blockdev, partno = block.get_blockdev_for_partition(target_dev) |
111 | |
112 | mpname = "mpath0" |
113 | |
114 | === modified file 'curtin/commands/net_meta.py' |
115 | --- curtin/commands/net_meta.py 2016-02-12 21:54:46 +0000 |
116 | +++ curtin/commands/net_meta.py 2016-07-12 16:34:37 +0000 |
117 | @@ -20,6 +20,7 @@ |
118 | import sys |
119 | |
120 | from curtin import net |
121 | +from curtin.log import LOG |
122 | import curtin.util as util |
123 | import curtin.config as config |
124 | |
125 | @@ -53,23 +54,20 @@ |
126 | raise ValueError("'%s' is not an alias: %s", alias, DEVNAME_ALIASES) |
127 | |
128 | |
129 | -def interfaces_basic_dhcp(devices): |
130 | - content = '\n'.join( |
131 | - [("# This file describes the network interfaces available on " |
132 | - "your system"), |
133 | - "# and how to activate them. For more information see interfaces(5).", |
134 | - "", |
135 | - "# The loopback network interface", |
136 | - "auto lo", |
137 | - "iface lo inet loopback", |
138 | - ]) |
139 | - |
140 | - for d in devices: |
141 | - content += '\n'.join(("", "", "auto %s" % d, |
142 | - "iface %s inet dhcp" % d,)) |
143 | - content += "\n" |
144 | - |
145 | - return content |
146 | +def interfaces_basic_dhcp(devices, macs=None): |
147 | + # return network configuration that says to dhcp on provided devices |
148 | + if macs is None: |
149 | + macs = {} |
150 | + for dev in devices: |
151 | + macs[dev] = net.get_interface_mac(dev) |
152 | + |
153 | + config = [] |
154 | + for dev in devices: |
155 | + config.append({ |
156 | + 'type': 'physical', 'name': dev, 'mac_address': macs.get(dev), |
157 | + 'subnets': [{'type': 'dhcp4'}]}) |
158 | + |
159 | + return {'network': {'version': 1, 'config': config}} |
160 | |
161 | |
162 | def interfaces_custom(args): |
163 | @@ -81,7 +79,7 @@ |
164 | raise Exception("network configuration is required by mode '%s' " |
165 | "but not provided in the config file" % 'custom') |
166 | |
167 | - return config.dump_config({'network': network_config}) |
168 | + return {'network': network_config} |
169 | |
170 | |
171 | def net_meta(args): |
172 | @@ -124,6 +122,9 @@ |
173 | else: |
174 | devices.append(dev) |
175 | |
176 | + LOG.debug("net-meta mode is '%s'. devices=%s", args.mode, devices) |
177 | + |
178 | + output_network_config = os.environ.get("OUTPUT_NETWORK_CONFIG", "") |
179 | if args.mode == "copy": |
180 | if not args.target: |
181 | raise argparse.ArgumentTypeError("mode 'copy' requires --target") |
182 | @@ -131,21 +132,31 @@ |
183 | t_eni = os.path.sep.join((args.target, "etc/network/interfaces",)) |
184 | with open(t_eni, "r") as fp: |
185 | content = fp.read() |
186 | + LOG.warn("net-meta mode is 'copy', static network interfaces files" |
187 | + "can be brittle. Copied interfaces: %s", content) |
188 | + target = args.output |
189 | |
190 | elif args.mode == "dhcp": |
191 | - content = interfaces_basic_dhcp(devices) |
192 | + target = output_network_config |
193 | + content = config.dump_config(interfaces_basic_dhcp(devices)) |
194 | + |
195 | elif args.mode == 'custom': |
196 | - content = interfaces_custom(args) |
197 | - # if we have a config, write it out to OUTPUT_NETWORK_CONFIG |
198 | - output_network_config = os.environ.get("OUTPUT_NETWORK_CONFIG", "") |
199 | - if output_network_config: |
200 | - with open(output_network_config, "w") as fp: |
201 | - fp.write(content) |
202 | - |
203 | - if args.output == "-": |
204 | + target = output_network_config |
205 | + content = config.dump_config(interfaces_custom(args)) |
206 | + |
207 | + else: |
208 | + raise Exception("Unexpected network config mode '%s'." % args.mode) |
209 | + |
210 | + if not target: |
211 | + raise Exception( |
212 | + "No target given for mode = '%s'. No where to write content: %s" % |
213 | + (args.mode, content)) |
214 | + |
215 | + LOG.debug("writing to file %s with network config: %s", target, content) |
216 | + if target == "-": |
217 | sys.stdout.write(content) |
218 | else: |
219 | - with open(args.output, "w") as fp: |
220 | + with open(target, "w") as fp: |
221 | fp.write(content) |
222 | |
223 | sys.exit(0) |
224 | |
225 | === modified file 'curtin/net/__init__.py' |
226 | --- curtin/net/__init__.py 2016-05-10 16:13:29 +0000 |
227 | +++ curtin/net/__init__.py 2016-07-12 16:34:37 +0000 |
228 | @@ -331,7 +331,14 @@ |
229 | |
230 | |
231 | # TODO: switch to valid_map for attrs |
232 | -def iface_add_attrs(iface): |
233 | +def iface_add_attrs(iface, index): |
234 | + # If the index is non-zero, this is an alias interface. Alias interfaces |
235 | + # represent additional interface addresses, and should not have additional |
236 | + # attributes. (extra attributes here are almost always either incorrect, |
237 | + # or are applied to the parent interface.) So if this is an alias, stop |
238 | + # right here. |
239 | + if index != 0: |
240 | + return "" |
241 | content = "" |
242 | ignore_map = [ |
243 | 'control', |
244 | @@ -423,22 +430,30 @@ |
245 | iface['index'] = index |
246 | iface['mode'] = subnet['type'] |
247 | iface['control'] = subnet.get('control', 'auto') |
248 | + subnet_inet = 'inet' |
249 | if iface['mode'].endswith('6'): |
250 | - iface['inet'] += '6' |
251 | + # This is a request for DHCPv6. |
252 | + subnet_inet += '6' |
253 | elif iface['mode'] == 'static' and ":" in subnet['address']: |
254 | - iface['inet'] += '6' |
255 | + # This is a static IPv6 address. |
256 | + subnet_inet += '6' |
257 | + iface['inet'] = subnet_inet |
258 | if iface['mode'].startswith('dhcp'): |
259 | iface['mode'] = 'dhcp' |
260 | |
261 | content += iface_start_entry(iface, index) |
262 | content += iface_add_subnet(iface, subnet) |
263 | - content += iface_add_attrs(iface) |
264 | + content += iface_add_attrs(iface, index) |
265 | + if len(subnets) > 1 and index == 0: |
266 | + for i in range(1, len(subnets)): |
267 | + content += " post-up ifup %s:%s\n" % (iface['name'], |
268 | + i) |
269 | else: |
270 | # ifenslave docs say to auto the slave devices |
271 | if 'bond-master' in iface: |
272 | content += "auto {name}\n".format(**iface) |
273 | content += "iface {name} {inet} {mode}\n".format(**iface) |
274 | - content += iface_add_attrs(iface) |
275 | + content += iface_add_attrs(iface, index) |
276 | |
277 | for route in network_state.get('routes'): |
278 | content += render_route(route) |
279 | @@ -469,4 +484,9 @@ |
280 | LOG.info('Writing ' + cc_disable) |
281 | util.write_file(cc_disable, content='network: {config: disabled}\n') |
282 | |
283 | + |
284 | +def get_interface_mac(ifname): |
285 | + """Returns the string value of an interface's MAC Address""" |
286 | + return read_sys_net(ifname, "address", enoent=False) |
287 | + |
288 | # vi: ts=4 expandtab syntax=python |
289 | |
290 | === modified file 'curtin/reporter/handlers.py' |
291 | --- curtin/reporter/handlers.py 2016-05-10 16:13:29 +0000 |
292 | +++ curtin/reporter/handlers.py 2016-07-12 16:34:37 +0000 |
293 | @@ -23,7 +23,7 @@ |
294 | |
295 | |
296 | class LogHandler(ReportingHandler): |
297 | - """Publishes events to the cloud-init log at the ``INFO`` log level.""" |
298 | + """Publishes events to the curtin log at the ``DEBUG`` log level.""" |
299 | |
300 | def __init__(self, level="DEBUG"): |
301 | super(LogHandler, self).__init__() |
302 | @@ -39,9 +39,9 @@ |
303 | self.level = level |
304 | |
305 | def publish_event(self, event): |
306 | - """Publish an event to the ``INFO`` log level.""" |
307 | + """Publish an event to the ``DEBUG`` log level.""" |
308 | logger = logging.getLogger( |
309 | - '.'.join(['cloudinit', 'reporting', event.event_type, event.name])) |
310 | + '.'.join(['curtin', 'reporting', event.event_type, event.name])) |
311 | logger.log(self.level, event.as_string()) |
312 | |
313 | |
314 | @@ -55,7 +55,7 @@ |
315 | class WebHookHandler(ReportingHandler): |
316 | def __init__(self, endpoint, consumer_key=None, token_key=None, |
317 | token_secret=None, consumer_secret=None, timeout=None, |
318 | - retries=None, level="INFO"): |
319 | + retries=None, level="DEBUG"): |
320 | super(WebHookHandler, self).__init__() |
321 | |
322 | self.oauth_helper = url_helper.OauthUrlHelper( |
323 | @@ -72,15 +72,6 @@ |
324 | self.headers = {'Content-Type': 'application/json'} |
325 | |
326 | def publish_event(self, event): |
327 | - if isinstance(event.level, int): |
328 | - ev_level = event.level |
329 | - else: |
330 | - try: |
331 | - ev_level = getattr(logging, event.level.upper()) |
332 | - except: |
333 | - ev_level = logging.INFO |
334 | - if ev_level < self.level: |
335 | - return |
336 | try: |
337 | return self.oauth_helper.geturl( |
338 | url=self.endpoint, data=event.as_dict(), |
339 | |
340 | === modified file 'curtin/util.py' |
341 | --- curtin/util.py 2016-06-03 13:50:09 +0000 |
342 | +++ curtin/util.py 2016-07-12 16:34:37 +0000 |
343 | @@ -499,6 +499,62 @@ |
344 | return False |
345 | |
346 | |
347 | +def parse_dpkg_version(raw, name=None, semx=None): |
348 | + """Parse a dpkg version string into various parts and calcualate a |
349 | + numerical value of the version for use in comparing package versions |
350 | + |
351 | + returns a dictionary with the results |
352 | + """ |
353 | + if semx is None: |
354 | + semx = (10000, 100, 1) |
355 | + |
356 | + upstream = raw.split('-')[0] |
357 | + toks = upstream.split(".", 2) |
358 | + if len(toks) == 3: |
359 | + major, minor, micro = toks |
360 | + elif len(toks) == 2: |
361 | + major, minor, micro = (toks[0], toks[1], 0) |
362 | + elif len(toks) == 1: |
363 | + major, minor, micro = (toks[0], 0, 0) |
364 | + |
365 | + version = { |
366 | + 'major': major, |
367 | + 'minor': minor, |
368 | + 'micro': micro, |
369 | + 'raw': raw, |
370 | + 'upstream': upstream, |
371 | + } |
372 | + if name: |
373 | + version['name'] = name |
374 | + |
375 | + if semx: |
376 | + try: |
377 | + version['semantic_version'] = int( |
378 | + int(major) * semx[0] + int(minor) * semx[1] + |
379 | + int(micro) * semx[2]) |
380 | + except (ValueError, IndexError): |
381 | + version['semantic_version'] = None |
382 | + |
383 | + return version |
384 | + |
385 | + |
386 | +def get_package_version(pkg, target=None, semx=None): |
387 | + """Use dpkg-query to extract package pkg's version string |
388 | + and parse the version string into a dictionary |
389 | + """ |
390 | + chroot = [] |
391 | + if target is not None: |
392 | + chroot = ['chroot', target] |
393 | + try: |
394 | + out, _ = subp(chroot + ['dpkg-query', '--show', '--showformat', |
395 | + '${Version}', pkg], |
396 | + capture=True) |
397 | + raw = out.rstrip() |
398 | + return parse_dpkg_version(raw, name=pkg, semx=semx) |
399 | + except ProcessExecutionError: |
400 | + return None |
401 | + |
402 | + |
403 | def find_newer(src, files): |
404 | mtime = os.stat(src).st_mtime |
405 | return [f for f in files if |
406 | |
407 | === modified file 'debian/changelog' |
408 | --- debian/changelog 2016-06-03 14:35:22 +0000 |
409 | +++ debian/changelog 2016-07-12 16:34:37 +0000 |
410 | @@ -1,3 +1,22 @@ |
411 | +curtin (0.1.0~bzr399-0ubuntu1~16.04.1) xenial; urgency=medium |
412 | + |
413 | + * sru current curtin |
414 | + - curtin/net: fix inet value for subnets, don't add interface attributes |
415 | + to alias (LP: #1588547) |
416 | + - improve net-meta network configuration (LP: #1592149) |
417 | + - reporting: set webhook handler level to DEBUG, no filtering |
418 | + (LP: #1590846) |
419 | + - tests/vmtests: add yakkety, remove vivid |
420 | + - curtin/net: use post-up for interface alias, resolve 120 second time out |
421 | + on Trusty when using interface aliases |
422 | + - vmtest: provide info on images used |
423 | + - fix multipath configuration and add multipath tests (LP: #1551937) |
424 | + - tools/launch and tools/xkvm: whitespace cleanup and bash -x |
425 | + - tools/launch: boot by root=LABEL=cloudimg-rootfs |
426 | + - Initial vmtest power8 support and TestSimple test. |
427 | + |
428 | + -- Ryan Harper <ryan.harper@canonical.com> Tue, 12 Jul 2016 11:29:30 -0500 |
429 | + |
430 | curtin (0.1.0~bzr389-0ubuntu1~16.04.1) xenial-proposed; urgency=medium |
431 | |
432 | * New upstream snapshot. |
433 | |
434 | === modified file 'examples/tests/basic_network.yaml' |
435 | --- examples/tests/basic_network.yaml 2016-06-03 13:50:09 +0000 |
436 | +++ examples/tests/basic_network.yaml 2016-07-12 16:34:37 +0000 |
437 | @@ -16,6 +16,12 @@ |
438 | - type: static |
439 | address: 10.0.2.100/24 |
440 | - type: static |
441 | + address: 10.0.3.100/24 |
442 | + - type: static |
443 | + address: 10.0.4.100/24 |
444 | + - type: static |
445 | + address: 10.0.5.100/24 |
446 | + - type: static |
447 | address: 10.0.2.200/24 |
448 | dns_nameservers: |
449 | - 8.8.8.8 |
450 | |
451 | === added file 'examples/tests/basic_scsi.yaml' |
452 | --- examples/tests/basic_scsi.yaml 1970-01-01 00:00:00 +0000 |
453 | +++ examples/tests/basic_scsi.yaml 2016-07-12 16:34:37 +0000 |
454 | @@ -0,0 +1,72 @@ |
455 | +showtrace: true |
456 | +storage: |
457 | + version: 1 |
458 | + config: |
459 | + - id: sda |
460 | + type: disk |
461 | + ptable: msdos |
462 | + wwn: '0x39cc071e72c64cc4' |
463 | + name: main_disk |
464 | + wipe: superblock |
465 | + grub_device: true |
466 | + - id: sda1 |
467 | + type: partition |
468 | + number: 1 |
469 | + size: 3GB |
470 | + device: sda |
471 | + flag: boot |
472 | + - id: sda2 |
473 | + type: partition |
474 | + number: 2 |
475 | + size: 1GB |
476 | + device: sda |
477 | + - id: sda1_root |
478 | + type: format |
479 | + fstype: ext4 |
480 | + volume: sda1 |
481 | + - id: sda2_home |
482 | + type: format |
483 | + fstype: ext4 |
484 | + volume: sda2 |
485 | + - id: sda1_mount |
486 | + type: mount |
487 | + path: / |
488 | + device: sda1_root |
489 | + - id: sda2_mount |
490 | + type: mount |
491 | + path: /home |
492 | + device: sda2_home |
493 | + - id: sparedisk_id |
494 | + type: disk |
495 | + wwn: '0x080258d13ea95ae5' |
496 | + name: sparedisk |
497 | + wipe: superblock |
498 | + - id: btrfs_disk_id |
499 | + type: disk |
500 | + wwn: '0x22dc58dc023c7008' |
501 | + name: btrfs_volume |
502 | + wipe: superblock |
503 | + - id: btrfs_disk_fmt_id |
504 | + type: format |
505 | + fstype: btrfs |
506 | + volume: btrfs_disk_id |
507 | + - id: btrfs_disk_mnt_id |
508 | + type: mount |
509 | + path: /btrfs |
510 | + device: btrfs_disk_fmt_id |
511 | + - id: pnum_disk |
512 | + type: disk |
513 | + wwn: '0x550a270c3a5811c5' |
514 | + name: pnum_disk |
515 | + wipe: superblock |
516 | + ptable: gpt |
517 | + - id: pnum_disk_p1 |
518 | + type: partition |
519 | + number: 1 |
520 | + size: 1GB |
521 | + device: pnum_disk |
522 | + - id: pnum_disk_p2 |
523 | + type: partition |
524 | + number: 10 |
525 | + size: 1GB |
526 | + device: pnum_disk |
527 | |
528 | === modified file 'examples/tests/bonding_network.yaml' |
529 | --- examples/tests/bonding_network.yaml 2016-06-03 13:50:09 +0000 |
530 | +++ examples/tests/bonding_network.yaml 2016-07-12 16:34:37 +0000 |
531 | @@ -26,6 +26,8 @@ |
532 | subnets: |
533 | - type: static |
534 | address: 10.23.23.2/24 |
535 | + - type: static |
536 | + address: 10.23.24.2/24 |
537 | |
538 | curthooks_commands: |
539 | # use curtin to disable open-iscsi ifupdown hooks for precise; they're |
540 | |
541 | === added file 'examples/tests/multipath.yaml' |
542 | --- examples/tests/multipath.yaml 1970-01-01 00:00:00 +0000 |
543 | +++ examples/tests/multipath.yaml 2016-07-12 16:34:37 +0000 |
544 | @@ -0,0 +1,38 @@ |
545 | +showtrace: true |
546 | +storage: |
547 | + version: 1 |
548 | + config: |
549 | + - id: sda |
550 | + type: disk |
551 | + ptable: msdos |
552 | + serial: 'IPR-0 1234567890' |
553 | + name: mpath_a |
554 | + wipe: superblock |
555 | + grub_device: true |
556 | + - id: sda1 |
557 | + type: partition |
558 | + number: 1 |
559 | + size: 3GB |
560 | + device: sda |
561 | + flag: boot |
562 | + - id: sda2 |
563 | + type: partition |
564 | + number: 2 |
565 | + size: 1GB |
566 | + device: sda |
567 | + - id: sda1_root |
568 | + type: format |
569 | + fstype: ext4 |
570 | + volume: sda1 |
571 | + - id: sda2_home |
572 | + type: format |
573 | + fstype: ext4 |
574 | + volume: sda2 |
575 | + - id: sda1_mount |
576 | + type: mount |
577 | + path: / |
578 | + device: sda1_root |
579 | + - id: sda2_mount |
580 | + type: mount |
581 | + path: /home |
582 | + device: sda2_home |
583 | |
584 | === added file 'examples/tests/simple.yaml' |
585 | --- examples/tests/simple.yaml 1970-01-01 00:00:00 +0000 |
586 | +++ examples/tests/simple.yaml 2016-07-12 16:34:37 +0000 |
587 | @@ -0,0 +1,3 @@ |
588 | +# This pushes curtin through a automatic installation |
589 | +# where no storage configuration is necessary. |
590 | +placeholder_simple_install: unused |
591 | |
592 | === modified file 'helpers/common' |
593 | --- helpers/common 2016-05-10 16:13:29 +0000 |
594 | +++ helpers/common 2016-07-12 16:34:37 +0000 |
595 | @@ -356,15 +356,17 @@ |
596 | local cmd="" isblk=false |
597 | [ -b "$target" ] && isblk=true |
598 | |
599 | + local pprep="1" proot="2" |
600 | wipedev "$target" || |
601 | { error "failed to clear $target"; return 1; } |
602 | |
603 | cmd=( |
604 | sgdisk |
605 | - --new "1::+8M" --typecode=1:4100 |
606 | - --new "2::$end" --typecode=2:8300 |
607 | + --new "${pprep}::+8M" "--typecode=${pprep}:4100" |
608 | + --new "${proot}::$end" "--typecode=${proot}:8300" |
609 | "$target" |
610 | ) |
611 | + debug 1 "partitioning '$target' with ${cmd[*]}" |
612 | "${cmd[@]}" || |
613 | fail "Failed to create GPT partitions (${cmd[*]})" |
614 | |
615 | @@ -374,13 +376,13 @@ |
616 | if $isblk; then |
617 | blockdev --rereadpt "$target" |
618 | udevadm settle |
619 | - assert_partitions "$target" 1 2 || |
620 | + assert_partitions "$target" "${proot}" "${pprep}" || |
621 | { error "$target missing partitions: $_RET"; return 1; } |
622 | # wipe the full prep partition |
623 | - wipe_partitions --full "$target" 1 || |
624 | + wipe_partitions --full "$target" "${pprep}" || |
625 | { error "$target: failed to wipe full PReP partition"; return 1;} |
626 | - wipe_partitions "$target" 2 || |
627 | - { error "$target: failed to wipe partition 2"; return 1;} |
628 | + wipe_partitions "$target" "${proot}" || |
629 | + { error "$target: failed to wipe partition ${proot}"; return 1;} |
630 | fi |
631 | |
632 | return 0 |
633 | @@ -695,6 +697,12 @@ |
634 | "${grub_name}" "${grub_target}" "$nvram" </dev/null || |
635 | { error "failed to install grub!"; return 1; } |
636 | else |
637 | + # Note: dpkg-reconfigure calls grub-install on ppc64 |
638 | + # this means that using '--no-nvram' below ends up |
639 | + # failing very oddly. This is because grub's post-inst |
640 | + # runs grub-install with no target. That ends up |
641 | + # updating nvram badly, and then the grub-install would |
642 | + # not fix it because of the no-nvram there. |
643 | debug 1 "installing ${grub_name} to: ${grubdevs[*]}" |
644 | chroot "$mp" env DEBIAN_FRONTEND=noninteractive sh -ec ' |
645 | pkg=$1; shift; |
646 | |
647 | === modified file 'tests/unittests/test_net.py' |
648 | --- tests/unittests/test_net.py 2016-06-03 13:50:09 +0000 |
649 | +++ tests/unittests/test_net.py 2016-07-12 16:34:37 +0000 |
650 | @@ -473,6 +473,7 @@ |
651 | |
652 | auto eth0 |
653 | iface eth0 inet dhcp |
654 | + post-up ifup eth0:1 |
655 | |
656 | auto eth0:1 |
657 | iface eth0:1 inet static |
658 | @@ -516,6 +517,11 @@ |
659 | bond-mode active-backup |
660 | hwaddress 52:54:00:12:34:06 |
661 | bond-slaves none |
662 | + post-up ifup bond0:1 |
663 | + |
664 | + auto bond0:1 |
665 | + iface bond0:1 inet static |
666 | + address 10.23.24.2/24 |
667 | |
668 | source /etc/network/interfaces.d/*.cfg |
669 | """) |
670 | @@ -545,11 +551,11 @@ |
671 | address 192.168.14.2/24 |
672 | gateway 192.168.14.1 |
673 | mtu 1492 |
674 | + post-up ifup interface1:1 |
675 | |
676 | auto interface1:1 |
677 | iface interface1:1 inet static |
678 | address 192.168.14.4/24 |
679 | - mtu 1492 |
680 | |
681 | allow-hotplug interface2 |
682 | iface interface2 inet static |
683 | @@ -566,4 +572,46 @@ |
684 | self.assertEqual(sorted(ifaces.split('\n')), |
685 | sorted(net_ifaces.split('\n'))) |
686 | |
687 | + def test_render_interfaces_ipv6_aliases(self): |
688 | + ipv6_aliases_config = ''' |
689 | +# YAML example of a simple network config |
690 | +network: |
691 | + version: 1 |
692 | + config: |
693 | + # Physical interfaces. |
694 | + - type: physical |
695 | + name: eth0 |
696 | + mac_address: "c0:d6:9f:2c:e8:80" |
697 | + subnets: |
698 | + - type: static |
699 | + address: fde9:8f83:4a81:1:0:1:0:6/64 |
700 | + - type: static |
701 | + address: 192.168.0.1/24 |
702 | +''' |
703 | + |
704 | + ns = self.get_net_state(ipv6_aliases_config) |
705 | + ifaces = dedent("""\ |
706 | + auto lo |
707 | + iface lo inet loopback |
708 | + |
709 | + auto eth0 |
710 | + iface eth0 inet6 static |
711 | + address fde9:8f83:4a81:1:0:1:0:6/64 |
712 | + post-up ifup eth0:1 |
713 | + |
714 | + auto eth0:1 |
715 | + iface eth0:1 inet static |
716 | + address 192.168.0.1/24 |
717 | + |
718 | + source /etc/network/interfaces.d/*.cfg |
719 | + """) |
720 | + net_ifaces = net.render_interfaces(ns.network_state) |
721 | + print("\n".join(sorted(ifaces.split('\n')))) |
722 | + print("\n^^ LOCAL -- RENDER vv") |
723 | + print("\n".join(sorted(net_ifaces.split('\n')))) |
724 | + print(ns.network_state.get('interfaces')) |
725 | + self.assertEqual(sorted(ifaces.split('\n')), |
726 | + sorted(net_ifaces.split('\n'))) |
727 | + |
728 | + |
729 | # vi: ts=4 expandtab syntax=python |
730 | |
731 | === modified file 'tests/unittests/test_reporter.py' |
732 | --- tests/unittests/test_reporter.py 2016-05-10 16:13:29 +0000 |
733 | +++ tests/unittests/test_reporter.py 2016-07-12 16:34:37 +0000 |
734 | @@ -128,7 +128,8 @@ |
735 | def test_webhook_handler(self, mock_url_helper): |
736 | event = events.ReportingEvent(events.START_EVENT_TYPE, 'test_event', |
737 | 'test event', level='INFO') |
738 | - webhook_handler = handlers.WebHookHandler('127.0.0.1:8000') |
739 | + webhook_handler = handlers.WebHookHandler('127.0.0.1:8000', |
740 | + level='INFO') |
741 | webhook_handler.publish_event(event) |
742 | webhook_handler.oauth_helper.geturl.assert_called_with( |
743 | url='127.0.0.1:8000', data=event.as_dict(), |
744 | @@ -136,7 +137,6 @@ |
745 | event.level = 'DEBUG' |
746 | webhook_handler.oauth_helper.geturl.called = False |
747 | webhook_handler.publish_event(event) |
748 | - self.assertFalse(webhook_handler.oauth_helper.geturl.called) |
749 | webhook_handler = handlers.WebHookHandler('127.0.0.1:8000', |
750 | level="INVALID") |
751 | self.assertEquals(webhook_handler.level, 30) |
752 | @@ -194,3 +194,24 @@ |
753 | base64.b64encode(test_data).decode()) |
754 | finally: |
755 | os.remove(tmp[1]) |
756 | + |
757 | + @patch('curtin.url_helper.OauthUrlHelper') |
758 | + def test_webhook_handler_post_files(self, mock_url_helper): |
759 | + test_data = b'abcdefg' |
760 | + tmp = tempfile.mkstemp() |
761 | + tmpfname = tmp[1] |
762 | + try: |
763 | + with open(tmpfname, 'wb') as fp: |
764 | + fp.write(test_data) |
765 | + event = events.FinishReportingEvent('test_event_name', |
766 | + 'test event description', |
767 | + post_files=[tmpfname], |
768 | + level='INFO') |
769 | + webhook_handler = handlers.WebHookHandler('127.0.0.1:8000', |
770 | + level='INFO') |
771 | + webhook_handler.publish_event(event) |
772 | + webhook_handler.oauth_helper.geturl.assert_called_with( |
773 | + url='127.0.0.1:8000', data=event.as_dict(), |
774 | + headers=webhook_handler.headers, retries=None) |
775 | + finally: |
776 | + os.remove(tmpfname) |
777 | |
778 | === modified file 'tests/vmtests/__init__.py' |
779 | --- tests/vmtests/__init__.py 2016-06-03 13:50:09 +0000 |
780 | +++ tests/vmtests/__init__.py 2016-07-12 16:34:37 +0000 |
781 | @@ -48,6 +48,7 @@ |
782 | |
783 | |
784 | DEFAULT_BRIDGE = os.environ.get("CURTIN_VMTEST_BRIDGE", "user") |
785 | +OUTPUT_DISK_NAME = 'output_disk.img' |
786 | |
787 | _TOPDIR = None |
788 | |
789 | @@ -223,6 +224,7 @@ |
790 | "Expected=%s" % (found, expected)) |
791 | for item in results: |
792 | ftypes[item['ftype']] = item['item_url'] |
793 | + last_item = item |
794 | |
795 | missing = [(ftype, path) for ftype, path in ftypes.items() |
796 | if not os.path.exists(path)] |
797 | @@ -230,7 +232,11 @@ |
798 | if len(missing): |
799 | raise ValueError("missing files for ftypes: %s" % missing) |
800 | |
801 | - return ftypes |
802 | + # trusty amd64/hwe-p 20150101 |
803 | + version_info = ('%(release)s %(arch)s/%(subarch)s %(version_name)s' % |
804 | + last_item) |
805 | + |
806 | + return version_info, ftypes |
807 | |
808 | |
809 | class ImageStore: |
810 | @@ -256,16 +262,17 @@ |
811 | self.url = pathlib.Path(self.base_dir).as_uri() |
812 | |
813 | def get_image(self, release, arch, krel=None): |
814 | - """Return local path for root image, kernel and initrd, tarball.""" |
815 | + """Return tuple of version info, and paths for root image, |
816 | + kernel, initrd, tarball.""" |
817 | if krel is None: |
818 | krel = release |
819 | - ftypes = get_images( |
820 | + ver_info, ftypes = get_images( |
821 | self.source_url, self.base_dir, release, arch, krel, self.sync) |
822 | root_image_path = ftypes['vmtest.root-image'] |
823 | kernel_path = ftypes['boot-kernel'] |
824 | initrd_path = ftypes['boot-initrd'] |
825 | tarball = ftypes['vmtest.root-tgz'] |
826 | - return (root_image_path, kernel_path, initrd_path, tarball) |
827 | + return ver_info, (root_image_path, kernel_path, initrd_path, tarball) |
828 | |
829 | |
830 | class TempDir(object): |
831 | @@ -327,7 +334,7 @@ |
832 | |
833 | # create output disk, mount ro |
834 | logger.debug('Creating output disk') |
835 | - self.output_disk = os.path.join(self.boot, "output_disk.img") |
836 | + self.output_disk = os.path.join(self.boot, OUTPUT_DISK_NAME) |
837 | subprocess.check_call(["qemu-img", "create", "-f", TARGET_IMAGE_FORMAT, |
838 | self.output_disk, "10M"], |
839 | stdout=DEVNULL, stderr=subprocess.STDOUT) |
840 | @@ -344,20 +351,23 @@ |
841 | class VMBaseClass(TestCase): |
842 | __test__ = False |
843 | arch_skip = [] |
844 | + boot_timeout = 300 |
845 | + collect_scripts = [] |
846 | + conf_file = "examples/tests/basic.yaml" |
847 | disk_block_size = 512 |
848 | + disk_driver = 'virtio-blk' |
849 | disk_to_check = {} |
850 | + extra_disks = [] |
851 | + extra_kern_args = None |
852 | fstab_expected = {} |
853 | - extra_kern_args = None |
854 | - recorded_errors = 0 |
855 | - recorded_failures = 0 |
856 | image_store_class = ImageStore |
857 | - collect_scripts = [] |
858 | + install_timeout = 3000 |
859 | interactive = False |
860 | - conf_file = "examples/tests/basic.yaml" |
861 | - extra_disks = [] |
862 | + multipath = False |
863 | + multipath_num_paths = 2 |
864 | nvme_disks = [] |
865 | - boot_timeout = 300 |
866 | - install_timeout = 3000 |
867 | + recorded_errors = 0 |
868 | + recorded_failures = 0 |
869 | uefi = False |
870 | |
871 | # these get set from base_vm_classes |
872 | @@ -380,15 +390,17 @@ |
873 | # Disable sync if env var is set. |
874 | image_store.sync = get_env_var_bool('CURTIN_VMTEST_IMAGE_SYNC', False) |
875 | logger.debug("Image sync = %s", image_store.sync) |
876 | - (boot_img, boot_kernel, boot_initrd, tarball) = image_store.get_image( |
877 | - cls.release, cls.arch, cls.krel) |
878 | - |
879 | + img_verstr, (boot_img, boot_kernel, boot_initrd, tarball) = ( |
880 | + image_store.get_image(cls.release, cls.arch, cls.krel)) |
881 | + logger.debug("Image %s\n boot=%s\n kernel=%s\n initrd=%s\n" |
882 | + " tarball=%s\n", img_verstr, boot_img, boot_kernel, |
883 | + boot_initrd, tarball) |
884 | # set up tempdir |
885 | cls.td = TempDir( |
886 | name=cls.__name__, |
887 | user_data=generate_user_data(collect_scripts=cls.collect_scripts)) |
888 | - logger.info('Using tempdir: {}'.format(cls.td.tmpdir)) |
889 | - |
890 | + logger.info('Using tempdir: %s , Image: %s', cls.td.tmpdir, |
891 | + img_verstr) |
892 | cls.install_log = os.path.join(cls.td.logs, 'install-serial.log') |
893 | cls.boot_log = os.path.join(cls.td.logs, 'boot-serial.log') |
894 | logger.debug('Install console log: {}'.format(cls.install_log)) |
895 | @@ -438,21 +450,51 @@ |
896 | netdevs.extend(["--netdev=" + DEFAULT_BRIDGE]) |
897 | |
898 | # build disk arguments |
899 | - # --disk source:size:driver:block_size |
900 | - extra_disks = [] |
901 | + disks = [] |
902 | + sc = util.load_file(cls.conf_file) |
903 | + storage_config = yaml.load(sc).get('storage', {}).get('config', {}) |
904 | + cls.disk_wwns = ["wwn=%s" % x.get('wwn') for x in storage_config |
905 | + if 'wwn' in x] |
906 | + cls.disk_serials = ["serial=%s" % x.get('serial') |
907 | + for x in storage_config if 'serial' in x] |
908 | + |
909 | + target_disk = "{}:{}:{}:{}:".format(cls.td.target_disk, |
910 | + "", |
911 | + cls.disk_driver, |
912 | + cls.disk_block_size) |
913 | + if len(cls.disk_wwns): |
914 | + target_disk += cls.disk_wwns[0] |
915 | + |
916 | + if len(cls.disk_serials): |
917 | + target_disk += cls.disk_serials[0] |
918 | + |
919 | + disks.extend(['--disk', target_disk]) |
920 | + |
921 | + # --disk source:size:driver:block_size:devopts |
922 | for (disk_no, disk_sz) in enumerate(cls.extra_disks): |
923 | dpath = os.path.join(cls.td.disks, 'extra_disk_%d.img' % disk_no) |
924 | - extra_disks.extend( |
925 | - ['--disk', '{}:{}:{}:{}'.format(dpath, disk_sz, "", |
926 | - cls.disk_block_size)]) |
927 | + extra_disk = '{}:{}:{}:{}:'.format(dpath, disk_sz, |
928 | + cls.disk_driver, |
929 | + cls.disk_block_size) |
930 | + if len(cls.disk_wwns): |
931 | + w_index = disk_no + 1 |
932 | + if w_index < len(cls.disk_wwns): |
933 | + extra_disk += cls.disk_wwns[w_index] |
934 | + |
935 | + if len(cls.disk_serials): |
936 | + w_index = disk_no + 1 |
937 | + if w_index < len(cls.disk_serials): |
938 | + extra_disk += cls.disk_serials[w_index] |
939 | + |
940 | + disks.extend(['--disk', extra_disk]) |
941 | |
942 | # build nvme disk args if needed |
943 | - nvme_disks = [] |
944 | for (disk_no, disk_sz) in enumerate(cls.nvme_disks): |
945 | dpath = os.path.join(cls.td.disks, 'nvme_disk_%d.img' % disk_no) |
946 | - nvme_disks.extend( |
947 | - ['--disk', '{}:{}:nvme:{}'.format(dpath, disk_sz, |
948 | - cls.disk_block_size)]) |
949 | + nvme_disk = '{}:{}:nvme:{}:{}'.format(dpath, disk_sz, |
950 | + cls.disk_block_size, |
951 | + "serial=nvme-%d" % disk_no) |
952 | + disks.extend(['--disk', nvme_disk]) |
953 | |
954 | # proxy config |
955 | configs = [cls.conf_file] |
956 | @@ -477,11 +519,10 @@ |
957 | shutil.copy(OVMF_VARS, nvram) |
958 | cmd.extend(["--uefi", nvram]) |
959 | |
960 | - # --disk source:size:driver:block_size |
961 | - target_disk = "{}:{}:{}:{}".format(cls.td.target_disk, "", "", |
962 | - cls.disk_block_size) |
963 | - cmd.extend(netdevs + ["--disk", target_disk] + |
964 | - extra_disks + nvme_disks + |
965 | + if cls.multipath: |
966 | + disks = disks * cls.multipath_num_paths |
967 | + |
968 | + cmd.extend(netdevs + disks + |
969 | [boot_img, "--kernel=%s" % boot_kernel, "--initrd=%s" % |
970 | boot_initrd, "--", "curtin", "-vv", "install"] + |
971 | ["--config=%s" % f for f in configs] + |
972 | @@ -510,8 +551,8 @@ |
973 | logger.debug('') |
974 | try: |
975 | if os.path.exists(cls.install_log): |
976 | - with open(cls.install_log) as l: |
977 | - install_log = l.read() |
978 | + with open(cls.install_log, 'rb') as l: |
979 | + install_log = l.read().decode('utf-8', errors='replace') |
980 | errmsg, errors = check_install_log(install_log) |
981 | if errmsg: |
982 | for e in errors: |
983 | @@ -527,39 +568,58 @@ |
984 | cls.tearDownClass() |
985 | raise |
986 | |
987 | - # drop the size parameter if present in extra_disks |
988 | - extra_disks = [x if ":" not in x else x.split(':')[0] |
989 | - for x in extra_disks] |
990 | # create --disk params for nvme disks |
991 | bsize_args = "logical_block_size={}".format(cls.disk_block_size) |
992 | bsize_args += ",physical_block_size={}".format(cls.disk_block_size) |
993 | bsize_args += ",min_io_size={}".format(cls.disk_block_size) |
994 | - disk_driver = "virtio-blk" |
995 | |
996 | target_disks = [] |
997 | - for (disk_no, disk) in enumerate([cls.td.target_disk, |
998 | - cls.td.output_disk]): |
999 | - d = '--disk={},driver={},format={},{}'.format(disk, disk_driver, |
1000 | - TARGET_IMAGE_FORMAT, |
1001 | - bsize_args) |
1002 | - target_disks.extend([d]) |
1003 | + for (disk_no, disk) in enumerate([cls.td.target_disk]): |
1004 | + disk = '--disk={},driver={},format={},{}'.format( |
1005 | + disk, cls.disk_driver, TARGET_IMAGE_FORMAT, bsize_args) |
1006 | + if len(cls.disk_wwns): |
1007 | + disk += ",%s" % cls.disk_wwns[0] |
1008 | + if len(cls.disk_serials): |
1009 | + disk += ",%s" % cls.disk_serials[0] |
1010 | + |
1011 | + target_disks.extend([disk]) |
1012 | |
1013 | extra_disks = [] |
1014 | for (disk_no, disk_sz) in enumerate(cls.extra_disks): |
1015 | dpath = os.path.join(cls.td.disks, 'extra_disk_%d.img' % disk_no) |
1016 | - d = '--disk={},driver={},format={},{}'.format(dpath, disk_driver, |
1017 | - TARGET_IMAGE_FORMAT, |
1018 | - bsize_args) |
1019 | - extra_disks.extend([d]) |
1020 | + disk = '--disk={},driver={},format={},{}'.format( |
1021 | + dpath, cls.disk_driver, TARGET_IMAGE_FORMAT, bsize_args) |
1022 | + if len(cls.disk_wwns): |
1023 | + w_index = disk_no + 1 |
1024 | + if w_index < len(cls.disk_wwns): |
1025 | + disk += ",%s" % cls.disk_wwns[w_index] |
1026 | + |
1027 | + if len(cls.disk_serials): |
1028 | + w_index = disk_no + 1 |
1029 | + if w_index < len(cls.disk_serials): |
1030 | + disk += ",%s" % cls.disk_serials[w_index] |
1031 | + |
1032 | + extra_disks.extend([disk]) |
1033 | |
1034 | nvme_disks = [] |
1035 | disk_driver = 'nvme' |
1036 | for (disk_no, disk_sz) in enumerate(cls.nvme_disks): |
1037 | dpath = os.path.join(cls.td.disks, 'nvme_disk_%d.img' % disk_no) |
1038 | - d = '--disk={},driver={},format={},{}'.format(dpath, disk_driver, |
1039 | - TARGET_IMAGE_FORMAT, |
1040 | - bsize_args) |
1041 | - nvme_disks.extend([d]) |
1042 | + disk = '--disk={},driver={},format={},{}'.format( |
1043 | + dpath, disk_driver, TARGET_IMAGE_FORMAT, bsize_args) |
1044 | + nvme_disks.extend([disk]) |
1045 | + |
1046 | + if cls.multipath: |
1047 | + target_disks = target_disks * cls.multipath_num_paths |
1048 | + extra_disks = extra_disks * cls.multipath_num_paths |
1049 | + nvme_disks = nvme_disks * cls.multipath_num_paths |
1050 | + |
1051 | + # output disk is always virtio-blk, with serial of output_disk.img |
1052 | + output_disk = '--disk={},driver={},format={},{},{}'.format( |
1053 | + cls.td.output_disk, 'virtio-blk', |
1054 | + TARGET_IMAGE_FORMAT, bsize_args, |
1055 | + 'serial=%s' % os.path.basename(cls.td.output_disk)) |
1056 | + target_disks.extend([output_disk]) |
1057 | |
1058 | # create xkvm cmd |
1059 | cmd = (["tools/xkvm", "-v", dowait] + netdevs + |
1060 | @@ -788,10 +848,13 @@ |
1061 | self.base_dir = base_dir |
1062 | |
1063 | def get_image(self, release, arch, krel=None): |
1064 | - """Return local path for root image, kernel and initrd, tarball.""" |
1065 | + """Return tuple of version info, and paths for root image, |
1066 | + kernel, initrd, tarball.""" |
1067 | names = ['psuedo-root-image', 'psuedo-kernel', 'psuedo-initrd', |
1068 | 'psuedo-tarball'] |
1069 | - return [os.path.join(self.base_dir, release, arch, f) for f in names] |
1070 | + return ( |
1071 | + "psuedo-%s %s/hwe-P 20160101" % (release, arch), |
1072 | + [os.path.join(self.base_dir, release, arch, f) for f in names]) |
1073 | |
1074 | |
1075 | class PsuedoVMBaseClass(VMBaseClass): |
1076 | @@ -940,9 +1003,9 @@ |
1077 | 'content': yaml.dump(base_cloudconfig, indent=1)}, |
1078 | {'type': 'text/cloud-config', 'content': ssh_keys}] |
1079 | |
1080 | + output_dir = '/mnt/output' |
1081 | output_dir_macro = 'OUTPUT_COLLECT_D' |
1082 | - output_dir = '/mnt/output' |
1083 | - output_device = '/dev/vdb' |
1084 | + output_device = '/dev/disk/by-id/virtio-%s' % OUTPUT_DISK_NAME |
1085 | |
1086 | collect_prep = textwrap.dedent("mkdir -p " + output_dir) |
1087 | collect_post = textwrap.dedent( |
1088 | @@ -950,7 +1013,7 @@ |
1089 | |
1090 | # failsafe poweroff runs on precise only, where power_state does |
1091 | # not exist. |
1092 | - precise_poweroff = textwrap.dedent("""#!/bin/sh |
1093 | + precise_poweroff = textwrap.dedent("""#!/bin/sh -x |
1094 | [ "$(lsb_release -sc)" = "precise" ] || exit 0; |
1095 | shutdown -P now "Shutting down on precise" |
1096 | """) |
1097 | @@ -960,7 +1023,7 @@ |
1098 | |
1099 | for part in scripts: |
1100 | if not part.startswith("#!"): |
1101 | - part = "#!/bin/sh\n" + part |
1102 | + part = "#!/bin/sh -x\n" + part |
1103 | part = part.replace(output_dir_macro, output_dir) |
1104 | logger.debug('Cloud config archive content (pre-json):' + part) |
1105 | parts.append({'content': part, 'type': 'text/x-shellscript'}) |
1106 | |
1107 | === modified file 'tests/vmtests/helpers.py' |
1108 | --- tests/vmtests/helpers.py 2016-02-12 21:54:46 +0000 |
1109 | +++ tests/vmtests/helpers.py 2016-07-12 16:34:37 +0000 |
1110 | @@ -117,3 +117,172 @@ |
1111 | if getattr(test_case, 'release', ''): |
1112 | releases.add(getattr(test_case, 'release')) |
1113 | return sorted(releases) |
1114 | + |
1115 | + |
1116 | +def _parse_ifconfig_xenial(ifconfig_out): |
1117 | + """Parse ifconfig output from xenial or earlier and return a dictionary. |
1118 | + given content like below, return: |
1119 | + {'eth0': {'address': '10.8.1.78', 'broadcast': '10.8.1.255', |
1120 | + 'inet6': [{'address': 'fe80::216:3eff:fe63:c05d', |
1121 | + 'prefixlen': '64', 'scope': 'Link'}, |
1122 | + {'address': 'fdec:2922:2f07:0:216:3eff:fe63:c05d', |
1123 | + 'prefixlen': '64', 'scope': 'Global'}], |
1124 | + 'interface': 'eth0', 'link_encap': 'Ethernet', |
1125 | + 'mac_address': '00:16:3e:63:c0:5d', 'mtu': 1500, |
1126 | + 'multicast': True, 'netmask': '255.255.255.0', |
1127 | + 'running': True, 'up': True}} |
1128 | + |
1129 | + eth0 Link encap:Ethernet HWaddr 00:16:3e:63:c0:5d |
1130 | + inet addr:10.8.1.78 Bcast:10.8.1.255 Mask:255.255.255.0 |
1131 | + inet6 addr: fe80::216:3eff:fe63:c05d/64 Scope:Link |
1132 | + inet6 addr: fdec:2922:2f07:0:216:3eff:fe63:c05d/64 Scope:Global |
1133 | + UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 |
1134 | + RX packets:21503 errors:0 dropped:0 overruns:0 frame:0 |
1135 | + TX packets:11346 errors:0 dropped:0 overruns:0 carrier:0 |
1136 | + collisions:0 txqueuelen:1000 |
1137 | + RX bytes:31556357 (31.5 MB) TX bytes:870943 (870.9 KB) |
1138 | + """ |
1139 | + ifaces = {} |
1140 | + combined_fields = {'addr': 'address', 'Bcast': 'broadcast', |
1141 | + 'Mask': 'netmask', 'MTU': 'mtu', |
1142 | + 'encap': 'link_encap'} |
1143 | + boolmap = {'RUNNING': 'running', 'UP': 'up', 'MULTICAST': 'multicast'} |
1144 | + |
1145 | + for line in ifconfig_out.splitlines(): |
1146 | + if not line: |
1147 | + continue |
1148 | + if not line.startswith(" "): |
1149 | + cur_iface = line.split()[0].rstrip(":") |
1150 | + cur_data = {'inet6': [], 'interface': cur_iface} |
1151 | + for t in boolmap.values(): |
1152 | + cur_data[t] = False |
1153 | + ifaces[cur_iface] = cur_data |
1154 | + |
1155 | + toks = line.split() |
1156 | + |
1157 | + if toks[0] == "inet6": |
1158 | + cidr = toks[2] |
1159 | + address, prefixlen = cidr.split("/") |
1160 | + scope = toks[3].split(":")[1] |
1161 | + cur_ipv6 = {'address': address, 'scope': scope, |
1162 | + 'prefixlen': prefixlen} |
1163 | + cur_data['inet6'].append(cur_ipv6) |
1164 | + continue |
1165 | + |
1166 | + for i in range(0, len(toks)): |
1167 | + cur_tok = toks[i] |
1168 | + try: |
1169 | + next_tok = toks[i+1] |
1170 | + except IndexError: |
1171 | + next_tok = None |
1172 | + |
1173 | + if cur_tok == "HWaddr": |
1174 | + cur_data['mac_address'] = next_tok |
1175 | + elif ":" in cur_tok: |
1176 | + key, _colon, val = cur_tok.partition(":") |
1177 | + if key in combined_fields: |
1178 | + cur_data[combined_fields[key]] = val |
1179 | + elif cur_tok in boolmap: |
1180 | + cur_data[boolmap[cur_tok]] = True |
1181 | + |
1182 | + if 'mtu' in cur_data: |
1183 | + cur_data['mtu'] = int(cur_data['mtu']) |
1184 | + |
1185 | + return ifaces |
1186 | + |
1187 | + |
1188 | +def _parse_ifconfig_yakkety(ifconfig_out): |
1189 | + """Parse ifconfig output from yakkety or later(?) and return a dictionary. |
1190 | + |
1191 | + given ifconfig output like below, return: |
1192 | + {'ens2': {'address': '10.5.0.78', |
1193 | + 'broadcast': '10.5.255.255', |
1194 | + 'broadcast_flag': True, |
1195 | + 'inet6': [{'address': 'fe80::f816:3eff:fe05:9673', |
1196 | + 'prefixlen': '64', 'scopeid': '0x20<link>'}, |
1197 | + {'address': 'fe80::f816:3eff:fe05:9673', |
1198 | + 'prefixlen': '64', 'scopeid': '0x20<link>'}], |
1199 | + 'interface': 'ens2', 'link_encap': 'Ethernet', |
1200 | + 'mac_address': 'fa:16:3e:05:96:73', 'mtu': 1500, |
1201 | + 'multicast': True, 'netmask': '255.255.0.0', |
1202 | + 'running': True, 'up': True}} |
1203 | + |
1204 | + ens2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 |
1205 | + inet 10.5.0.78 netmask 255.255.0.0 broadcast 10.5.255.255 |
1206 | + inet6 fe80::f816:3eff:fe05:9673 prefixlen 64 scopeid 0x20<link> |
1207 | + inet6 fe80::f816:3eff:fe05:9673 prefixlen 64 scopeid 0x20<link> |
1208 | + ether fa:16:3e:05:96:73 txqueuelen 1000 (Ethernet) |
1209 | + RX packets 33196 bytes 48916947 (48.9 MB) |
1210 | + RX errors 0 dropped 0 overruns 0 frame 0 |
1211 | + TX packets 5458 bytes 411486 (411.4 KB) |
1212 | + TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 |
1213 | + """ |
1214 | + fmap = {'mtu': 'mtu', 'inet': 'address', |
1215 | + 'netmask': 'netmask', 'broadcast': 'broadcast', |
1216 | + 'ether': 'mac_address'} |
1217 | + boolmap = {'RUNNING': 'running', 'UP': 'up', 'MULTICAST': 'multicast', |
1218 | + 'BROADCAST': 'broadcast_flag'} |
1219 | + |
1220 | + ifaces = {} |
1221 | + for line in ifconfig_out.splitlines(): |
1222 | + if not line: |
1223 | + continue |
1224 | + if not line.startswith(" "): |
1225 | + cur_iface = line.split()[0].rstrip(":") |
1226 | + cur_data = {'inet6': [], 'interface': cur_iface} |
1227 | + for t in boolmap.values(): |
1228 | + cur_data[t] = False |
1229 | + ifaces[cur_iface] = cur_data |
1230 | + |
1231 | + toks = line.split() |
1232 | + if toks[0] == "inet6": |
1233 | + cur_ipv6 = {'address': toks[1]} |
1234 | + cur_data['inet6'].append(cur_ipv6) |
1235 | + |
1236 | + for i in range(0, len(toks)): |
1237 | + cur_tok = toks[i] |
1238 | + try: |
1239 | + next_tok = toks[i+1] |
1240 | + except IndexError: |
1241 | + next_tok = None |
1242 | + if cur_tok in fmap: |
1243 | + cur_data[fmap[cur_tok]] = next_tok |
1244 | + elif cur_tok in ('prefixlen', 'scopeid'): |
1245 | + cur_ipv6[cur_tok] = next_tok |
1246 | + cur_data['inet6'].append |
1247 | + elif cur_tok.startswith("flags="): |
1248 | + # flags=4163<UP,BROADCAST,RUNNING,MULTICAST> |
1249 | + flags = cur_tok[cur_tok.find("<") + 1: |
1250 | + cur_tok.rfind(">")].split(",") |
1251 | + for flag in flags: |
1252 | + if flag in boolmap: |
1253 | + cur_data[boolmap[flag]] = True |
1254 | + elif cur_tok == "(Ethernet)": |
1255 | + cur_data['link_encap'] = 'Ethernet' |
1256 | + |
1257 | + if 'mtu' in cur_data: |
1258 | + cur_data['mtu'] = int(cur_data['mtu']) |
1259 | + |
1260 | + return ifaces |
1261 | + |
1262 | + |
1263 | +def ifconfig_to_dict(ifconfig_a): |
1264 | + # if the first token of the first line ends in a ':' then assume yakkety |
1265 | + # parse ifconfig output and return a dictionary. |
1266 | + # |
1267 | + # return a dictionary of network information like: |
1268 | + # {'ens2': {'address': '10.5.0.78', 'broadcast': '10.5.255.255', |
1269 | + # 'broadcast_flag': True, |
1270 | + # 'inet6': [{'address': 'fe80::f816:3eff:fe05:9673', |
1271 | + # 'prefixlen': '64', 'scopeid': '0x20<link>'}, |
1272 | + # {'address': 'fe80::f816:3eff:fe05:9673', |
1273 | + # 'prefixlen': '64', 'scopeid': '0x20<link>'}], |
1274 | + # 'interface': 'ens2', 'link_encap': 'Ethernet', |
1275 | + # 'mac_address': 'fa:16:3e:05:96:73', 'mtu': 1500, |
1276 | + # 'multicast': True, 'netmask': '255.255.0.0', |
1277 | + # 'running': True, 'up': True}} |
1278 | + line = ifconfig_a.lstrip().splitlines()[0] |
1279 | + if line.split()[0].endswith(":"): |
1280 | + return _parse_ifconfig_yakkety(ifconfig_a) |
1281 | + else: |
1282 | + return _parse_ifconfig_xenial(ifconfig_a) |
1283 | |
1284 | === modified file 'tests/vmtests/image_sync.py' |
1285 | --- tests/vmtests/image_sync.py 2016-05-10 16:13:29 +0000 |
1286 | +++ tests/vmtests/image_sync.py 2016-07-12 16:34:37 +0000 |
1287 | @@ -29,6 +29,8 @@ |
1288 | VMTEST_CONTENT_ID = 'com.ubuntu.maas:daily:v2:download' |
1289 | VMTEST_JSON_PATH = "streams/v1/vmtest.json" |
1290 | |
1291 | +DEFAULT_OUTPUT_FORMAT = ( |
1292 | + "%(release)-7s %(arch)s/%(subarch)s %(version_name)-10s %(item_name)s") |
1293 | |
1294 | DEFAULT_ARCHES = { |
1295 | 'i386': ['i386'], |
1296 | @@ -397,7 +399,19 @@ |
1297 | results = query(args.mirror_url, args.max_items, args.filters, |
1298 | verbosity=vlevel) |
1299 | try: |
1300 | - print(util.json_dumps(results).decode()) |
1301 | + if args.output_format == FORMAT_JSON: |
1302 | + print(util.json_dumps(results).decode()) |
1303 | + else: |
1304 | + output = [] |
1305 | + for item in results: |
1306 | + try: |
1307 | + output.append(args.output_format % item) |
1308 | + except KeyError as e: |
1309 | + sys.stderr.write("output format failed (%s) for: %s\n" % |
1310 | + (e, item)) |
1311 | + sys.exit(1) |
1312 | + for line in sorted(output): |
1313 | + print(line) |
1314 | except IOError as e: |
1315 | if e.errno == errno.EPIPE: |
1316 | sys.exit(0x80 | signal.SIGPIPE) |
1317 | @@ -440,7 +454,7 @@ |
1318 | |
1319 | fmt_group = query_p.add_mutually_exclusive_group() |
1320 | fmt_group.add_argument('--output-format', '-o', action='store', |
1321 | - dest='output_format', default=None, |
1322 | + dest='output_format', default=DEFAULT_OUTPUT_FORMAT, |
1323 | help="specify output format per python str.format") |
1324 | fmt_group.add_argument('--json', action='store_const', |
1325 | const=FORMAT_JSON, dest='output_format', |
1326 | |
1327 | === modified file 'tests/vmtests/releases.py' |
1328 | --- tests/vmtests/releases.py 2016-05-10 16:13:29 +0000 |
1329 | +++ tests/vmtests/releases.py 2016-07-12 16:34:37 +0000 |
1330 | @@ -46,6 +46,10 @@ |
1331 | release = "xenial" |
1332 | |
1333 | |
1334 | +class _YakketyBase(_ReleaseBase): |
1335 | + release = "yakkety" |
1336 | + |
1337 | + |
1338 | class _Releases(object): |
1339 | precise = _PreciseBase |
1340 | precise_hwe_t = _PreciseHWET |
1341 | @@ -56,6 +60,7 @@ |
1342 | vivid = _VividBase |
1343 | wily = _WilyBase |
1344 | xenial = _XenialBase |
1345 | + yakkety = _YakketyBase |
1346 | |
1347 | base_vm_classes = _Releases |
1348 | |
1349 | |
1350 | === modified file 'tests/vmtests/test_basic.py' |
1351 | --- tests/vmtests/test_basic.py 2016-06-03 13:50:09 +0000 |
1352 | +++ tests/vmtests/test_basic.py 2016-07-12 16:34:37 +0000 |
1353 | @@ -223,13 +223,130 @@ |
1354 | __test__ = False |
1355 | |
1356 | |
1357 | -class VividTestBasic(relbase.vivid, TestBasicAbs): |
1358 | - __test__ = True |
1359 | - |
1360 | - |
1361 | class WilyTestBasic(relbase.wily, TestBasicAbs): |
1362 | __test__ = True |
1363 | |
1364 | |
1365 | class XenialTestBasic(relbase.xenial, TestBasicAbs): |
1366 | __test__ = True |
1367 | + |
1368 | + |
1369 | +class YakketyTestBasic(relbase.yakkety, TestBasicAbs): |
1370 | + __test__ = True |
1371 | + |
1372 | + |
1373 | +class TestBasicScsiAbs(TestBasicAbs): |
1374 | + conf_file = "examples/tests/basic_scsi.yaml" |
1375 | + disk_driver = 'scsi-hd' |
1376 | + extra_disks = ['128G', '128G', '4G'] |
1377 | + nvme_disks = ['4G'] |
1378 | + collect_scripts = [textwrap.dedent(""" |
1379 | + cd OUTPUT_COLLECT_D |
1380 | + blkid -o export /dev/sda > blkid_output_sda |
1381 | + blkid -o export /dev/sda1 > blkid_output_sda1 |
1382 | + blkid -o export /dev/sda2 > blkid_output_sda2 |
1383 | + btrfs-show-super /dev/sdc > btrfs_show_super_sdc |
1384 | + cat /proc/partitions > proc_partitions |
1385 | + ls -al /dev/disk/by-uuid/ > ls_uuid |
1386 | + ls -al /dev/disk/by-id/ > ls_disk_id |
1387 | + cat /etc/fstab > fstab |
1388 | + mkdir -p /dev/disk/by-dname |
1389 | + ls /dev/disk/by-dname/ > ls_dname |
1390 | + find /etc/network/interfaces.d > find_interfacesd |
1391 | + |
1392 | + v="" |
1393 | + out=$(apt-config shell v Acquire::HTTP::Proxy) |
1394 | + eval "$out" |
1395 | + echo "$v" > apt-proxy |
1396 | + """)] |
1397 | + |
1398 | + def test_output_files_exist(self): |
1399 | + self.output_files_exist( |
1400 | + ["blkid_output_sda", "blkid_output_sda1", "blkid_output_sda2", |
1401 | + "btrfs_show_super_sdc", "fstab", "ls_dname", "ls_uuid", |
1402 | + "ls_disk_id", "proc_partitions"]) |
1403 | + |
1404 | + def test_ptable(self): |
1405 | + blkid_info = self.get_blkid_data("blkid_output_sda") |
1406 | + self.assertEquals(blkid_info["PTTYPE"], "dos") |
1407 | + |
1408 | + def test_partition_numbers(self): |
1409 | + # vde should have partitions 1 and 10 |
1410 | + disk = "sdd" |
1411 | + proc_partitions_path = os.path.join(self.td.collect, |
1412 | + 'proc_partitions') |
1413 | + self.assertTrue(os.path.exists(proc_partitions_path)) |
1414 | + found = [] |
1415 | + with open(proc_partitions_path, 'r') as fp: |
1416 | + for line in fp.readlines(): |
1417 | + if disk in line: |
1418 | + found.append(line.split()[3]) |
1419 | + # /proc/partitions should have 3 lines with 'vde' in them. |
1420 | + expected = [disk + s for s in ["", "1", "10"]] |
1421 | + self.assertEqual(found, expected) |
1422 | + |
1423 | + def test_partitions(self): |
1424 | + with open(os.path.join(self.td.collect, "fstab")) as fp: |
1425 | + fstab_lines = fp.readlines() |
1426 | + print("\n".join(fstab_lines)) |
1427 | + # Test that vda1 is on / |
1428 | + blkid_info = self.get_blkid_data("blkid_output_sda1") |
1429 | + fstab_entry = None |
1430 | + for line in fstab_lines: |
1431 | + if blkid_info['UUID'] in line: |
1432 | + fstab_entry = line |
1433 | + break |
1434 | + self.assertIsNotNone(fstab_entry) |
1435 | + self.assertEqual(fstab_entry.split(' ')[1], "/") |
1436 | + |
1437 | + # Test that vda2 is on /home |
1438 | + blkid_info = self.get_blkid_data("blkid_output_sda2") |
1439 | + fstab_entry = None |
1440 | + for line in fstab_lines: |
1441 | + if blkid_info['UUID'] in line: |
1442 | + fstab_entry = line |
1443 | + break |
1444 | + self.assertIsNotNone(fstab_entry) |
1445 | + self.assertEqual(fstab_entry.split(' ')[1], "/home") |
1446 | + |
1447 | + # Test whole disk sdc is mounted at /btrfs |
1448 | + fstab_entry = None |
1449 | + for line in fstab_lines: |
1450 | + if "/dev/sdc" in line: |
1451 | + fstab_entry = line |
1452 | + break |
1453 | + self.assertIsNotNone(fstab_entry) |
1454 | + self.assertEqual(fstab_entry.split(' ')[1], "/btrfs") |
1455 | + |
1456 | + def test_whole_disk_format(self): |
1457 | + # confirm the whole disk format is the expected device |
1458 | + with open(os.path.join(self.td.collect, |
1459 | + "btrfs_show_super_sdc"), "r") as fp: |
1460 | + btrfs_show_super = fp.read() |
1461 | + |
1462 | + with open(os.path.join(self.td.collect, "ls_uuid"), "r") as fp: |
1463 | + ls_uuid = fp.read() |
1464 | + |
1465 | + # extract uuid from btrfs superblock |
1466 | + btrfs_fsid = [line for line in btrfs_show_super.split('\n') |
1467 | + if line.startswith('fsid\t\t')] |
1468 | + self.assertEqual(len(btrfs_fsid), 1) |
1469 | + btrfs_uuid = btrfs_fsid[0].split()[1] |
1470 | + self.assertTrue(btrfs_uuid is not None) |
1471 | + |
1472 | + # extract uuid from /dev/disk/by-uuid on /dev/sdc |
1473 | + # parsing ls -al output on /dev/disk/by-uuid: |
1474 | + # lrwxrwxrwx 1 root root 9 Dec 4 20:02 |
1475 | + # d591e9e9-825a-4f0a-b280-3bfaf470b83c -> ../../vdg |
1476 | + uuid = [line.split()[8] for line in ls_uuid.split('\n') |
1477 | + if 'sdc' in line] |
1478 | + self.assertEqual(len(uuid), 1) |
1479 | + uuid = uuid.pop() |
1480 | + self.assertTrue(uuid is not None) |
1481 | + |
1482 | + # compare them |
1483 | + self.assertEqual(uuid, btrfs_uuid) |
1484 | + |
1485 | + |
1486 | +class XenialTestScsiBasic(relbase.xenial, TestBasicScsiAbs): |
1487 | + __test__ = True |
1488 | |
1489 | === modified file 'tests/vmtests/test_bcache_basic.py' |
1490 | --- tests/vmtests/test_bcache_basic.py 2016-06-03 13:50:09 +0000 |
1491 | +++ tests/vmtests/test_bcache_basic.py 2016-07-12 16:34:37 +0000 |
1492 | @@ -50,3 +50,7 @@ |
1493 | |
1494 | class XenialBcacheBasic(relbase.xenial, TestBcacheBasic): |
1495 | __test__ = True |
1496 | + |
1497 | + |
1498 | +class YakketyBcacheBasic(relbase.yakkety, TestBcacheBasic): |
1499 | + __test__ = True |
1500 | |
1501 | === modified file 'tests/vmtests/test_bonding.py' |
1502 | --- tests/vmtests/test_bonding.py 2016-06-03 13:50:09 +0000 |
1503 | +++ tests/vmtests/test_bonding.py 2016-07-12 16:34:37 +0000 |
1504 | @@ -1,4 +1,4 @@ |
1505 | -from . import VMBaseClass, logger |
1506 | +from . import VMBaseClass, logger, helpers |
1507 | from .releases import base_vm_classes as relbase |
1508 | |
1509 | import ipaddress |
1510 | @@ -8,44 +8,6 @@ |
1511 | import yaml |
1512 | |
1513 | |
1514 | -def iface_extract(input): |
1515 | - mo = re.search(r'^(?P<interface>\w+|\w+:\d+)\s+' + |
1516 | - r'Link encap:(?P<link_encap>\S+)\s+' + |
1517 | - r'(HWaddr\s+(?P<mac_address>\S+))?' + |
1518 | - r'(\s+inet addr:(?P<address>\S+))?' + |
1519 | - r'(\s+Bcast:(?P<broadcast>\S+)\s+)?' + |
1520 | - r'(Mask:(?P<netmask>\S+)\s+)?', |
1521 | - input, re.MULTILINE) |
1522 | - |
1523 | - mtu = re.search(r'(\s+MTU:(?P<mtu>\d+)\s+)\s+', input, re.MULTILINE) |
1524 | - mtu_info = mtu.groupdict('') |
1525 | - mtu_info['mtu'] = int(mtu_info['mtu']) |
1526 | - |
1527 | - if mo: |
1528 | - info = mo.groupdict('') |
1529 | - info['running'] = False |
1530 | - info['up'] = False |
1531 | - info['multicast'] = False |
1532 | - if 'RUNNING' in input: |
1533 | - info['running'] = True |
1534 | - if 'UP' in input: |
1535 | - info['up'] = True |
1536 | - if 'MULTICAST' in input: |
1537 | - info['multicast'] = True |
1538 | - info.update(mtu_info) |
1539 | - return info |
1540 | - return {} |
1541 | - |
1542 | - |
1543 | -def ifconfig_to_dict(ifconfig): |
1544 | - interfaces = {} |
1545 | - for iface in [iface_extract(iface) for iface in ifconfig.split('\n\n') |
1546 | - if iface.strip()]: |
1547 | - interfaces[iface['interface']] = iface |
1548 | - |
1549 | - return interfaces |
1550 | - |
1551 | - |
1552 | class TestNetworkAbs(VMBaseClass): |
1553 | interactive = False |
1554 | conf_file = "examples/tests/bonding_network.yaml" |
1555 | @@ -96,7 +58,7 @@ |
1556 | ifconfig_a = fp.read() |
1557 | logger.debug('ifconfig -a:\n{}'.format(ifconfig_a)) |
1558 | |
1559 | - ifconfig_dict = ifconfig_to_dict(ifconfig_a) |
1560 | + ifconfig_dict = helpers.ifconfig_to_dict(ifconfig_a) |
1561 | logger.debug('parsed ifcfg dict:\n{}'.format( |
1562 | yaml.dump(ifconfig_dict, default_flow_style=False, indent=4))) |
1563 | |
1564 | @@ -230,13 +192,13 @@ |
1565 | __test__ = True |
1566 | |
1567 | |
1568 | -class VividTestBonding(relbase.vivid, TestNetworkAbs): |
1569 | - __test__ = True |
1570 | - |
1571 | - |
1572 | class WilyTestBonding(relbase.wily, TestNetworkAbs): |
1573 | __test__ = True |
1574 | |
1575 | |
1576 | class XenialTestBonding(relbase.xenial, TestNetworkAbs): |
1577 | __test__ = True |
1578 | + |
1579 | + |
1580 | +class YakketyTestBonding(relbase.yakkety, TestNetworkAbs): |
1581 | + __test__ = True |
1582 | |
1583 | === modified file 'tests/vmtests/test_lvm.py' |
1584 | --- tests/vmtests/test_lvm.py 2016-06-03 13:50:09 +0000 |
1585 | +++ tests/vmtests/test_lvm.py 2016-07-12 16:34:37 +0000 |
1586 | @@ -63,13 +63,13 @@ |
1587 | print("test_dname does not work for Trusty") |
1588 | |
1589 | |
1590 | -class VividTestLvm(relbase.vivid, TestLvmAbs): |
1591 | - __test__ = True |
1592 | - |
1593 | - |
1594 | class WilyTestLvm(relbase.wily, TestLvmAbs): |
1595 | __test__ = True |
1596 | |
1597 | |
1598 | class XenialTestLvm(relbase.xenial, TestLvmAbs): |
1599 | __test__ = True |
1600 | + |
1601 | + |
1602 | +class YakketyTestLvm(relbase.yakkety, TestLvmAbs): |
1603 | + __test__ = True |
1604 | |
1605 | === modified file 'tests/vmtests/test_mdadm_bcache.py' |
1606 | --- tests/vmtests/test_mdadm_bcache.py 2016-06-03 13:50:09 +0000 |
1607 | +++ tests/vmtests/test_mdadm_bcache.py 2016-07-12 16:34:37 +0000 |
1608 | @@ -130,10 +130,6 @@ |
1609 | __test__ = True |
1610 | |
1611 | |
1612 | -class VividTestMdadmBcache(relbase.vivid, TestMdadmBcacheAbs): |
1613 | - __test__ = True |
1614 | - |
1615 | - |
1616 | class WilyTestMdadmBcache(relbase.wily, TestMdadmBcacheAbs): |
1617 | __test__ = True |
1618 | |
1619 | @@ -142,6 +138,10 @@ |
1620 | __test__ = True |
1621 | |
1622 | |
1623 | +class YakketyTestMdadmBcache(relbase.yakkety, TestMdadmBcacheAbs): |
1624 | + __test__ = True |
1625 | + |
1626 | + |
1627 | class TestMirrorbootAbs(TestMdadmAbs): |
1628 | # alternative config for more complex setup |
1629 | conf_file = "examples/tests/mirrorboot.yaml" |
1630 | @@ -170,10 +170,6 @@ |
1631 | __test__ = True |
1632 | |
1633 | |
1634 | -class VividTestMirrorboot(relbase.vivid, TestMirrorbootAbs): |
1635 | - __test__ = True |
1636 | - |
1637 | - |
1638 | class WilyTestMirrorboot(relbase.wily, TestMirrorbootAbs): |
1639 | __test__ = True |
1640 | |
1641 | @@ -182,6 +178,10 @@ |
1642 | __test__ = True |
1643 | |
1644 | |
1645 | +class YakketyTestMirrorboot(relbase.yakkety, TestMirrorbootAbs): |
1646 | + __test__ = True |
1647 | + |
1648 | + |
1649 | class TestRaid5bootAbs(TestMdadmAbs): |
1650 | # alternative config for more complex setup |
1651 | conf_file = "examples/tests/raid5boot.yaml" |
1652 | @@ -211,10 +211,6 @@ |
1653 | __test__ = True |
1654 | |
1655 | |
1656 | -class VividTestRaid5boot(relbase.vivid, TestRaid5bootAbs): |
1657 | - __test__ = True |
1658 | - |
1659 | - |
1660 | class WilyTestRaid5boot(relbase.wily, TestRaid5bootAbs): |
1661 | __test__ = True |
1662 | |
1663 | @@ -223,6 +219,10 @@ |
1664 | __test__ = True |
1665 | |
1666 | |
1667 | +class YakketyTestRaid5boot(relbase.yakkety, TestRaid5bootAbs): |
1668 | + __test__ = True |
1669 | + |
1670 | + |
1671 | class TestRaid6bootAbs(TestMdadmAbs): |
1672 | # alternative config for more complex setup |
1673 | conf_file = "examples/tests/raid6boot.yaml" |
1674 | @@ -264,10 +264,6 @@ |
1675 | __test__ = True |
1676 | |
1677 | |
1678 | -class VividTestRaid6boot(relbase.vivid, TestRaid6bootAbs): |
1679 | - __test__ = True |
1680 | - |
1681 | - |
1682 | class WilyTestRaid6boot(relbase.wily, TestRaid6bootAbs): |
1683 | __test__ = True |
1684 | |
1685 | @@ -276,6 +272,10 @@ |
1686 | __test__ = True |
1687 | |
1688 | |
1689 | +class YakketyTestRaid6boot(relbase.yakkety, TestRaid6bootAbs): |
1690 | + __test__ = True |
1691 | + |
1692 | + |
1693 | class TestRaid10bootAbs(TestMdadmAbs): |
1694 | # alternative config for more complex setup |
1695 | conf_file = "examples/tests/raid10boot.yaml" |
1696 | @@ -305,10 +305,6 @@ |
1697 | __test__ = True |
1698 | |
1699 | |
1700 | -class VividTestRaid10boot(relbase.vivid, TestRaid10bootAbs): |
1701 | - __test__ = True |
1702 | - |
1703 | - |
1704 | class WilyTestRaid10boot(relbase.wily, TestRaid10bootAbs): |
1705 | __test__ = True |
1706 | |
1707 | @@ -317,6 +313,10 @@ |
1708 | __test__ = True |
1709 | |
1710 | |
1711 | +class YakketyTestRaid10boot(relbase.yakkety, TestRaid10bootAbs): |
1712 | + __test__ = True |
1713 | + |
1714 | + |
1715 | class TestAllindataAbs(TestMdadmAbs): |
1716 | # more complex, needs more time |
1717 | # alternative config for more complex setup |
1718 | @@ -403,13 +403,13 @@ |
1719 | __test__ = False # lukes=no does not disable mounting of device |
1720 | |
1721 | |
1722 | -class VividTestAllindata(relbase.vivid, TestAllindataAbs): |
1723 | - __test__ = True |
1724 | - |
1725 | - |
1726 | class WilyTestAllindata(relbase.wily, TestAllindataAbs): |
1727 | __test__ = True |
1728 | |
1729 | |
1730 | class XenialTestAllindata(relbase.xenial, TestAllindataAbs): |
1731 | __test__ = True |
1732 | + |
1733 | + |
1734 | +class YakketyTestAllindata(relbase.yakkety, TestAllindataAbs): |
1735 | + __test__ = True |
1736 | |
1737 | === added file 'tests/vmtests/test_multipath.py' |
1738 | --- tests/vmtests/test_multipath.py 1970-01-01 00:00:00 +0000 |
1739 | +++ tests/vmtests/test_multipath.py 2016-07-12 16:34:37 +0000 |
1740 | @@ -0,0 +1,63 @@ |
1741 | +from . import VMBaseClass |
1742 | +from .releases import base_vm_classes as relbase |
1743 | + |
1744 | +import os |
1745 | +import textwrap |
1746 | + |
1747 | + |
1748 | +class TestMultipathBasicAbs(VMBaseClass): |
1749 | + conf_file = "examples/tests/multipath.yaml" |
1750 | + multipath = True |
1751 | + disk_driver = 'scsi-hd' |
1752 | + extra_disks = [] |
1753 | + nvme_disks = [] |
1754 | + collect_scripts = [textwrap.dedent(""" |
1755 | + cd OUTPUT_COLLECT_D |
1756 | + blkid -o export /dev/sda > blkid_output_sda |
1757 | + blkid -o export /dev/sda1 > blkid_output_sda1 |
1758 | + blkid -o export /dev/sda2 > blkid_output_sda2 |
1759 | + blkid -o export /dev/sdb > blkid_output_sdb |
1760 | + blkid -o export /dev/sdb1 > blkid_output_sdb1 |
1761 | + blkid -o export /dev/sdb2 > blkid_output_sdb2 |
1762 | + dmsetup ls > dmsetup_ls |
1763 | + dmsetup info > dmsetup_info |
1764 | + cat /proc/partitions > proc_partitions |
1765 | + multipath -ll > multipath_ll |
1766 | + multipath -v3 -ll > multipath_v3_ll |
1767 | + multipath -r > multipath_r |
1768 | + cp -a /etc/multipath* . |
1769 | + ls -al /dev/disk/by-uuid/ > ls_uuid |
1770 | + ls -al /dev/disk/by-id/ > ls_disk_id |
1771 | + readlink -f /sys/class/block/sda/holders/dm-0 > holders_sda |
1772 | + readlink /sys/class/block/sdb/holders/dm-0 > holders_sdb |
1773 | + cat /etc/fstab > fstab |
1774 | + mkdir -p /dev/disk/by-dname |
1775 | + ls /dev/disk/by-dname/ > ls_dname |
1776 | + find /etc/network/interfaces.d > find_interfacesd |
1777 | + """)] |
1778 | + |
1779 | + def test_multipath_disks_match(self): |
1780 | + sda = os.path.join(self.td.collect, 'holders_sda') |
1781 | + sdb = os.path.join(self.td.collect, 'holders_sdb') |
1782 | + self.assertTrue(os.path.exists(sda)) |
1783 | + self.assertTrue(os.path.exists(sdb)) |
1784 | + with open(sda, 'r') as fp: |
1785 | + sda_data = fp.read() |
1786 | + print('sda holders:\n%s' % sda_data) |
1787 | + with open(sda, 'r') as fp: |
1788 | + sdb_data = fp.read() |
1789 | + print('sdb holders:\n%s' % sda_data) |
1790 | + |
1791 | + self.assertEqual(sda_data, sdb_data) |
1792 | + |
1793 | + |
1794 | +class TrustyTestMultipathBasic(relbase.trusty, TestMultipathBasicAbs): |
1795 | + __test__ = True |
1796 | + |
1797 | + |
1798 | +class XenialTestMultipathBasic(relbase.xenial, TestMultipathBasicAbs): |
1799 | + __test__ = True |
1800 | + |
1801 | + |
1802 | +class YakketyTestMultipathBasic(relbase.yakkety, TestMultipathBasicAbs): |
1803 | + __test__ = True |
1804 | |
1805 | === modified file 'tests/vmtests/test_network.py' |
1806 | --- tests/vmtests/test_network.py 2016-06-03 13:50:09 +0000 |
1807 | +++ tests/vmtests/test_network.py 2016-07-12 16:34:37 +0000 |
1808 | @@ -1,4 +1,4 @@ |
1809 | -from . import VMBaseClass, logger |
1810 | +from . import VMBaseClass, logger, helpers |
1811 | from .releases import base_vm_classes as relbase |
1812 | |
1813 | import ipaddress |
1814 | @@ -9,44 +9,6 @@ |
1815 | import yaml |
1816 | |
1817 | |
1818 | -def iface_extract(input): |
1819 | - mo = re.search(r'^(?P<interface>\w+|\w+:\d+|\w+\.\d+)\s+' + |
1820 | - r'Link encap:(?P<link_encap>\S+)\s+' + |
1821 | - r'(HWaddr\s+(?P<mac_address>\S+))?' + |
1822 | - r'(\s+inet addr:(?P<address>\S+))?' + |
1823 | - r'(\s+Bcast:(?P<broadcast>\S+)\s+)?' + |
1824 | - r'(Mask:(?P<netmask>\S+)\s+)?', |
1825 | - input, re.MULTILINE) |
1826 | - |
1827 | - mtu = re.search(r'(\s+MTU:(?P<mtu>\d+)\s+)\s+', input, re.MULTILINE) |
1828 | - mtu_info = mtu.groupdict('') |
1829 | - mtu_info['mtu'] = int(mtu_info['mtu']) |
1830 | - |
1831 | - if mo: |
1832 | - info = mo.groupdict('') |
1833 | - info['running'] = False |
1834 | - info['up'] = False |
1835 | - info['multicast'] = False |
1836 | - if 'RUNNING' in input: |
1837 | - info['running'] = True |
1838 | - if 'UP' in input: |
1839 | - info['up'] = True |
1840 | - if 'MULTICAST' in input: |
1841 | - info['multicast'] = True |
1842 | - info.update(mtu_info) |
1843 | - return info |
1844 | - return {} |
1845 | - |
1846 | - |
1847 | -def ifconfig_to_dict(ifconfig): |
1848 | - interfaces = {} |
1849 | - for iface in [iface_extract(iface) for iface in ifconfig.split('\n\n') |
1850 | - if iface.strip()]: |
1851 | - interfaces[iface['interface']] = iface |
1852 | - |
1853 | - return interfaces |
1854 | - |
1855 | - |
1856 | class TestNetworkAbs(VMBaseClass): |
1857 | interactive = False |
1858 | conf_file = "examples/tests/basic_network.yaml" |
1859 | @@ -132,7 +94,7 @@ |
1860 | ifconfig_a = fp.read() |
1861 | logger.debug('ifconfig -a:\n{}'.format(ifconfig_a)) |
1862 | |
1863 | - ifconfig_dict = ifconfig_to_dict(ifconfig_a) |
1864 | + ifconfig_dict = helpers.ifconfig_to_dict(ifconfig_a) |
1865 | logger.debug('parsed ifcfg dict:\n{}'.format( |
1866 | yaml.dump(ifconfig_dict, default_flow_style=False, indent=4))) |
1867 | |
1868 | @@ -340,7 +302,7 @@ |
1869 | ifconfig_a = fp.read() |
1870 | logger.debug('ifconfig -a:\n{}'.format(ifconfig_a)) |
1871 | |
1872 | - ifconfig_dict = ifconfig_to_dict(ifconfig_a) |
1873 | + ifconfig_dict = helpers.ifconfig_to_dict(ifconfig_a) |
1874 | logger.debug('parsed ifconfig dict:\n{}'.format( |
1875 | yaml.dump(ifconfig_dict, default_flow_style=False, indent=4))) |
1876 | print('parsed ifconfig dict:\n{}'.format( |
1877 | @@ -411,14 +373,6 @@ |
1878 | __test__ = False |
1879 | |
1880 | |
1881 | -class VividTestNetwork(relbase.vivid, TestNetworkAbs): |
1882 | - __test__ = True |
1883 | - |
1884 | - |
1885 | -class VividTestNetworkStatic(relbase.vivid, TestNetworkStaticAbs): |
1886 | - __test__ = True |
1887 | - |
1888 | - |
1889 | class WilyTestNetwork(relbase.wily, TestNetworkAbs): |
1890 | __test__ = True |
1891 | |
1892 | @@ -435,6 +389,14 @@ |
1893 | __test__ = True |
1894 | |
1895 | |
1896 | +class YakketyTestNetwork(relbase.yakkety, TestNetworkAbs): |
1897 | + __test__ = True |
1898 | + |
1899 | + |
1900 | +class YakketyTestNetworkStatic(relbase.yakkety, TestNetworkStaticAbs): |
1901 | + __test__ = True |
1902 | + |
1903 | + |
1904 | class PreciseTestNetworkVlan(relbase.precise, TestNetworkVlanAbs): |
1905 | __test__ = True |
1906 | |
1907 | @@ -455,10 +417,6 @@ |
1908 | __test__ = True |
1909 | |
1910 | |
1911 | -class VividTestNetworkVlan(relbase.vivid, TestNetworkVlanAbs): |
1912 | - __test__ = True |
1913 | - |
1914 | - |
1915 | class WilyTestNetworkVlan(relbase.wily, TestNetworkVlanAbs): |
1916 | __test__ = True |
1917 | |
1918 | @@ -467,6 +425,10 @@ |
1919 | __test__ = True |
1920 | |
1921 | |
1922 | +class YakketyTestNetworkVlan(relbase.yakkety, TestNetworkVlanAbs): |
1923 | + __test__ = True |
1924 | + |
1925 | + |
1926 | class PreciseTestNetworkENISource(relbase.precise, TestNetworkENISource): |
1927 | __test__ = False |
1928 | # not working, still debugging though; possible older ifupdown doesn't |
1929 | @@ -477,13 +439,13 @@ |
1930 | __test__ = True |
1931 | |
1932 | |
1933 | -class VividTestNetworkENISource(relbase.vivid, TestNetworkENISource): |
1934 | - __test__ = True |
1935 | - |
1936 | - |
1937 | class WilyTestNetworkENISource(relbase.wily, TestNetworkENISource): |
1938 | __test__ = True |
1939 | |
1940 | |
1941 | class XenialTestNetworkENISource(relbase.xenial, TestNetworkENISource): |
1942 | __test__ = True |
1943 | + |
1944 | + |
1945 | +class YakketyTestNetworkENISource(relbase.yakkety, TestNetworkENISource): |
1946 | + __test__ = True |
1947 | |
1948 | === modified file 'tests/vmtests/test_nvme.py' |
1949 | --- tests/vmtests/test_nvme.py 2016-06-03 13:50:09 +0000 |
1950 | +++ tests/vmtests/test_nvme.py 2016-07-12 16:34:37 +0000 |
1951 | @@ -74,13 +74,13 @@ |
1952 | print("test_ptable does not work for Trusty") |
1953 | |
1954 | |
1955 | -class VividTestNvme(relbase.vivid, TestNvmeAbs): |
1956 | - __test__ = True |
1957 | - |
1958 | - |
1959 | class WilyTestNvme(relbase.wily, TestNvmeAbs): |
1960 | __test__ = True |
1961 | |
1962 | |
1963 | class XenialTestNvme(relbase.xenial, TestNvmeAbs): |
1964 | __test__ = True |
1965 | + |
1966 | + |
1967 | +class YakketyTestNvme(relbase.yakkety, TestNvmeAbs): |
1968 | + __test__ = True |
1969 | |
1970 | === modified file 'tests/vmtests/test_raid5_bcache.py' |
1971 | --- tests/vmtests/test_raid5_bcache.py 2016-06-03 13:50:09 +0000 |
1972 | +++ tests/vmtests/test_raid5_bcache.py 2016-07-12 16:34:37 +0000 |
1973 | @@ -93,9 +93,13 @@ |
1974 | __test__ = False |
1975 | |
1976 | |
1977 | -class VividTestRaid5Bcache(relbase.vivid, TestMdadmBcacheAbs): |
1978 | - __test__ = True |
1979 | - |
1980 | - |
1981 | class WilyTestRaid5Bcache(relbase.wily, TestMdadmBcacheAbs): |
1982 | __test__ = True |
1983 | + |
1984 | + |
1985 | +class XenialTestRaid5Bcache(relbase.xenial, TestMdadmBcacheAbs): |
1986 | + __test__ = True |
1987 | + |
1988 | + |
1989 | +class YakketyTestRaid5Bcache(relbase.yakkety, TestMdadmBcacheAbs): |
1990 | + __test__ = True |
1991 | |
1992 | === added file 'tests/vmtests/test_simple.py' |
1993 | --- tests/vmtests/test_simple.py 1970-01-01 00:00:00 +0000 |
1994 | +++ tests/vmtests/test_simple.py 2016-07-12 16:34:37 +0000 |
1995 | @@ -0,0 +1,40 @@ |
1996 | +from . import VMBaseClass |
1997 | +from .releases import base_vm_classes as relbase |
1998 | + |
1999 | +import textwrap |
2000 | + |
2001 | + |
2002 | +class TestSimple(VMBaseClass): |
2003 | + # Test that curtin with no config does the right thing |
2004 | + conf_file = "examples/tests/simple.yaml" |
2005 | + extra_disks = [] |
2006 | + extra_nics = [] |
2007 | + collect_scripts = [textwrap.dedent(""" |
2008 | + cd OUTPUT_COLLECT_D |
2009 | + sfdisk --list > sfdisk_list |
2010 | + for d in /dev/[sv]d[a-z] /dev/xvd?; do |
2011 | + [ -b "$d" ] || continue |
2012 | + echo == $d == |
2013 | + sgdisk --print $d |
2014 | + done > sgdisk_list |
2015 | + blkid > blkid |
2016 | + cat /proc/partitions > proc_partitions |
2017 | + cp /etc/network/interfaces interfaces |
2018 | + if [ -f /var/log/cloud-init-output.log ]; then |
2019 | + cp /var/log/cloud-init-output.log . |
2020 | + fi |
2021 | + cp /var/log/cloud-init.log . |
2022 | + find /etc/network/interfaces.d > find_interfacesd |
2023 | + """)] |
2024 | + |
2025 | + def test_output_files_exist(self): |
2026 | + self.output_files_exist(["sfdisk_list", "blkid", |
2027 | + "proc_partitions", "interfaces"]) |
2028 | + |
2029 | + |
2030 | +class TrustyTestSimple(relbase.trusty, TestSimple): |
2031 | + __test__ = True |
2032 | + |
2033 | + |
2034 | +class XenialTestSimple(relbase.xenial, TestSimple): |
2035 | + __test__ = True |
2036 | |
2037 | === modified file 'tests/vmtests/test_uefi_basic.py' |
2038 | --- tests/vmtests/test_uefi_basic.py 2016-06-03 13:50:09 +0000 |
2039 | +++ tests/vmtests/test_uefi_basic.py 2016-07-12 16:34:37 +0000 |
2040 | @@ -108,14 +108,14 @@ |
2041 | __test__ = True |
2042 | |
2043 | |
2044 | -class VividUefiTestBasic(relbase.vivid, TestBasicAbs): |
2045 | - __test__ = True |
2046 | - |
2047 | - |
2048 | class XenialUefiTestBasic(relbase.xenial, TestBasicAbs): |
2049 | __test__ = True |
2050 | |
2051 | |
2052 | +class YakketyUefiTestBasic(relbase.yakkety, TestBasicAbs): |
2053 | + __test__ = True |
2054 | + |
2055 | + |
2056 | class PreciseUefiTestBasic4k(PreciseUefiTestBasic): |
2057 | disk_block_size = 4096 |
2058 | |
2059 | @@ -124,13 +124,13 @@ |
2060 | disk_block_size = 4096 |
2061 | |
2062 | |
2063 | -class VividUefiTestBasic4k(VividUefiTestBasic): |
2064 | - disk_block_size = 4096 |
2065 | - |
2066 | - |
2067 | class WilyUefiTestBasic4k(WilyUefiTestBasic): |
2068 | disk_block_size = 4096 |
2069 | |
2070 | |
2071 | class XenialUefiTestBasic4k(XenialUefiTestBasic): |
2072 | disk_block_size = 4096 |
2073 | + |
2074 | + |
2075 | +class YakketyUefiTestBasic4k(YakketyUefiTestBasic): |
2076 | + disk_block_size = 4096 |
2077 | |
2078 | === modified file 'tools/jenkins-runner' |
2079 | --- tools/jenkins-runner 2016-02-12 21:54:46 +0000 |
2080 | +++ tools/jenkins-runner 2016-07-12 16:34:37 +0000 |
2081 | @@ -7,6 +7,7 @@ |
2082 | export CURTIN_VMTEST_KEEP_DATA_FAIL=$fkeep |
2083 | export CURTIN_VMTEST_TOPDIR="$topdir" |
2084 | export CURTIN_VMTEST_LOG=${CURTIN_VMTEST_LOG:-"$topdir/debug.log"} |
2085 | +export IMAGE_DIR=${IMAGE_DIR:-/srv/images} |
2086 | |
2087 | fail() { echo "$@" 1>&2; exit 1; } |
2088 | |
2089 | @@ -24,6 +25,15 @@ |
2090 | for v in ${!CURTIN_*}; do |
2091 | echo "$v=${!v}" |
2092 | done |
2093 | + |
2094 | +# avoid LOG info by running python3 tests/vmtests/image_sync.py |
2095 | +# rather than python3 -m tests.vmtests.image_sync (LP: #1594465) |
2096 | +echo "Working with images in $IMAGE_DIR" |
2097 | +fmt=" %(release)-7s %(arch)s/%(subarch)s %(version_name)-10s" |
2098 | +PYTHONPATH="$PWD" python3 tests/vmtests/image_sync.py query \ |
2099 | + --output-format="$fmt" "$IMAGE_DIR" ftype=root-image.gz || |
2100 | + { echo "WARNING: error querying images in $IMAGE_DIR" 1>&2; } |
2101 | + |
2102 | echo "$(date -R): vmtest start: nosetests3 $*" |
2103 | nosetests3 "$@" |
2104 | ret=$? |
2105 | |
2106 | === modified file 'tools/launch' |
2107 | --- tools/launch 2016-05-10 16:13:29 +0000 |
2108 | +++ tools/launch 2016-07-12 16:34:37 +0000 |
2109 | @@ -8,6 +8,7 @@ |
2110 | HTTP_PORT_MIN=${HTTP_PORT_MIN:-12000} |
2111 | HTTP_PORT_MAX=${HTTP_PORT_MAX:-65500} |
2112 | MY_D=$(dirname "$0") |
2113 | +DEFAULT_ROOT_ARG="root=LABEL=cloudimg-rootfs" |
2114 | |
2115 | error() { echo "$@" 1>&2; } |
2116 | |
2117 | @@ -15,19 +16,24 @@ |
2118 | cat <<EOF |
2119 | Usage: ${0##*/} [ options ] boot-image curtin install [args] |
2120 | |
2121 | - boot the image 'boot-image', so that it will run |
2122 | + boot the image 'boot-image', so that it will run |
2123 | curtin install [args] |
2124 | after booting. 'curtin install [args]' can be any command' |
2125 | - |
2126 | + |
2127 | options: |
2128 | --add F[:T] add file 'F' to the curtin archive at T |
2129 | -a | --append append args to kernel cmdline (--kernel) |
2130 | -A | --arch A assume guest kernel architecture A |
2131 | - -d | --disk D add a disk 'D' format (path[:size][:driver][:bsize]) |
2132 | + -d | --disk D add a disk 'D' format |
2133 | + (path[:size][:driver][:bsize][:devopts]) |
2134 | driver can be specified without size using path::driver |
2135 | driver defaults to virtio-blk |
2136 | bsize <logical>[,<physical>][,<min_io_size>] |
2137 | bsize defaults to 512b sector size |
2138 | + opts is a comma delimitted list of property=value |
2139 | + elements. Examine qemu-kvm -device scsi-hd,? for |
2140 | + details. |
2141 | + --vnc D use -vnc D (mutually exclusive with --silent) |
2142 | --uefi N enable uefi boot method, store nvram at N |
2143 | -h | --help show this message |
2144 | -i | --initrd F use initramfs F |
2145 | @@ -40,6 +46,8 @@ |
2146 | directly through to qemu-system. |
2147 | Note, qemu adds 5900 to port numbers. (:0 = port 5900) |
2148 | --serial-log F : log to F (default 'serial.log') |
2149 | + --root-arg X pass 'X' through as the root= param when booting a |
2150 | + kernel. default: $DEFAULT_ROOT_PARAM |
2151 | -v | --verbose be more verbose |
2152 | --no-install-deps do not install insert '--install-deps' |
2153 | on curtin command invocations |
2154 | @@ -188,7 +196,7 @@ |
2155 | # starts a web service at 'port' that serves files in 'pubdir' |
2156 | # waits until it is verified to be lisenting at ip |
2157 | # if port is not provided, '$tries' random ports are tried. |
2158 | - # |
2159 | + # |
2160 | # sets HTTP_PID and returns in _RET the port selected. |
2161 | local pubdir="$1" ip="$2" port="$3" tries="${4:-5}" i="" |
2162 | [ -z "$ip" ] && ip="localhost" |
2163 | @@ -212,7 +220,7 @@ |
2164 | [ "$port" = "random" ] && port=$(($pmin+($RANDOM%($pmax+1-$pmin)))) |
2165 | debug 2 "trying http server $ip:$port" |
2166 | _start_http "$pubdir" "$ip" "$port" && |
2167 | - HTTP_PID="$_RET" && _RET="$port" && |
2168 | + HTTP_PID="$_RET" && _RET="$port" && |
2169 | debug 1 "serving $pubdir at http://$ip:$port/ in pid $HTTP_PID" && |
2170 | return 0 |
2171 | ret=$? |
2172 | @@ -241,7 +249,7 @@ |
2173 | |
2174 | main() { |
2175 | local short_opts="a:A:d:h:i:k:n:p:v" |
2176 | - local long_opts="add:,append:,arch:,bios:,disk:,dowait,help,initrd:,kernel:,mem:,netdev:,no-dowait,power:,publish:,silent,serial-log:,uefi:,verbose,vnc:" |
2177 | + local long_opts="add:,append:,arch:,bios:,disk:,dowait,help,initrd:,kernel:,mem:,netdev:,no-dowait,power:,publish:,root-arg:,silent,serial-log:,uefi:,verbose,vnc:" |
2178 | local getopt_out="" |
2179 | getopt_out=$(getopt --name "${0##*/}" \ |
2180 | --options "${short_opts}" --long "${long_opts}" -- "$@") && |
2181 | @@ -258,6 +266,7 @@ |
2182 | local netdevs="" install_deps="--install-deps" |
2183 | local arch_hint="" |
2184 | local video="-curses -vga std" serial_log="serial.log" |
2185 | + local root_arg="$DEFAULT_ROOT_ARG" |
2186 | # dowait: run xkvm with a '&' and then 'wait' on the pid. |
2187 | # the reason to do this or not do this has to do with interactivity |
2188 | # if detached with &, then user input will not go to xkvm. |
2189 | @@ -280,13 +289,17 @@ |
2190 | case "$cur" in |
2191 | --add) addfiles[${#addfiles[@]}]="$next"; shift;; |
2192 | -a|--append) uappend="$next"; shift;; |
2193 | - -A|--arch) arch_hint="$next"; shift;; |
2194 | + -A|--arch) arch_hint="$next"; shift;; |
2195 | + --bios) bios="$2"; shift;; |
2196 | -d|--disk) disks[${#disks[@]}]="$next"; shift;; |
2197 | + --dowait) pt[${#pt[@]}]="$cur"; dowait=true;; |
2198 | -h|--help) Usage ; exit 0;; |
2199 | -i|--initrd) initrd="$next"; shift;; |
2200 | - --no-install-deps) install_deps="";; |
2201 | -k|--kernel) kernel="$next"; shift;; |
2202 | --mem) mem="$next"; shift;; |
2203 | + -n|--netdev) netdevs[${#netdevs[@]}]="$next"; shift;; |
2204 | + --no-dowait) pt[${#pt[@]}]="$cur"; dowait=false;; |
2205 | + --no-install-deps) install_deps="";; |
2206 | --power) |
2207 | case "$next" in |
2208 | off) pstate="poweroff";; |
2209 | @@ -295,19 +308,16 @@ |
2210 | *) error "Invalid power state, must be: off, on, reboot";; |
2211 | esac |
2212 | shift;; |
2213 | - -n|--netdev) netdevs[${#netdevs[@]}]="$next"; shift;; |
2214 | -p|--publish) pubs[${#pub[@]}]="$next"; shift;; |
2215 | + --root-arg) root_arg="$next";; |
2216 | + --serial-log) serial_log="$next"; shift;; |
2217 | + --silent) video="-nographic";; |
2218 | --uefi) uefi="$2"; shift;; |
2219 | - --bios) bios="$2"; shift;; |
2220 | - --silent) video="-nographic";; |
2221 | + -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; |
2222 | --vnc) |
2223 | video="-vnc $next" |
2224 | debug 1 "VNC requested - $next" |
2225 | shift;; |
2226 | - --serial-log) serial_log="$next"; shift;; |
2227 | - -v|--verbose) VERBOSITY=$((${VERBOSITY}+1));; |
2228 | - --dowait) pt[${#pt[@]}]="$cur"; dowait=true;; |
2229 | - --no-dowait) pt[${#pt[@]}]="$cur"; dowait=false;; |
2230 | --) shift; break;; |
2231 | esac |
2232 | shift; |
2233 | @@ -336,10 +346,10 @@ |
2234 | if [ -n "$bios" ]; then |
2235 | bios_opts=( -drive "if=pflash,format=raw,file=$bios" ) |
2236 | elif [ -n "$uefi" ]; then |
2237 | - case `lsb_release -sc` in |
2238 | + case `lsb_release -sc` in |
2239 | precise|trusty|vivid) |
2240 | # for non-split UEFI firmware, the code and |
2241 | - # var space are in the same file. We must |
2242 | + # var space are in the same file. We must |
2243 | # make a copy so we can retain modifications. |
2244 | local ovmf_code="/usr/share/ovmf/OVMF.fd" |
2245 | local ovmf_var=$ovmf_code |
2246 | @@ -388,21 +398,22 @@ |
2247 | { error "failed to get dir for $0"; return 1; } |
2248 | |
2249 | local disk="" src="" size="" fmt="" out="" id="" driver="" if="" |
2250 | - local split_input="" |
2251 | + local split_input="" serial="" |
2252 | disk_args=( ) |
2253 | id=1 |
2254 | for disk in "${disks[@]}"; do |
2255 | ((id++)) |
2256 | - |
2257 | # 1=src |
2258 | # 2=src:size |
2259 | # 3=src:size:driver |
2260 | # 4=src:size:driver:bsize |
2261 | + # 5=src:size:driver:bsize:devopts |
2262 | src=$(echo $disk | awk -F: '{print $1}') |
2263 | size=$(echo $disk | awk -F: '{print $2}') |
2264 | driver=$(echo $disk | awk -F: '{print $3}') |
2265 | bsize=$(echo $disk | awk -F: '{print $4}') |
2266 | - |
2267 | + devopts=$(echo $disk | awk -F: '{print $5}') |
2268 | + |
2269 | if [ -z "${src}" ]; then |
2270 | error "Failed to provide disk source" |
2271 | exit 1 |
2272 | @@ -415,7 +426,7 @@ |
2273 | if [ -z "${driver}" ]; then |
2274 | driver="virtio-blk" |
2275 | fi |
2276 | - |
2277 | + |
2278 | if [ -z "${bsize}" ]; then |
2279 | bsize="512" |
2280 | fi |
2281 | @@ -430,6 +441,11 @@ |
2282 | { error "failed to determine format of $src"; return 1; } |
2283 | fi |
2284 | |
2285 | + # prepend comma if passing devopts |
2286 | + if [ -n "${devopts}" ]; then |
2287 | + devopts=",${devopts}" |
2288 | + fi |
2289 | + |
2290 | # set logical/physical size blocksz is logical:phys |
2291 | local logbs=$(round_up ${bsize%%:*}) |
2292 | local phybs=$(round_up ${bsize##*:}) |
2293 | @@ -441,8 +457,8 @@ |
2294 | "file=${src},if=none,cache=unsafe,format=$fmt,id=drv${id},index=$id" ) |
2295 | |
2296 | disk_args=( "${disk_args[@]}" "-device" |
2297 | - "${driver},drive=drv${id},serial=dev${id},${bs_args}" ) |
2298 | - |
2299 | + "${driver},drive=drv${id},${bs_args}${devopts}" ) |
2300 | + |
2301 | done |
2302 | |
2303 | get_my_ip || { error "failed to get your ip. set IP_ADDR"; return 1; } |
2304 | @@ -554,17 +570,24 @@ |
2305 | seedargs=() |
2306 | if [ -n "$kernel" ]; then |
2307 | local append="" root="" |
2308 | - # if this is a partition image, root=/dev/vda. else root=/dev/vda1 |
2309 | - # this hack is necessary because LABEL even UUID might be the same |
2310 | - # in the boot image and the target (if re-using target) |
2311 | - if tmp=$(blkid "$bootimg_dist" -ovalue -s UUID) && [ -n "$tmp" ]; then |
2312 | - root="/dev/vda" |
2313 | - else |
2314 | - root="/dev/vda1" |
2315 | + # Note: root_arg is by default done by LABEL. This assumes |
2316 | + # a.) our root device is not multipath |
2317 | + # b.) no other disks attached will have this LABEL |
2318 | + # c.) the LABEL is in fact correct. |
2319 | + # all of these assumptions are true under vmtest. |
2320 | + if [ -z "$root_arg" ]; then |
2321 | + debug 1 "WARN: root_arg is empty with kernel." |
2322 | fi |
2323 | - append="root=$root ds=nocloud-net;seedfrom=$burl" |
2324 | - if [ "${arch_hint}" != "s390x" ]; then |
2325 | - append="${append} console=ttyS0" |
2326 | + append="${root_arg:+${root_arg} }ds=nocloud-net;seedfrom=$burl" |
2327 | + |
2328 | + local console_name="" |
2329 | + case "${arch_hint}" in |
2330 | + s390x) console_name="";; |
2331 | + ppc64*) console_name="hvc0";; |
2332 | + *) console_name="ttyS0";; |
2333 | + esac |
2334 | + if [ -n "$console_name" ]; then |
2335 | + append="${append} console=${console_name}" |
2336 | fi |
2337 | append="${append} $uappend" |
2338 | seedargs=( "${seedargs[@]}" -kernel "$kernel" ) |
2339 | @@ -586,18 +609,20 @@ |
2340 | local cmd serial_args="" chardev_arg="" |
2341 | [ "${serial_log}" = "none" ] && serial_log="" |
2342 | if [ -n "${serial_log}" ]; then |
2343 | - if [ "${arch_hint}" = "s390x" ]; then |
2344 | - if [ "${serial_log}" = "stdio" ]; then |
2345 | - chardev_arg="stdio" |
2346 | - else |
2347 | - chardev_arg="file,path=${serial_log}" |
2348 | - fi |
2349 | - serial_args="-nodefaults -chardev ${chardev_arg},id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0" |
2350 | - else |
2351 | - serial_args="-serial file:${serial_log}" |
2352 | - fi |
2353 | + if [ "${arch_hint}" = "s390x" ]; then |
2354 | + if [ "${serial_log}" = "stdio" ]; then |
2355 | + chardev_arg="stdio" |
2356 | + else |
2357 | + chardev_arg="file,path=${serial_log}" |
2358 | + fi |
2359 | + serial_args="-nodefaults -chardev ${chardev_arg},id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0" |
2360 | + else |
2361 | + serial_args="-serial file:${serial_log}" |
2362 | + #debug mode serial_args="-serial ${serial_log} -monitor stdio" |
2363 | + fi |
2364 | fi |
2365 | - cmd=( |
2366 | + # -monitor stdio |
2367 | + cmd=( |
2368 | xkvm "${pt[@]}" "${netargs[@]}" -- |
2369 | "${bios_opts[@]}" |
2370 | -m ${mem} ${serial_args} ${video} |
2371 | @@ -625,6 +650,11 @@ |
2372 | return $ret |
2373 | } |
2374 | |
2375 | +random_wwn() { |
2376 | + # wwn must be a int64, less than (1 << 63) - 1 |
2377 | + # we achieve this by combining 4 (1 << 15) ints |
2378 | + printf "0x%04x%04x%04x%04x" $RANDOM $RANDOM $RANDOM $RANDOM |
2379 | +} |
2380 | |
2381 | round_up() { |
2382 | local size="${1}" |
2383 | |
2384 | === modified file 'tools/vmtest-sync-images' |
2385 | --- tools/vmtest-sync-images 2016-05-10 16:13:29 +0000 |
2386 | +++ tools/vmtest-sync-images 2016-07-12 16:34:37 +0000 |
2387 | @@ -34,7 +34,11 @@ |
2388 | print(" removing vmtest file %s" % fpath) |
2389 | os.unlink(fpath) |
2390 | |
2391 | - releases = find_releases() |
2392 | + arg_releases = [r for r in sys.argv[1:] if r != "--clean"] |
2393 | + if len(arg_releases): |
2394 | + releases = arg_releases |
2395 | + else: |
2396 | + releases = find_releases() |
2397 | release_filter = 'release~{}'.format('|'.join(releases)) |
2398 | my_filters = ['arch=' + DEFAULT_ARCH, release_filter] + ITEM_NAME_FILTERS |
2399 | # Sync images. |
2400 | |
2401 | === modified file 'tools/xkvm' |
2402 | --- tools/xkvm 2016-05-10 16:13:29 +0000 |
2403 | +++ tools/xkvm 2016-07-12 16:34:37 +0000 |
2404 | @@ -77,14 +77,14 @@ |
2405 | |
2406 | NETDEV: |
2407 | Above, 'NETDEV' is a comma delimited string |
2408 | - The first field must be |
2409 | + The first field must be |
2410 | * bridge name: (br0 or virbr0): attach a device to this bridge |
2411 | * literal 'user': use qemu user networking |
2412 | - |
2413 | + |
2414 | Additional fields are optional, and can be anything that is acceptable |
2415 | to kvm either as: |
2416 | * '-device virtio-net-pci' option (see 'kvm -device virtio-net-pci,?') |
2417 | - * '-net [user|tap]' option |
2418 | + * '-net [user|tap]' option |
2419 | |
2420 | Example: |
2421 | * xkvm --netdev br0,macaddr=:05 -- -drive file=disk.img,if=virtio -curses |
2422 | @@ -345,7 +345,7 @@ |
2423 | if=sd|if=mtd|floppy) fail "do not know what to do with $tok on $cur";; |
2424 | id=*) id=$val;; |
2425 | file=*) file=$val;; |
2426 | - format=*) fmt=$val;; |
2427 | + fmt=*|format=*) fmt=$val;; |
2428 | serial=*) serial=$val;; |
2429 | bus=*) bus=$val;; |
2430 | unit=*) unit=$val;; |
2431 | @@ -357,6 +357,8 @@ |
2432 | out=$(LANG=C qemu-img info "$file") && |
2433 | fmt=$(echo "$out" | awk '$0 ~ /^file format:/ { print $3 }') || |
2434 | { error "failed to determine format of $file"; return 1; } |
2435 | + else |
2436 | + fmt=raw |
2437 | fi |
2438 | if [ -z "$driver" ]; then |
2439 | driver="$def_disk_driver" |
2440 | @@ -379,7 +381,8 @@ |
2441 | devopts="$driver,drive=$id${serial:+,serial=${serial}}" |
2442 | for tok in "$@"; do |
2443 | case "$tok" in |
2444 | - id=*|if=*|driver=*|$file) continue;; |
2445 | + id=*|if=*|driver=*|$file|file=*) continue;; |
2446 | + fmt=*|format=*) continue;; |
2447 | serial=*|bus=*|unit=*|index=*) continue;; |
2448 | esac |
2449 | isdevopt "$driver" "$tok" && devopts="${devopts},$tok" || |
2450 | @@ -529,7 +532,7 @@ |
2451 | |
2452 | netargs=() |
2453 | for((i=0;i<${#device_args[@]};i++)); do |
2454 | - netargs=( "${netargs[@]}" -device "${device_args[$i]}" |
2455 | + netargs=( "${netargs[@]}" -device "${device_args[$i]}" |
2456 | -netdev "${netdev_args[$i]}") |
2457 | done |
2458 |
i also added the debian/ new-upstream- snapshot fix.