~wesley-wiedenmeier/curtin/fstab

« back to all changes in this revision

Viewing changes to tests/vmtests/__init__.py

  • Committer: Ryan Harper
  • Date: 2016-06-24 19:45:04 UTC
  • mfrom: (389.5.13 trunk.vmtest-multipath)
  • Revision ID: ryan.harper@canonical.com-20160624194504-vlexvzp38lobcjnj
fix multipath configuration and add multipath tests

Xenial multipath fails without ensuring the multipath/bindings file is written
with whitespace removed; this is triggered on in-target mulitpath versions 
>= 1.5.0. This fixes LP:1551937

Add multipath testing via a test-case option, cls.multipath which will
if set to true, duplicate all disks in a test class.  This has the effect
of looking exactly like multipath setups where we see the same device
with two paths.

To handle devices with wwn or serial numbers with spaces in them curtin.block
was updated to ensure it supports finding devices via there serial or wwn
attribute. Specifically for serial numbers with spaces, we currently will
escape the spaces to underscores; this is supported by observing the names
that show up in /dev/disk/by-id/* for those devices.

For wwn, /dev/disk/by-id/wwn-$wwn ; curtin resolves the symlink target to
obtain a kernel devname for use with sysfs.

For serial with spaces, curtin attempts to remove whitespace like udev to
find the disk under /dev/disk/by-id/ and determine a devname.

Show diffs side-by-side

added added

removed removed

Lines of Context:
48
48
 
49
49
 
50
50
DEFAULT_BRIDGE = os.environ.get("CURTIN_VMTEST_BRIDGE", "user")
 
51
OUTPUT_DISK_NAME = 'output_disk.img'
51
52
 
52
53
_TOPDIR = None
53
54
 
333
334
 
334
335
        # create output disk, mount ro
335
336
        logger.debug('Creating output disk')
336
 
        self.output_disk = os.path.join(self.boot, "output_disk.img")
 
337
        self.output_disk = os.path.join(self.boot, OUTPUT_DISK_NAME)
337
338
        subprocess.check_call(["qemu-img", "create", "-f", TARGET_IMAGE_FORMAT,
338
339
                              self.output_disk, "10M"],
339
340
                              stdout=DEVNULL, stderr=subprocess.STDOUT)
350
351
class VMBaseClass(TestCase):
351
352
    __test__ = False
352
353
    arch_skip = []
 
354
    boot_timeout = 300
 
355
    collect_scripts = []
 
356
    conf_file = "examples/tests/basic.yaml"
353
357
    disk_block_size = 512
 
358
    disk_driver = 'virtio-blk'
354
359
    disk_to_check = {}
 
360
    extra_disks = []
 
361
    extra_kern_args = None
355
362
    fstab_expected = {}
356
 
    extra_kern_args = None
357
 
    recorded_errors = 0
358
 
    recorded_failures = 0
359
363
    image_store_class = ImageStore
360
 
    collect_scripts = []
 
364
    install_timeout = 3000
361
365
    interactive = False
362
 
    conf_file = "examples/tests/basic.yaml"
363
 
    extra_disks = []
 
366
    multipath = False
 
367
    multipath_num_paths = 2
364
368
    nvme_disks = []
365
 
    boot_timeout = 300
366
 
    install_timeout = 3000
 
369
    recorded_errors = 0
 
370
    recorded_failures = 0
367
371
    uefi = False
368
372
 
369
373
    # these get set from base_vm_classes
446
450
            netdevs.extend(["--netdev=" + DEFAULT_BRIDGE])
447
451
 
448
452
        # build disk arguments
449
 
        # --disk source:size:driver:block_size
450
 
        extra_disks = []
 
453
        disks = []
 
454
        sc = util.load_file(cls.conf_file)
 
455
        storage_config = yaml.load(sc).get('storage', {}).get('config', {})
 
456
        cls.disk_wwns = ["wwn=%s" % x.get('wwn') for x in storage_config
 
457
                         if 'wwn' in x]
 
458
        cls.disk_serials = ["serial=%s" % x.get('serial')
 
459
                            for x in storage_config if 'serial' in x]
 
460
 
 
461
        target_disk = "{}:{}:{}:{}:".format(cls.td.target_disk,
 
462
                                            "",
 
463
                                            cls.disk_driver,
 
464
                                            cls.disk_block_size)
 
465
        if len(cls.disk_wwns):
 
466
            target_disk += cls.disk_wwns[0]
 
467
 
 
468
        if len(cls.disk_serials):
 
469
            target_disk += cls.disk_serials[0]
 
470
 
 
471
        disks.extend(['--disk', target_disk])
 
472
 
 
473
        # --disk source:size:driver:block_size:devopts
451
474
        for (disk_no, disk_sz) in enumerate(cls.extra_disks):
452
475
            dpath = os.path.join(cls.td.disks, 'extra_disk_%d.img' % disk_no)
453
 
            extra_disks.extend(
454
 
                ['--disk', '{}:{}:{}:{}'.format(dpath, disk_sz, "",
455
 
                                                cls.disk_block_size)])
 
476
            extra_disk = '{}:{}:{}:{}:'.format(dpath, disk_sz,
 
477
                                               cls.disk_driver,
 
478
                                               cls.disk_block_size)
 
479
            if len(cls.disk_wwns):
 
480
                w_index = disk_no + 1
 
481
                if w_index < len(cls.disk_wwns):
 
482
                    extra_disk += cls.disk_wwns[w_index]
 
483
 
 
484
            if len(cls.disk_serials):
 
485
                w_index = disk_no + 1
 
486
                if w_index < len(cls.disk_serials):
 
487
                    extra_disk += cls.disk_serials[w_index]
 
488
 
 
489
            disks.extend(['--disk', extra_disk])
456
490
 
457
491
        # build nvme disk args if needed
458
 
        nvme_disks = []
459
492
        for (disk_no, disk_sz) in enumerate(cls.nvme_disks):
460
493
            dpath = os.path.join(cls.td.disks, 'nvme_disk_%d.img' % disk_no)
461
 
            nvme_disks.extend(
462
 
                ['--disk', '{}:{}:nvme:{}'.format(dpath, disk_sz,
463
 
                                                  cls.disk_block_size)])
 
494
            nvme_disk = '{}:{}:nvme:{}:{}'.format(dpath, disk_sz,
 
495
                                                  cls.disk_block_size,
 
496
                                                  "serial=nvme-%d" % disk_no)
 
497
            disks.extend(['--disk', nvme_disk])
464
498
 
465
499
        # proxy config
466
500
        configs = [cls.conf_file]
485
519
            shutil.copy(OVMF_VARS, nvram)
486
520
            cmd.extend(["--uefi", nvram])
487
521
 
488
 
        # --disk source:size:driver:block_size
489
 
        target_disk = "{}:{}:{}:{}".format(cls.td.target_disk, "", "",
490
 
                                           cls.disk_block_size)
491
 
        cmd.extend(netdevs + ["--disk", target_disk] +
492
 
                   extra_disks + nvme_disks +
 
522
        if cls.multipath:
 
523
            disks = disks * cls.multipath_num_paths
 
524
 
 
525
        cmd.extend(netdevs + disks +
493
526
                   [boot_img, "--kernel=%s" % boot_kernel, "--initrd=%s" %
494
527
                    boot_initrd, "--", "curtin", "-vv", "install"] +
495
528
                   ["--config=%s" % f for f in configs] +
535
568
            cls.tearDownClass()
536
569
            raise
537
570
 
538
 
        # drop the size parameter if present in extra_disks
539
 
        extra_disks = [x if ":" not in x else x.split(':')[0]
540
 
                       for x in extra_disks]
541
571
        # create --disk params for nvme disks
542
572
        bsize_args = "logical_block_size={}".format(cls.disk_block_size)
543
573
        bsize_args += ",physical_block_size={}".format(cls.disk_block_size)
544
574
        bsize_args += ",min_io_size={}".format(cls.disk_block_size)
545
 
        disk_driver = "virtio-blk"
546
575
 
547
576
        target_disks = []
548
 
        for (disk_no, disk) in enumerate([cls.td.target_disk,
549
 
                                          cls.td.output_disk]):
550
 
            d = '--disk={},driver={},format={},{}'.format(disk, disk_driver,
551
 
                                                          TARGET_IMAGE_FORMAT,
552
 
                                                          bsize_args)
553
 
            target_disks.extend([d])
 
577
        for (disk_no, disk) in enumerate([cls.td.target_disk]):
 
578
            disk = '--disk={},driver={},format={},{}'.format(
 
579
                disk, cls.disk_driver, TARGET_IMAGE_FORMAT, bsize_args)
 
580
            if len(cls.disk_wwns):
 
581
                disk += ",%s" % cls.disk_wwns[0]
 
582
            if len(cls.disk_serials):
 
583
                disk += ",%s" % cls.disk_serials[0]
 
584
 
 
585
            target_disks.extend([disk])
554
586
 
555
587
        extra_disks = []
556
588
        for (disk_no, disk_sz) in enumerate(cls.extra_disks):
557
589
            dpath = os.path.join(cls.td.disks, 'extra_disk_%d.img' % disk_no)
558
 
            d = '--disk={},driver={},format={},{}'.format(dpath, disk_driver,
559
 
                                                          TARGET_IMAGE_FORMAT,
560
 
                                                          bsize_args)
561
 
            extra_disks.extend([d])
 
590
            disk = '--disk={},driver={},format={},{}'.format(
 
591
                dpath, cls.disk_driver, TARGET_IMAGE_FORMAT, bsize_args)
 
592
            if len(cls.disk_wwns):
 
593
                w_index = disk_no + 1
 
594
                if w_index < len(cls.disk_wwns):
 
595
                    disk += ",%s" % cls.disk_wwns[w_index]
 
596
 
 
597
            if len(cls.disk_serials):
 
598
                w_index = disk_no + 1
 
599
                if w_index < len(cls.disk_serials):
 
600
                    disk += ",%s" % cls.disk_serials[w_index]
 
601
 
 
602
            extra_disks.extend([disk])
562
603
 
563
604
        nvme_disks = []
564
605
        disk_driver = 'nvme'
565
606
        for (disk_no, disk_sz) in enumerate(cls.nvme_disks):
566
607
            dpath = os.path.join(cls.td.disks, 'nvme_disk_%d.img' % disk_no)
567
 
            d = '--disk={},driver={},format={},{}'.format(dpath, disk_driver,
568
 
                                                          TARGET_IMAGE_FORMAT,
569
 
                                                          bsize_args)
570
 
            nvme_disks.extend([d])
 
608
            disk = '--disk={},driver={},format={},{}'.format(
 
609
                dpath, disk_driver, TARGET_IMAGE_FORMAT, bsize_args)
 
610
            nvme_disks.extend([disk])
 
611
 
 
612
        if cls.multipath:
 
613
            target_disks = target_disks * cls.multipath_num_paths
 
614
            extra_disks = extra_disks * cls.multipath_num_paths
 
615
            nvme_disks = nvme_disks * cls.multipath_num_paths
 
616
 
 
617
        # output disk is always virtio-blk, with serial of output_disk.img
 
618
        output_disk = '--disk={},driver={},format={},{},{}'.format(
 
619
            cls.td.output_disk, 'virtio-blk',
 
620
            TARGET_IMAGE_FORMAT, bsize_args,
 
621
            'serial=%s' % os.path.basename(cls.td.output_disk))
 
622
        target_disks.extend([output_disk])
571
623
 
572
624
        # create xkvm cmd
573
625
        cmd = (["tools/xkvm", "-v", dowait] + netdevs +
951
1003
              'content': yaml.dump(base_cloudconfig, indent=1)},
952
1004
             {'type': 'text/cloud-config', 'content': ssh_keys}]
953
1005
 
 
1006
    output_dir = '/mnt/output'
954
1007
    output_dir_macro = 'OUTPUT_COLLECT_D'
955
 
    output_dir = '/mnt/output'
956
 
    output_device = '/dev/vdb'
 
1008
    output_device = '/dev/disk/by-id/virtio-%s' % OUTPUT_DISK_NAME
957
1009
 
958
1010
    collect_prep = textwrap.dedent("mkdir -p " + output_dir)
959
1011
    collect_post = textwrap.dedent(
961
1013
 
962
1014
    # failsafe poweroff runs on precise only, where power_state does
963
1015
    # not exist.
964
 
    precise_poweroff = textwrap.dedent("""#!/bin/sh
 
1016
    precise_poweroff = textwrap.dedent("""#!/bin/sh -x
965
1017
        [ "$(lsb_release -sc)" = "precise" ] || exit 0;
966
1018
        shutdown -P now "Shutting down on precise"
967
1019
        """)
971
1023
 
972
1024
    for part in scripts:
973
1025
        if not part.startswith("#!"):
974
 
            part = "#!/bin/sh\n" + part
 
1026
            part = "#!/bin/sh -x\n" + part
975
1027
        part = part.replace(output_dir_macro, output_dir)
976
1028
        logger.debug('Cloud config archive content (pre-json):' + part)
977
1029
        parts.append({'content': part, 'type': 'text/x-shellscript'})