Ejemplo n.º 1
0
def group_test(test, params, env, vm, session):
    """
    :param test:
    :param params:
    :param env:
    :param vm:
    :param session:
    :return:
    """
    logging.info(test, params, env, vm, session)
    tgm = ThrottleGroupManager(vm)
    tgm.get_throttle_group_props("group2")
    logging.info(vm.devices.str_bus_short())
    images = ["stg2", "stg4"]
    tester1 = ThrottleTester(test, params, vm, session, "group2", images)
    tester1.build_default_option()
    images_info = tester1.build_images_fio_option()
    print(images_info)

    fio = generate_instance(params, vm, 'fio')
    tester1.set_fio(fio)
    # tester1.start()

    groups_tester = ThrottleGroupsTester([tester1])
    groups_tester.start()
Ejemplo n.º 2
0
 def run_iozone(timeout):
     """ Do iozone testing inside guest. """
     logging.info("Do iozone testing on data disks.")
     iozone = generate_instance(params, vm, 'iozone')
     try:
         for target in format_data_disks():
             iozone.run(stress_options.format(target), timeout)
     finally:
         iozone.clean()
Ejemplo n.º 3
0
 def run_iozone(mount_points):
     """ Run iozone inside guest. """
     iozone = generate_instance(params, vm, 'iozone')
     try:
         for mount_point in mount_points:
             iozone.run(params['iozone_cmd_opitons'] % mount_point,
                        int(params['iozone_timeout']))
     finally:
         iozone.clean()
Ejemplo n.º 4
0
 def run_stress_iozone():
     error_context.context("Run iozone stress after hotplug", logging.info)
     iozone = generate_instance(params, vm, 'iozone')
     try:
         iozone_cmd_option = params['iozone_cmd_option']
         iozone_timeout = float(params['iozone_timeout'])
         for letter in _initial_win_drives():
             iozone.run(iozone_cmd_option.format(letter), iozone_timeout)
     finally:
         iozone.clean()
Ejemplo n.º 5
0
 def fio_thread(self):
     fio_options = self.params.get("fio_options")
     if fio_options:
         logging.info("Start to run fio")
         fio = generate_instance(self.params, self.main_vm, 'fio')
         try:
             fio.run(fio_options)
         finally:
             fio.clean()
         self.main_vm.verify_dmesg()
Ejemplo n.º 6
0
 def _fio_test(session):
     """ Execute fio testing inside guest. """
     logging.info('Doing fio testing inside guest.')
     session = utils_test.qemu.windrv_check_running_verifier(
         session, vm, test, params["driver_name"])
     fio = generate_instance(params, vm, 'fio')
     try:
         fio.run(params['fio_options'], float(params['stress_timeout']))
     finally:
         fio.clean()
Ejemplo n.º 7
0
 def fio_thread():
     """
     run fio command in guest
     """
     # generate instance with fio
     fio = generate_instance(params, vm, 'fio')
     try:
         fio.run(run_fio_options)
     finally:
         fio.clean()
Ejemplo n.º 8
0
def run(test, params, env):
    """
    Boot guest with "aio=native" or "aio=threads" CLI option and run fio tools.
    Step:
        1. Boot guest with "aio=threads,cache=none" option.
        2. Run fio tool to the data disk in guest.
        3. Boot guest with "aio=native, cache=none" option
           (cmd lines refer to step 1).
        4. Run fio tool to the data disk in guest.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def _get_data_disks():
        """ Get the data disks by serial or wwn options. """
        for data_image in data_images:
            extra_params = params.get("blk_extra_params_%s" % data_image, '')
            match = re.search(r"(serial|wwn)=(\w+)", extra_params, re.M)
            if match:
                drive_id = match.group(2)
            else:
                continue
            drive_path = utils_misc.get_linux_drive_path(session, drive_id)
            if not drive_path:
                test.error("Failed to get '%s' drive path" % data_image)
            yield drive_path[5:]

    def _run_fio_test(target):
        for option in params['fio_options'].split(';'):
            fio.run('--filename=%s %s' % (target, option))

    data_images = params["images"].split()[1:]
    info = []
    for image in data_images:
        aio = params.get('image_aio_%s' % image, 'threads')
        cache = params.get('drive_cache_%s' % image, 'none')
        info.append('%s(\"aio=%s,cache=%s\")' % (image, aio, cache))
    logging.info('Boot a guest with %s.' % ', '.join(info))

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(
        timeout=float(params.get("login_timeout", 240)))
    fio = generate_instance(params, vm, 'fio')
    try:
        if params.get('image_backend') == 'nvme_direct':
            _run_fio_test(params.get('fio_filename'))
        else:
            for did in _get_data_disks():
                _run_fio_test(did)
    finally:
        fio.clean()
        session.close()
Ejemplo n.º 9
0
 def fio_thread(self):
     fio_options = self.params.get("fio_options")
     if fio_options:
         logging.info("Start to run fio")
         self.fio = generate_instance(self.params, self.main_vm, 'fio')
         fio_run_timeout = self.params.get_numeric("fio_timeout", 2400)
         try:
             self.fio.run(fio_options, fio_run_timeout)
         finally:
             self.fio.clean()
         self.main_vm.verify_dmesg()
Ejemplo n.º 10
0
 def _iozone_test(session):
     """ Execute iozone testing inside guest. """
     logging.info('Doing iozone inside guest.')
     if os_type == 'windows':
         session = utils_test.qemu.windrv_check_running_verifier(
             session, vm, test, params["driver_name"])
     iozone = generate_instance(params, vm, 'iozone')
     try:
         iozone.run(params['iozone_options'], float(params['iozone_timeout']))
     finally:
         iozone.clean()
         return session
Ejemplo n.º 11
0
    def run_iozone_background(vm):
        """
        run iozone in guest

        :param vm: vm object
        """
        logging.debug("Start iozone in background.")
        iozone = generate_instance(params, vm, 'iozone')
        args = (params['iozone_cmd_opitons'], int(params['iozone_timeout']))
        iozone_thread = utils_misc.InterruptedThread(iozone.run, args)
        iozone_thread.start()
        if not utils_misc.wait_for(lambda: iozone_thread.is_alive, 60):
            test.error("Failed to start iozone thread.")
        return iozone_thread
Ejemplo n.º 12
0
 def run_io_test(session, partition):
     """ Run io test on the hot plugged disk. """
     iozone_options = params.get('iozone_options')
     dd_test = params.get('dd_test')
     if iozone_options:
         error_context.context("Run iozone test on the plugged disk.",
                               logging.info)
         iozone = generate_instance(params, vm, 'iozone')
         iozone.run(iozone_options.format(partition[0]))
     if dd_test:
         error_context.context("Do dd test on the plugged disk",
                               logging.info)
         partition = partition.split("/")[-1]
         session.cmd(dd_test.format(partition))
Ejemplo n.º 13
0
def run(test, params, env):
    """
    Test hot plug and unplug NVMe device.

    Steps:
        1. Install guest with local filesystem.
        2. Hot plug NVMe device to guest.
        3. Check if the NVMe device exists in qemu side.
        4. Check if the NVMe has been successfully added to guest.
        5. Run fio in the hot plugged NVMe device in guest.
        6. Unplug the NVMe device.
        7. Check if the NVMe device still exists.
        8. Check if the NVMe has been successfully removed from guest.
        9. Reboot guest.

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    unattended_install.run(test, params, env)

    if params.get('remove_options'):
        for option in params.get('remove_options').split():
            del params[option]
    params['cdroms'] = params.get('default_cdroms')

    params['start_vm'] = 'yes'
    env_process.preprocess_vm(test, params, env, params["main_vm"])
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login()

    plug = BlockDevicesPlug(vm)
    plug.hotplug_devs_serial()
    target = '/dev/%s' % plug[0]
    os_type = params['os_type']
    data_img_size = params.get('image_size_%s' % params.get('data_img_tag'))
    if os_type == 'windows':
        utils_disk.update_windows_disk_attributes(session, plug[0])
        drive_letter = utils_disk.configure_empty_disk(session, plug[0],
                                                       data_img_size,
                                                       os_type)[0]
        target = r'%s\:\\%s' % (drive_letter, params.get('fio_filename'))
    fio = generate_instance(params, vm, 'fio')
    for option in params['fio_options'].split(';'):
        fio.run('--filename=%s %s' % (target, option))
    plug.unplug_devs_serial()
    vm.reboot(session)
Ejemplo n.º 14
0
    def _run_fio(session, drive_letter):
        """
        First format tmpfs disk to wipe out cache,
        then run fio test, and return the result's bw value

        param session: a session loggined to guest os
        drive_letter: the drive to run the fio job on
        return: the bw value of the running result(bw=xxxB/s)
        """
        bw_search_reg = params["bw_search_reg"]
        logging.info("Format tmpfs data disk")
        utils_disk.create_filesystem_windows(session, drive_letter, "ntfs")
        logging.info("Start fio test")
        fio = generate_instance(params, vm, 'fio')
        o = fio.run(params["fio_options"] % drive_letter)
        return int(re.search(bw_search_reg, o, re.M).group(1))
Ejemplo n.º 15
0
def run(test, params, env):
    """
    Boot guest with "aio=native" or "aio=threads" CLI option and run fio tools.
    Step:
        1. Boot guest with "aio=threads,cache=none" option.
        2. Run fio tool to the data disk in guest.
        3. Boot guest with "aio=native, cache=none" option
           (cmd lines refer to step 1).
        4. Run fio tool to the data disk in guest.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def _get_data_disks():
        """ Get the data disks by serial or wwn options. """
        for data_image in data_images:
            extra_params = params.get("blk_extra_params_%s" % data_image, '')
            match = re.search(r"(serial|wwn)=(\w+)", extra_params, re.M)
            if match:
                drive_id = match.group(2)
            else:
                continue
            drive_path = utils_misc.get_linux_drive_path(session, drive_id)
            if not drive_path:
                test.error("Failed to get '%s' drive path" % data_image)
            yield drive_path[5:]

    data_images = params["images"].split()[1:]
    info = []
    for image in data_images:
        aio = params.get('image_aio_%s' % image, 'threads')
        cache = params.get('drive_cache_%s' % image, 'none')
        info.append('%s(\"aio=%s,cache=%s\")' % (image, aio, cache))
    logging.info('Boot a guest with %s.' % ', '.join(info))

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(timeout=float(params.get("login_timeout", 240)))
    try:
        fio = generate_instance(params, session, 'fio')
        for did in _get_data_disks():
            for option in params['fio_options'].split(';'):
                fio.run('--filename=%s %s' % (did, option))
    finally:
        fio.clean()
        session.close()
 def fio_on_vm(vm_t, session_t):
     error_context.context("Deploy fio", logging.info)
     fio = generate_instance(params, vm_t, 'fio')
     logging.info("fio: %s", fio)
     tgm = ThrottleGroupManager(vm_t)
     logging.info("tgm: %s", tgm)
     groups = params["throttle_groups"].split()
     testers = []
     for group in groups:
         tgm.get_throttle_group_props(group)
         images = params["throttle_group_member_%s" % group].split()
         tester = ThrottleTester(test, params, vm_t, session_t, group,
                                 images)
         error_context.context(
             "Build test stuff for %s:%s" % (group, images), logging.info)
         tester.build_default_option()
         tester.build_images_fio_option()
         tester.set_fio(fio)
         testers.append(tester)
     error_context.context("Start groups testing:%s" % groups, logging.info)
     groups_tester = ThrottleGroupsTester(testers)
     groups_tester.start()
Ejemplo n.º 17
0
def run(test, params, env):
    """
        Test throttle relevant properties feature.

        1) Boot up guest with throttle groups.
        There are two throttle groups and each have two disk
        2) Build fio operation options and expected result
         according to throttle properties.
        3) Execute one disk or all disks testing on groups parallel.
    """

    error_context.context("Get the main VM", test.log.info)
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=360)

    error_context.context("Deploy fio", test.log.info)
    fio = generate_instance(params, vm, 'fio')

    tgm = ThrottleGroupManager(vm)
    groups = params["throttle_groups"].split()
    testers = []
    for group in groups:
        tgm.get_throttle_group_props(group)
        images = params["throttle_group_member_%s" % group].split()
        tester = ThrottleTester(test, params, vm, session, group, images)
        error_context.context("Build test stuff for %s:%s" % (group, images),
                              test.log.info)
        tester.build_default_option()
        tester.build_images_fio_option()
        tester.set_fio(fio)
        testers.append(tester)

    error_context.context("Start groups testing:%s" % groups, test.log.info)
    groups_tester = ThrottleGroupsTester(testers)

    groups_tester.start()
Ejemplo n.º 18
0
def run(test, params, env):
    """
    KVM block resize test:

    1) Start guest with data disk or system disk.
    2) Do format disk in guest if needed.
    3) Record md5 of test file on the data disk.
       Enlarge the data disk image from qemu monitor.
    4) Extend data disk partition/file-system in guest.
    5) Verify the data disk size match expected size.
    6) Reboot the guest.
    7) Do iozone test, compare the md5 of test file.
    8) Shrink data disk partition/file-system in guest.
    9) Shrink data disk image from qemu monitor.
    10) Verify the data disk size match expected size.
    11) Reboot the guest.
    12) Do iozone test, compare the md5 of test file.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def verify_disk_size(session, os_type, disk):
        """
        Verify the current block size match with the expected size.
        """
        global current_size
        current_size = utils_disk.get_disk_size(session, os_type, disk)
        accept_ratio = float(params.get("accept_ratio", 0))
        if (current_size <= block_size
                and current_size >= block_size * (1 - accept_ratio)):
            logging.info(
                "Block Resizing Finished !!! \n"
                "Current size %s is same as the expected %s", current_size,
                block_size)
            return True

    def create_md5_file(filename):
        """
        Create the file to verify md5 value.
        """
        logging.debug("create md5 file %s" % filename)
        if os_type == 'windows':
            vm.copy_files_to(params["tmp_md5_file"], filename)
        else:
            session.cmd(params["dd_cmd"] % filename)

    def get_md5_of_file(filename):
        """
        Get the md5 value of filename.
        """
        ex_args = (mpoint, filename) if os_type == 'windows' else filename
        return session.cmd(md5_cmd % ex_args).split()[0]

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = float(params.get("login_timeout", 240))
    driver_name = params.get("driver_name")
    os_type = params["os_type"]
    fstype = params.get("fstype")
    labeltype = params.get("labeltype", "msdos")
    img_size = params.get("image_size_stg", "10G")
    mpoint = params.get("disk_letter", "C")
    disk = params.get("disk_index", 0)
    md5_cmd = params.get("md5_cmd", "md5sum %s")
    md5_file = params.get("md5_file", "md5.dat")
    data_image = params.get("images").split()[-1]
    data_image_params = params.object_params(data_image)
    data_image_filename = storage.get_image_filename(data_image_params,
                                                     data_dir.get_data_dir())
    data_image_dev = vm.get_block({'file': data_image_filename})
    img = QemuImg(data_image_params, data_dir.get_data_dir(), data_image)
    block_virtual_size = json.loads(img.info(force_share=True,
                                             output="json"))["virtual-size"]

    session = vm.wait_for_login(timeout=timeout)

    if os_type == 'windows' and driver_name:
        session = utils_test.qemu.windrv_check_running_verifier(
            session, vm, test, driver_name, timeout)

    if params.get("format_disk") == "yes":
        if os_type == 'linux':
            disk = sorted(utils_disk.get_linux_disks(session).keys())[0]
        else:
            disk = utils_disk.get_windows_disks_index(session, img_size)[0]
            utils_disk.update_windows_disk_attributes(session, disk)
        error_context.context("Formatting disk", logging.info)
        mpoint = utils_disk.configure_empty_disk(session,
                                                 disk,
                                                 img_size,
                                                 os_type,
                                                 fstype=fstype,
                                                 labeltype=labeltype)[0]
        partition = mpoint.replace('mnt', 'dev') if 'mnt' in mpoint else None

    for ratio in params.objects("disk_change_ratio"):
        block_size = int(int(block_virtual_size) * float(ratio))

        # Record md5
        if params.get('md5_test') == 'yes':
            junction = ":\\" if os_type == 'windows' else "/"
            md5_filename = mpoint + junction + md5_file
            create_md5_file(md5_filename)
            md5 = get_md5_of_file(md5_filename)
            logging.debug("Got md5 %s ratio:%s on %s" % (md5, ratio, disk))

        # We need shrink the disk in guest first, than in monitor
        if float(ratio) < 1.0:
            error_context.context(
                "Shrink disk size to %s in guest" % block_size, logging.info)
            if os_type == 'windows':
                shr_size = utils_numeric.normalize_data_size(
                    str(
                        utils_disk.get_disk_size(session, os_type, disk) -
                        block_size), 'M').split(".")[0]
                drive.shrink_volume(session, mpoint, shr_size)
            else:
                utils_disk.resize_filesystem_linux(session, partition,
                                                   str(block_size))
                utils_disk.resize_partition_linux(session, partition,
                                                  str(block_size))

        error_context.context("Change disk size to %s in monitor" % block_size,
                              logging.info)
        if vm.check_capability(Flags.BLOCKDEV):
            args = (None, block_size, data_image_dev)
        else:
            args = (data_image_dev, block_size)
        vm.monitor.block_resize(*args)

        if params.get("guest_prepare_cmd", ""):
            session.cmd(params.get("guest_prepare_cmd"))
        # Update GPT due to size changed
        if os_type == "linux" and labeltype == "gpt":
            session.cmd("sgdisk -e /dev/%s" % disk)
        if params.get("need_reboot") == "yes":
            session = vm.reboot(session=session)
        if params.get("need_rescan") == "yes":
            drive.rescan_disks(session)

        # We need extend disk in monitor first than extend it in guest
        if float(ratio) > 1.0:
            error_context.context("Extend disk to %s in guest" % block_size,
                                  logging.info)
            if os_type == 'windows':
                drive.extend_volume(session, mpoint)
            else:
                utils_disk.resize_partition_linux(session, partition,
                                                  str(block_size))
                utils_disk.resize_filesystem_linux(session, partition,
                                                   utils_disk.SIZE_AVAILABLE)
        global current_size
        current_size = 0
        if not wait.wait_for(lambda: verify_disk_size(session, os_type, disk),
                             20, 0, 1, "Block Resizing"):
            test.fail("Block size get from guest is not same as expected.\n"
                      "Reported: %s\nExpect: %s\n" %
                      (current_size, block_size))
        session = vm.reboot(session=session)

        if os_type == 'linux':
            if not utils_disk.is_mount(
                    partition, dst=mpoint, fstype=fstype, session=session):
                utils_disk.mount(partition,
                                 mpoint,
                                 fstype=fstype,
                                 session=session)

        if params.get('iozone_test') == 'yes':
            iozone_timeout = float(params.get("iozone_timeout", 1800))
            iozone_cmd_options = params.get("iozone_option") % mpoint
            io_test = generate_instance(params, vm, 'iozone')
            try:
                io_test.run(iozone_cmd_options, iozone_timeout)
            finally:
                io_test.clean()

        # Verify md5
        if params.get('md5_test') == 'yes':
            new_md5 = get_md5_of_file(md5_filename)
            test.assertTrue(new_md5 == md5, "Unmatched md5: %s" % new_md5)

    session.close()
Ejemplo n.º 19
0
def run(test, params, env):
    """
    Special hardware test case.
    FC host: ibm-x3650m4-05.lab.eng.pek2.redhat.com
    Disk serial name: scsi-360050763008084e6e0000000000001a4
    # multipath -ll
    mpathb (360050763008084e6e0000000000001a8) dm-4 IBM,2145
    size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
    |-+- policy='service-time 0' prio=50 status=active
    | `- 2:0:1:0 sde 8:64 active ready running
    `-+- policy='service-time 0' prio=10 status=enabled
      `- 2:0:0:0 sdd 8:48 active ready running
    mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
    size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
    |-+- policy='service-time 0' prio=50 status=active
    | `- 1:0:1:0 sdc 8:32 active ready running
    `-+- policy='service-time 0' prio=10 status=enabled
      `- 1:0:0:0 sdb 8:16 active ready running
    Customer Bug ID: 1741937  1673546

    Test if VM paused/resume when fc storage offline/online.

    1) pass-through /dev/mapper/mpatha
    2) install guest on pass-through disk
    3) Disconnect the storage during installation
    4) Check if VM status is 'paused'
    5) Connect the storage, Wait until the storage is accessible again
    6) resume the vm
    7) Check if VM status is 'running'
    8) installation completed successfully
    9) re-pass-through /dev/mapper/mpatha
    10) fio test on pass-through disk
    11) Disconnect any path of multipath during fio testing
    12) Check if VM status is 'paused'
    13) Connect the storage, Wait until the storage is accessible again
    14) resume the vm
    15) fio testing completed successfully

    :param test: kvm test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    def check_vm_status(vm, status):
        """
        Check if VM has the given status or not.

        :param vm: VM object.
        :param status: String with desired status.
        :return: True if VM status matches our desired status.
        :return: False if VM status does not match our desired status.
        """
        try:
            current_status = vm.monitor.get_status()
            vm.verify_status(status)
        except (virt_vm.VMStatusError, qemu_monitor.MonitorLockError):
            logging.info("Failed to check vm status, it is '%s' "
                         "instead of '%s'" % (current_status, status))
            return False
        except Exception as e:
            logging.info("Failed to check vm status: %s" % six.text_type(e))
            logging.info("vm status is '%s' instead of"
                         " '%s'" % (current_status, status))
            return False
        else:
            logging.info("Check vm status successfully. It is '%s'" % status)
            return True

    def get_multipath_disks(mpath_name="mpatha"):
        """
        Get all disks of multiple paths.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16  active ready running

        :param mpath_name: multi-path name.
        :return: a list. if get disks successfully or raise a error
        """
        logging.info("get_multipath_disks:" + mpath_name)
        disks = []
        disk_str = []
        outputs = process.run("multipath -ll " + mpath_name,
                              shell=True).stdout.decode()
        outputs = outputs.split(mpath_name)[-1]
        disk_str.append("active ready running")
        disk_str.append("active faulty offline")
        disk_str.append("failed faulty offline")
        disk_str.append("failed ready running")
        for line in outputs.splitlines():
            if disk_str[0] in line or disk_str[1] in line or disk_str[2] \
                    in line or disk_str[3] in line:
                disks.append(line.split()[-5])
        if not disks:
            test.fail("Failed to get disks by 'multipath -ll'")
        else:
            return disks

    def get_multipath_disks_status(mpath_name="mpatha"):
        """
        Get status of multiple paths.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16  active ready running

        :param mpath_name: multi-path name.
        :return: a dict. e.g. {"sdb": "running", "sdc": "running"}
        """
        disks = get_multipath_disks(mpath_name)
        disks_status = {}
        outputs = process.run("multipath -ll " + mpath_name,
                              shell=True).stdout.decode()
        outputs = outputs.split(mpath_name)[-1]
        for line in outputs.splitlines():
            for i in range(len(disks)):
                if disks[i] in line:
                    disks_status[disks[i]] = line.strip().split()[-1]
                    break
        if not disks_status or len(disks_status) != len(disks):
            logging.info("Failed to get disks status by 'multipath -ll'")
            return {}
        else:
            return disks_status

    def compare_onepath_status(status, disk):
        """
        Compare status whether equal to the given status.
        This function just focus on all paths are running or all are offline.

        :param status: the state of disks.
        :param disk: disk kname.
        :return: True, if equal to the given status or False
        """
        status_dict = get_multipath_disks_status(mpath_name)
        logging.debug("compare_onepath_status disk:", disk, status_dict,
                      status)
        if disk in status_dict.keys() and status == status_dict[disk]:
            return True
        else:
            return False

    def compare_multipath_status(status, mpath_name="mpatha"):
        """
        Compare status whether equal to the given status.
        This function just focus on all paths are running or all are offline.

        :param status: the state of disks.
        :param mpath_name: multi-path name.
        :return: True, if equal to the given status or False
        """
        status_dict = get_multipath_disks_status(mpath_name)
        logging.debug("compare_multipath_status mpath_name:", mpath_name,
                      status_dict, status)
        if len(set(
                status_dict.values())) == 1 and status in status_dict.values():
            return True
        else:
            return False

    def set_disk_status_to_online_offline(disk, status):
        """
        set disk state to online/offline.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16 failed faulty offline

        :param disk: disk name.
        :param status: the state of disk.
        :return: by default
        """
        error_context.context("Set disk '%s' to status '%s'." % (disk, status),
                              logging.info)
        process.run("echo %s >  /sys/block/%s/device/state" % (status, disk),
                    shell=True)

    def set_multipath_disks_status(disks, status):
        """
        set multiple paths to same status. all disks online or offline.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16 failed faulty offline

        :param disks: disk list.
        :param status: the state of disk. online/offline
        :return: by default
        """
        for disk in disks:
            set_disk_status_to_online_offline(disk, status)
            time.sleep(2)
        if len(disks) == 1:
            wait.wait_for(lambda: compare_onepath_status(status, disks[0]),
                          first=wait_time,
                          step=3,
                          timeout=60)
        else:
            wait.wait_for(lambda: compare_multipath_status(status),
                          first=wait_time,
                          step=3,
                          timeout=60)

    def get_lvm_dm_name(blkdevs_used):
        """
        Get dm name for lvm. such as rhel_ibm--x3650m4--05-root in below
        NAME                           MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINT
        sda                              8:0    0 278.9G  0 disk
        ├─sda1                           8:1    0     1G  0 part  /boot
        └─sda2                           8:2    0 277.9G  0 part
            ├─rhel_ibm--x3650m4--05-root 253:0    0    50G  0 lvm   /
            ├─rhel_ibm--x3650m4--05-swap 253:1    0  15.7G  0 lvm   [SWAP]
            └─rhel_ibm--x3650m4--05-home 253:2    0 212.2G  0 lvm   /home
        # ls /dev/mapper/* -l
        crw-------. 1 root root 10, 236 Oct 25 02:07 /dev/mapper/control
        lrwxrwxrwx. 1 root root       7 Oct 25 09:26 /dev/mapper/mpatha -> ../dm-3
        lrwxrwxrwx. 1 root root       7 Oct 25 09:26 /dev/mapper/mpatha1 -> ../dm-5
        lrwxrwxrwx. 1 root root       7 Oct 25 09:26 /dev/mapper/mpatha2 -> ../dm-6
        lrwxrwxrwx. 1 root root       7 Oct 25 06:49 /dev/mapper/mpathb -> ../dm-4
        lrwxrwxrwx. 1 root root       7 Oct 25 09:17 /dev/mapper/rhel_bootp--73--199--5-home -> ../dm-8
        lrwxrwxrwx. 1 root root       7 Oct 25 09:17 /dev/mapper/rhel_bootp--73--199--5-root -> ../dm-9
        lrwxrwxrwx. 1 root root       7 Oct 25 09:17 /dev/mapper/rhel_bootp--73--199--5-swap -> ../dm-7
        lrwxrwxrwx. 1 root root       7 Oct 25 02:07 /dev/mapper/rhel_ibm--x3650m4--05-home -> ../dm-2
        lrwxrwxrwx. 1 root root       7 Oct 25 02:07 /dev/mapper/rhel_ibm--x3650m4--05-root -> ../dm-0
        lrwxrwxrwx. 1 root root       7 Oct 25 02:07 /dev/mapper/rhel_ibm--x3650m4--05-swap -> ../dm-1
        -rw-r--r--. 1 root root       0 Oct 25 07:52 /dev/mapper/vg_raid10-lv_home
        # dmsetup info -c -o name,blkdevs_used
        Name                        BlkDevNamesUsed
        rhel_bootp--73--199--5-home dm-6
        mpathb                      sdd,sde
        mpatha                      sdb,sdc
        mpatha2                     dm-3
        rhel_bootp--73--199--5-swap dm-6
        rhel_bootp--73--199--5-root dm-6
        mpatha1                     dm-3
        rhel_ibm--x3650m4--05-home  sda2
        rhel_ibm--x3650m4--05-swap  sda2
        rhel_ibm--x3650m4--05-root  sda2

        :param blkdevs_used: block name, e.g. sda2
        :return: a list contains all dm name for one blkdev
        """
        dm_list = []
        logging.info("Get dm name for '%s'" % blkdevs_used)
        output = process.run("ls /dev/mapper/* -l", shell=True).stdout.decode()
        for line in output.splitlines():
            if blkdevs_used in line:
                dm_name = line.split("/")[-1]
                break
        output = process.run("dmsetup info -c -o name,blkdevs_used",
                             shell=True).stdout.decode()
        for line in output.splitlines():
            if dm_name == line.split()[-1]:
                dm_list.append(line.split()[0])
        return dm_list

    def delete_lvm_on_multipath(mpath_name="mpatha"):
        """
        Delete lvm on the given multipath.

        :param mpath_name: multi-path name.
        :return: by default.
        """
        output = process.run("pvscan", shell=True).stdout.decode()
        pv_list = []
        vg_list = []
        lv_list = []
        for line in output.splitlines():
            if mpath_name in line:
                if line.split()[1] not in pv_list:
                    pv_list.append(line.split()[1])
                if line.split()[3] not in vg_list:
                    vg_list.append(line.split()[3])
        output = process.run("lvscan", shell=True).stdout.decode()
        for line in output.splitlines():
            for vg in vg_list:
                lv = "/dev/%s/" % vg
                if lv in line and line.split("'")[1] not in lv_list:
                    lv_list.append(line.split("'")[1])
        logging.info("pv list: %s" % pv_list)
        logging.info("vg list: %s" % vg_list)
        logging.info("lv list: %s" % lv_list)
        for lv in lv_list:
            logging.info("Remove lvm '%s'." % lv)
            process.run("lvremove -y %s" % lv, ignore_status=True, shell=True)
        for vg in vg_list:
            logging.info("Remove vg '%s'." % vg)
            process.run("vgremove -y %s" % vg, ignore_status=True, shell=True)
        for pv in pv_list:
            pv_name = pv.split("/")[-1]
            for dm in get_lvm_dm_name(pv_name):
                process.run("dmsetup remove %s" % dm,
                            ignore_status=True,
                            shell=True)
            logging.info("Remove pv '%s'." % pv)
            process.run("pvremove -y %s" % pv, ignore_status=True, shell=True)

    def delete_partition_on_host(did):
        """
        Delete partitions on the given disk.

        :param did: disk ID. disk kname. e.g. 'sdb', 'nvme0n1'
        :return: by default.
        """
        # process.run("partprobe /dev/%s" % did, shell=True)
        list_disk_cmd = "lsblk -o KNAME,MOUNTPOINT"
        output = process.run(list_disk_cmd, shell=True).stdout.decode()
        regex_str = did + "\w*(\d+)"
        rm_cmd = 'parted -s "/dev/%s" rm %s'
        for line in output.splitlines():
            partition = re.findall(regex_str, line, re.I | re.M)
            if partition:
                if "/" in line.split()[-1]:
                    process.run("umount %s" % line.split()[-1], shell=True)
        list_partition_number = "parted -s /dev/%s print|awk '/^ / {print $1}'"
        partition_numbers = process.run(list_partition_number % did,
                                        ignore_status=True,
                                        shell=True).stdout.decode()
        ignore_err_msg = "unrecognised disk label"
        if ignore_err_msg in partition_numbers:
            logging.info("no partition to delete on %s" % did)
        else:
            partition_numbers = partition_numbers.splitlines()
            for number in partition_numbers:
                logging.info("remove partition %s on %s" % (number, did))
                process.run(rm_cmd % (did, number),
                            ignore_status=True,
                            shell=True)
            process.run("partprobe /dev/%s" % did, shell=True)

    def delete_multipath_partition_on_host(mpath_name="mpatha"):
        """
        Delete partitions on the given multipath.

        :param mpath_name: multi-path name.
        :return: by default.
        """
        # process.run("partprobe /dev/mapper/%s" % mpath_name, shell=True)
        output = process.run("lsblk", shell=True).stdout.decode()
        mpath_dict = {}
        pattern = r'%s(\d+)' % mpath_name
        rm_cmd = 'parted -s "/dev/mapper/%s" rm %s'
        for line in output.splitlines():
            for part_num in re.findall(pattern, line, re.I | re.M):
                if part_num not in mpath_dict.keys():
                    mpath_dict[part_num] = line.split()[-1]
        for key, value in mpath_dict.items():
            if "/" in value:
                process.run("umount %s" % value, shell=True)
            logging.info("remove partition %s on %s" % (key, mpath_name))
            process.run(rm_cmd % (mpath_name, key),
                        ignore_status=True,
                        shell=True)
        output = process.run("dmsetup ls", shell=True).stdout.decode()
        for line in output.splitlines():
            for key in mpath_dict.keys():
                if (mpath_name + key) in line:
                    process.run("dmsetup remove %s%s" % (mpath_name, key),
                                ignore_status=True,
                                shell=True)
        process.run("partprobe /dev/mapper/%s" % mpath_name, shell=True)

    def clean_partition_on_host(mpath_name="mpatha"):
        """
        Delete partitions on multi-path disks.

        :param mpath_name: multi-path name.
        :return: by default
        """
        delete_multipath_partition_on_host(mpath_name)
        disks = get_multipath_disks(mpath_name)
        for disk in disks:
            delete_partition_on_host(disk)

    def _run_fio_background(session, filename):
        """run fio testing by thread"""

        logging.info("Start fio in background.")
        cmd = fio_multipath.cfg.fio_path + params['fio_options'] % filename
        logging.info(cmd)
        session.cmdline(cmd)
        # args = (params['fio_options'] % filename, 3600)
        # fio_thread = utils_misc.InterruptedThread(fio_multipath.run, args)
        # fio_thread.start()
        # if not utils_misc.wait_for(lambda: fio_thread.is_alive, 60):
        #     test.fail("Failed to start fio thread.")
        # return fio_thread

    # def _run_fio_background(filename):
    #     """run fio testing by thread"""
    #
    #     logging.info("Start fio in background.")
    #     args = (params['fio_options'] % filename, 3600)
    #     fio_thread = utils_misc.InterruptedThread(fio_multipath.run, args)
    #     fio_thread.start()
    #     if not utils_misc.wait_for(lambda: fio_thread.is_alive, 60):
    #         test.fail("Failed to start fio thread.")
    #     return fio_thread

    def _get_windows_disks_index(session, image_size):
        """
        Get all disks index which show in 'diskpart list disk'.
        except for system disk.
        in diskpart: if disk size < 8GB: it displays as MB
                     else: it displays as GB

        :param session: session object to guest.
        :param image_size: image size. e.g. 40M
        :return: a list with all disks index except for system disk.
        """
        disk = "disk_" + ''.join(
            random.sample(string.ascii_letters + string.digits, 4))
        disk_indexs = []
        list_disk_cmd = "echo list disk > " + disk
        list_disk_cmd += " && echo exit >> " + disk
        list_disk_cmd += " && diskpart /s " + disk
        list_disk_cmd += " && del /f " + disk
        disks = session.cmd_output(list_disk_cmd)
        size_type = image_size[-1] + "B"
        if size_type == "MB":
            disk_size = image_size[:-1] + " MB"
        elif size_type == "GB" and int(image_size[:-1]) < 8:
            disk_size = str(int(image_size[:-1]) * 1024) + " MB"
        else:
            disk_size = image_size[:-1] + " GB"
        regex_str = 'Disk (\d+).*?%s' % disk_size
        for disk in disks.splitlines():
            if disk.startswith("  Disk"):
                o = re.findall(regex_str, disk, re.I | re.M)
                if o:
                    disk_indexs.append(o[0])
        return disk_indexs

    def resume_vm_plus(vm, timeout=120):
        """resume vm when it is paused.

        :param vm: VM object.
        :param timeout: re-try times, if it is still paused after resume
        :return: True or None.
                 If resume successfully return True or return None
        """
        logging.info("Try to resume vm within %s seconds." % timeout)
        try:
            vm_status = vm.resume(timeout=timeout)
        except Exception as e:
            logging.error("Failed to resume vm: %s" % six.text_type(e))
        return vm_status

    def resume_vm(vm, n_repeat=2):
        """resume vm when it is paused.

        :param vm: VM object.
        :param n_repeat: re-try times, if it is still paused after resume
        :return: True or False.
                 If resume successfully return True or return False
        """
        for i in range(1, n_repeat + 1):
            logging.info("Try to resume vm %s time(s)" % i)
            try:
                vm.resume()
                time.sleep(wait_time * 15)
            except Exception as e:
                logging.error("Failed to resume vm: %s" % six.text_type(e))
            finally:
                if check_vm_status(vm, "running"):
                    return True
                if vm.is_paused() and i == 3:
                    return False

    error_context.context("Get FC host name:", logging.info)
    hostname = process.run("hostname", shell=True).stdout.decode().strip()
    if hostname != params["special_host"]:
        test.cancel("The special host is not '%s', cancel the test." %
                    params["special_host"])
    error_context.context("Get FC disk serial name:", logging.info)
    outputs = process.run("multipath -ll",
                          shell=True).stdout.decode().splitlines()
    stg_serial_name = params["stg_serial_name"]
    image_name_stg = params["image_name_stg"]
    mpath_name = image_name_stg.split("/")[-1]
    for output in outputs:
        if stg_serial_name in output and mpath_name in output:
            break
    else:
        test.cancel("The special disk is not '%s', cancel the test." %
                    stg_serial_name)
    wait_time = float(params.get("sub_test_wait_time", 0))
    repeat_times = int(params.get("repeat_times", 2))
    multi_disks = get_multipath_disks(mpath_name)
    error_context.context(
        "Get all disks for '%s': %s" % (mpath_name, multi_disks), logging.info)
    error_context.context(
        "Verify all paths are running for %s before"
        "start vm." % mpath_name, logging.info)
    if compare_multipath_status("running", mpath_name):
        logging.info("All paths are running for %s." % mpath_name)
    else:
        logging.info("Not all paths are running for %s, set "
                     "them to running." % mpath_name)
        set_multipath_disks_status(multi_disks, "running")
    error_context.context(
        "Delete lvm on multipath disks on host "
        "before testing.", logging.info)
    delete_lvm_on_multipath(mpath_name)
    error_context.context("Delete partitions on host before testing.",
                          logging.info)
    clean_partition_on_host(mpath_name)
    vm = env.get_vm(params["main_vm"])
    try:
        if params.get("need_install") == "yes":
            error_context.context("Install guest on passthrough disk:",
                                  logging.info)
            args = (test, params, env)
            bg = utils_misc.InterruptedThread(
                utils_test.run_virt_sub_test, args,
                {"sub_type": "unattended_install"})
            bg.start()
            utils_misc.wait_for(bg.is_alive, timeout=10)
            time.sleep(random.uniform(60, 180))
        else:
            vm.create(params=params)
            session = vm.wait_for_login(
                timeout=int(params.get("timeout", 240)))
            fio_multipath = generate_instance(params, vm, 'fio')
            image_size_stg = params["image_size_stg"]
            image_num_stg = int(params["image_num_stg"])
            os_type = params["os_type"]
    except Exception as e:
        test.error("failed to create VM: %s" % six.text_type(e))
    try:
        error_context.context("Make sure guest is running before test",
                              logging.info)
        if vm.is_paused():
            vm.resume()
        vm.verify_status("running")
        if "fio_multipath" in locals().keys():
            if os_type == "windows":
                error_context.context(
                    "Get windows disk index that to "
                    "be formatted", logging.info)
                disks = _get_windows_disks_index(session, image_size_stg)
                if len(disks) != image_num_stg:
                    test.fail(
                        "Failed to list all disks by image size. The expected "
                        "is %s, actual is %s" % (image_num_stg, len(disks)))
                error_context.context(
                    "Clear readonly for all disks and online "
                    "them in windows guest.", logging.info)
                if not utils_disk.update_windows_disk_attributes(
                        session, disks):
                    test.fail("Failed to update windows disk attributes.")
            else:
                error_context.context("Get linux disk that to be "
                                      "formatted", logging.info)
                disks = sorted(utils_disk.get_linux_disks(session).keys())
                if len(disks) != image_num_stg:
                    test.fail(
                        "Failed to list all disks by image size. The expected "
                        "is %s, actual is %s" % (image_num_stg, len(disks)))
            file_system = [_.strip() for _ in params["file_system"].split()]
            labeltype = params.get("labeltype", "gpt")
            for n, disk in enumerate(disks):
                error_context.context("Format disk in guest: '%s'" % disk,
                                      logging.info)
                # Random select one file system from file_system
                index = random.randint(0, (len(file_system) - 1))
                fstype = file_system[index].strip()
                partitions = utils_disk.configure_empty_disk(
                    session,
                    disk,
                    image_size_stg,
                    os_type,
                    fstype=fstype,
                    labeltype=labeltype)
                if not partitions:
                    test.fail("Fail to format disks.")
            fio_file_name = params["fio_file_name"] % partitions[0]
            # fio_thread = _run_fio_background(fio_file_name)
            _run_fio_background(session, fio_file_name)
        # disk = random.sample(multi_disks, 1)
        for disk in multi_disks:
            error_context.context(
                "Disable disk %s during guest running" % disk, logging.info)
            set_multipath_disks_status([disk], "offline")
            time.sleep(wait_time * 15)
            if vm.is_paused():
                logging.info("vm is paused, will resume it.")
                if not resume_vm(vm, repeat_times):
                    test.fail("Failed to resume guest after disable one disk")
                logging.info("Has resumed vm already. Then verify it running.")
                if not utils_misc.wait_for(
                        lambda: check_vm_status(vm, "running"), 60):
                    test.fail("Guest is not running after disable one disk")
            error_context.context("Enable disk %s during guest running" % disk,
                                  logging.info)
            set_multipath_disks_status([disk], "running")
            time.sleep(wait_time * 15)
        error_context.context(
            "Disable multipath '%s' during guest "
            "running." % mpath_name, logging.info)
        set_multipath_disks_status(multi_disks, "offline")
        time.sleep(wait_time * 15)
        error_context.context("Check if VM status is 'paused'", logging.info)
        if not utils_misc.wait_for(lambda: check_vm_status(vm, "paused"), 120):
            test.fail("Guest is not paused after all disks offline")
        error_context.context(
            "Re-connect fc storage, wait until the "
            "storage is accessible again", logging.info)
        set_multipath_disks_status(multi_disks, "running")
        time.sleep(wait_time * 15)
        error_context.context("vm is paused, resume it.", logging.info)
        if not resume_vm(vm, repeat_times):
            test.fail("Failed to resume guest after enable multipath.")
        logging.info("Has resumed vm already. Then verify it running.")
        time.sleep(wait_time * 15)
        error_context.context("Check if VM status is 'running'", logging.info)
        if not utils_misc.wait_for(lambda: check_vm_status(vm, "running"),
                                   120):
            test.fail("Guest is not running after all disks online")
        if "bg" in locals().keys() and bg.is_alive and not vm.is_paused():
            bg.join()
        # wq comment ,why need wait fio
        # if "fio_thread" in locals().keys() and fio_thread.is_alive \
        #         and not vm.is_paused():
        #     fio_thread.join()
        error_context.context(
            "Verify Host and guest kernel no error "
            "and call trace", logging.info)
        vm.verify_kernel_crash()
    # except Exception as e:
    #     logging.error(e)
    finally:
        logging.info("Finally, clean environment.")
Ejemplo n.º 20
0
def run(test, params, env):
    """
    Test usb redirection

    1) Check host configurations
    2) Start usbredirserver on host (optional)
    3) Preprocess VM
    4) Start USB redirection via spice (optional)
    5) Check the boot menu list (optional)
    6) Check the redirected USB device in guest

    :param test: QEMU test object
    :param params: Dictionary with test parameters
    :param env: Dictionary with test environment.
    """
    def _start_usbredir_server():
        process.getoutput("killall usbredirserver")
        usbredir_server = utils_misc.get_binary('usbredirserver', params)
        usbredirserver_args = usbredir_server + " -p %s " % free_port
        usbredirserver_args += " %s:%s" % (vendorid, productid)
        usbredirserver_args += " > /dev/null 2>&1"
        rv_thread = utils_misc.InterruptedThread(os.system,
                                                 (usbredirserver_args, ))
        rv_thread.start()

    def create_repo():
        logging.info("Create temp repository")
        version_cmd = 'grep "^VERSION_ID=" /etc/os-release | cut -d = -f2'
        version_id = process.getoutput(version_cmd).strip('"')
        major, minor = version_id.split('.')
        baseurl = params["temprepo_url"]
        baseurl = baseurl.replace("MAJOR", major)
        content = "[temp]\nname=temp\nbaseurl=%s\nenable=1\n" % baseurl
        content += "gpgcheck=0\nskip_if_unavailable=1"
        create_cmd = r'echo -e "%s" > /etc/yum.repos.d/temp.repo' % content
        process.system(create_cmd, shell=True)

    def _host_config_check():
        status = True
        err_msg = ''
        if option == "with_negative_config":
            out = process.getoutput("dmesg")
            pattern = r"usb (\d-\d(?:.\d)?):.*idVendor=%s, idProduct=%s"
            pattern = pattern % (vendorid, productid)
            obj = re.search(pattern, out, re.ASCII)
            if not obj:
                status = False
                err_msg = "Fail to get the USB device info in host dmesg"
                return (status, err_msg)
            error_context.context("Make USB device unconfigured", logging.info)
            unconfig_value = params["usbredir_unconfigured_value"]
            cmd = "echo %s > /sys/bus/usb/devices/%s/bConfigurationValue"
            cmd = cmd % (unconfig_value, obj.group(1))
            logging.info(cmd)
            s, o = process.getstatusoutput(cmd)
            if s:
                status = False
                err_msg = "Fail to unconfig the USB device, output: %s" % o
                return (status, err_msg)

        if backend == 'spicevmc':
            gui_group = "Server with GUI"
            out = process.getoutput('yum group list --installed',
                                    allow_output_check='stdout',
                                    shell=True)
            obj = re.search(r"(Installed Environment Groups:.*?)^\S", out,
                            re.S | re.M)
            if not obj or gui_group not in obj.group(1):
                gui_groupinstall_cmd = "yum groupinstall -y '%s'" % gui_group
                s, o = process.getstatusoutput(gui_groupinstall_cmd,
                                               shell=True)
                if s:
                    status = False
                    err_msg = "Fail to install '%s' on host, " % gui_group
                    err_msg += "output: %s" % o
                    return (status, err_msg)
            virt_viewer_cmd = "rpm -q virt-viewer || yum install -y virt-viewer"
            s, o = process.getstatusoutput(virt_viewer_cmd, shell=True)
            if s:
                status = False
                err_msg = "Fail to install 'virt-viewer' on host, "
                err_msg += "output: %s" % o
                return (status, err_msg)
        elif backend == 'tcp_socket':
            create_repo()
            if not utils_package.package_install("usbredir-server"):
                status = False
                err_msg = "Fail to install 'usbredir-server' on host"
                return (status, err_msg)
        return (status, err_msg)

    def _usbredir_preprocess():
        def _generate_usb_redir_cmdline():
            extra_params = ''
            _backend = 'socket' if 'socket' in backend else backend
            chardev_id = usbredir_params.get("chardev_id",
                                             "chardev_%s" % usbredirdev_name)
            chardev_params = Params({'backend': _backend, 'id': chardev_id})
            if backend == 'spicevmc':
                chardev_params['debug'] = usbredir_params.get('chardev_debug')
                chardev_params['name'] = usbredir_params.get('chardev_name')
            else:
                chardev_params['host'] = usbredir_params['chardev_host']
                chardev_params['port'] = free_port
                chardev_params['server'] = usbredir_params.get(
                    'chardev_server')
                chardev_params['wait'] = usbredir_params.get('chardev_wait')
            chardev = qdevices.CharDevice(chardev_params, chardev_id)
            usbredir_dev = qdevices.QDevice('usb-redir',
                                            aobject=usbredirdev_name)
            usbredir_filter = usbredir_params.get("usbdev_option_filter")
            usbredir_bootindex = usbredir_params.get("usbdev_option_bootindex")
            usbredir_bus = usbredir_params.get("usb_bus")
            usbredir_dev.set_param('id', 'usb-%s' % usbredirdev_name)
            usbredir_dev.set_param('chardev', chardev_id)
            usbredir_dev.set_param('filter', usbredir_filter)
            usbredir_dev.set_param('bootindex', usbredir_bootindex)
            usbredir_dev.set_param('bus', usbredir_bus)
            extra_params += ' '.join(
                [chardev.cmdline(), usbredir_dev.cmdline()])
            return extra_params

        extra_params = _generate_usb_redir_cmdline()
        params["extra_params"] = extra_params
        if backend == 'spicevmc':
            params["paused_after_start_vm"] = "yes"
            del params["spice_password"]
            del params["spice_addr"]
            del params["spice_image_compression"]
            del params["spice_zlib_glz_wan_compression"]
            del params["spice_streaming_video"]
            del params["spice_agent_mouse"]
            del params["spice_playback_compression"]
            del params["spice_ipv4"]
        params["start_vm"] = "yes"
        env_process.preprocess_vm(test, params, env, params["main_vm"])

    def _start_spice_redirection():
        def _rv_connection_check():
            rv_pid = process.getoutput("pidof %s" % rv_binary)
            spice_port = vm.get_spice_var('spice_port')
            cmd = 'netstat -ptn | grep "^tcp.*127.0.0.1:%s.*ESTABLISHED %s.*"'
            cmd = cmd % (spice_port, rv_pid)
            s, o = process.getstatusoutput(cmd)
            if s:
                return False
            logging.info("netstat output:\n%s", o)
            return True

        status = True
        err_msg = ''
        rv_binary_path = utils_misc.get_binary(rv_binary, params)
        spice_port = vm.get_spice_var('spice_port')
        rv_args = rv_binary_path + " spice://localhost:%s " % spice_port
        rv_args += "--spice-usbredir-redirect-on-connect="
        rv_args += "'-1,0x%s,0x%s,-1,1'" % (vendorid, productid)
        rv_args += " > /dev/null 2>&1"
        rv_thread = utils_misc.InterruptedThread(os.system, (rv_args, ))
        rv_thread.start()
        if not utils_misc.wait_for(_rv_connection_check, timeout, 60):
            status = False
            err_msg = "Fail to establish %s connection" % rv_binary
        return (status, err_msg)

    def boot_check(info):
        """
        boot info check
        """
        return re.search(info, vm.serial_console.get_stripped_output())

    def _usb_dev_verify():
        error_context.context("Check USB device in guest", logging.info)
        if session.cmd_status(lsusb_cmd):
            return False
        return True

    def _kill_rv_proc():
        s, o = process.getstatusoutput("pidof %s" % rv_binary)
        if not s:
            process.getoutput("killall %s" % rv_binary)

    def _get_usb_mount_point():
        """ Get redirected USB stick mount point """
        dmesg_cmd = "dmesg | grep 'Attached SCSI removable disk'"
        s, o = session.cmd_status_output(dmesg_cmd)
        if s:
            test.error("Fail to get redirected USB stick in guest.")
        dev = re.findall(r'\[(sd\w+)\]', o)[0]
        mounts_cmd = "cat /proc/mounts | grep /dev/%s" % dev
        s, o = session.cmd_status_output(mounts_cmd)
        if s:
            s, o = session.cmd_status_output('mount /dev/%s /mnt' % dev)
            if s:
                test.error("Fail to mount /dev/%s, output: %s" % (dev, o))
            mp = "/mnt"
        else:
            mp = re.findall(r'/dev/%s\d*\s+(\S+)\s+' % dev, o)[0]
        return mp

    def _usb_stick_io(mount_point):
        """
        Do I/O operations on passthrough USB stick
        """
        error_context.context("Read and write on USB stick ", logging.info)
        testfile = os.path.join(mount_point, 'testfile')
        iozone_cmd = params.get("iozone_cmd",
                                " -a -I -r 64k -s 1m -i 0 -i 1 -f %s")
        iozone_test.run(iozone_cmd % testfile)

    usbredirdev_name = params["usbredirdev_name"]
    usbredir_params = params.object_params(usbredirdev_name)
    backend = usbredir_params.get('chardev_backend', 'spicevmc')
    if backend not in ('spicevmc', 'tcp_socket'):
        test.error("Unsupported char device backend type: %s" % backend)

    if backend == 'spicevmc' and params.get('display') != 'spice':
        test.cancel("Only support spice connection")

    option = params.get("option")
    vendorid = params["usbredir_vendorid"]
    productid = params["usbredir_productid"]
    timeout = params.get("wait_timeout", 600)
    lsusb_cmd = "lsusb -v -d %s:%s" % (vendorid, productid)
    usb_stick = "Mass Storage" in process.getoutput(lsusb_cmd)
    rv_binary = params.get('rv_binary', 'remote-viewer')

    error_context.context("Check host configurations", logging.info)
    s, o = _host_config_check()
    if not s:
        test.error(o)

    if backend == 'tcp_socket':
        free_port = utils_misc.find_free_port()
        _start_usbredir_server()

    error_context.context("Preprocess VM", logging.info)
    _usbredir_preprocess()
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    if backend == 'spicevmc':
        error_context.context("Start USB redirection via spice", logging.info)
        s, o = _start_spice_redirection()
        if not s:
            test.error(o)
        vm.resume()

    if option == "with_bootindex":
        error_context.context("Check 'bootindex' option", logging.info)
        boot_menu_hint = params["boot_menu_hint"]
        boot_menu_key = params["boot_menu_key"]
        if not utils_misc.wait_for(lambda: boot_check(boot_menu_hint), timeout,
                                   1):
            test.fail("Could not get boot menu message")

        # Send boot menu key in monitor.
        vm.send_key(boot_menu_key)

        output = vm.serial_console.get_stripped_output()
        boot_list = re.findall(r"^\d+\. (.*)\s", output, re.M)
        if not boot_list:
            test.fail("Could not get boot entries list")
        logging.info("Got boot menu entries: '%s'", boot_list)

        bootindex = int(params["usbdev_option_bootindex_%s" %
                               usbredirdev_name])
        if "USB" not in boot_list[bootindex]:
            test.fail("'bootindex' option of usb-redir doesn't take effect")

        if usb_stick:
            error_context.context("Boot from redirected USB stick",
                                  logging.info)
            boot_entry_info = params["boot_entry_info"]
            vm.send_key(str(bootindex + 1))
            if not utils_misc.wait_for(lambda: boot_check(boot_entry_info),
                                       timeout, 1):
                test.fail("Could not boot from redirected USB stick")
        return

    error_context.context("Login to guest", logging.info)
    session = vm.wait_for_login()

    if params.get("policy") == "deny":
        if _usb_dev_verify():
            error_msg = "Redirected USB device can be found in guest"
            error_msg += " while policy is deny"
            test.fail(error_msg)
        if backend == 'spicevmc':
            _kill_rv_proc()
        return

    if not _usb_dev_verify():
        if backend == 'tcp_socket':
            process.system("killall usbredirserver", ignore_status=True)
        test.fail("Can not find the redirected USB device in guest")

    if usb_stick:
        iozone_test = None
        try:
            mount_point = _get_usb_mount_point()
            iozone_test = generate_instance(params, vm, 'iozone')
            _usb_stick_io(mount_point)
        finally:
            if iozone_test:
                iozone_test.clean()

    if backend == 'tcp_socket':
        process.system("killall usbredirserver", ignore_status=True)

    session.close()
Ejemplo n.º 21
0
 def _io_stress_windows(target):
     fio = generate_instance(params, vm, 'fio')
     try:
         fio.run(params['fio_opts'] % target)
     finally:
         fio.clean()
Ejemplo n.º 22
0
def run(test, params, env):
    """
    Run IOzone for linux on a linux guest:
    1) Log into a guest.
    2) Execute the IOzone test.
    :param test: kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def _get_data_disks():
        """ Get the data disks by serial or wwn options. """
        disks = {}
        for data_image in params["images"].split()[1:]:
            extra_params = params.get("blk_extra_params_%s" % data_image, '')
            match = re.search(r"(serial|wwn)=(\w+)", extra_params, re.M)
            if match:
                drive_id = match.group(2)
            else:
                continue
            drive_path = utils_misc.get_linux_drive_path(session, drive_id)
            if not drive_path:
                test.error("Failed to get '%s' drive path" % data_image)
            disks[drive_path[5:]] = data_image
        return disks

    def _get_mounted_points():
        """ Get the mounted points. """
        points = []
        for id in re.finditer(r'(%s\d+)' % did, ' '.join(disks)):
            s = re.search(r'/dev/%s\s+(\S+)\s+' % id.group(1), mount_info,
                          re.M)
            if s:
                points.append(s.group(1))
        return points

    def _wait_for_procs_done(timeout=1800):
        """ Wait all the processes are done. """
        if not utils_misc.wait_for(
                lambda: 'iozone' not in session.cmd_output('pgrep -xl iozone'),
                timeout,
                step=3.0):
            test.error('Not all iozone processes done in %s sec.' % timeout)

    iozone_test_dir = params.get('iozone_test_dir', '/home')
    iozone_cmd_options = params['iozone_cmd_options']
    iozone_timeout = float(params.get("iozone_timeout", 1800))
    n_partitions = params.get('partitions_num', 1)
    fstype = params.get('fstype', 'xfs')
    labeltype = params.get('labeltype', utils_disk.PARTITION_TABLE_TYPE_GPT)

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(
        timeout=float(params.get("login_timeout", 360)))
    _wait_for_procs_done()
    error_context.context("Running IOzone command on guest.")
    iozone = generate_instance(params, vm, 'iozone')
    try:
        dids = _get_data_disks()
        if dids:
            mount_info = session.cmd_output_safe(
                'cat /proc/mounts | grep \'/dev/\'')
            disks = utils_disk.get_linux_disks(session, True)
            for did, image_name in dids.items():
                size = params.get('image_size_%s' % image_name)
                start = params.get('image_start_%s' % image_name, "0M")
                mounted_points = _get_mounted_points()
                if not mounted_points:
                    mounted_points = utils_disk.configure_empty_linux_disk(
                        session, did, size, start, n_partitions, fstype,
                        labeltype)
                for mounted_point in mounted_points:
                    iozone.run(iozone_cmd_options % mounted_point,
                               iozone_timeout)
                utils_disk.clean_partition_linux(session, did)
        else:
            iozone.run(iozone_cmd_options % iozone_test_dir, iozone_timeout)
    finally:
        if params.get('sub_test_shutdown_vm', 'no') == 'no':
            iozone.clean()
        session.close()
Ejemplo n.º 23
0
def run(test, params, env):
    """
    Test virtio-fs by sharing the data between host and guest.
    Steps:
        1. Create shared directories on the host.
        2. Run virtiofsd daemons on the host.
        3. Boot a guest on the host with virtiofs options.
        4. Log into guest then mount the virtiofs targets.
        5. Generate files or run stress on the mount points inside guest.

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    def get_viofs_exe(session):
        """
        Get viofs.exe from virtio win iso,such as E:\viofs\2k19\amd64
        """
        logging.info("Get virtiofs exe full path.")
        media_type = params["virtio_win_media_type"]
        try:
            get_drive_letter = getattr(virtio_win, "drive_letter_%s" % media_type)
            get_product_dirname = getattr(virtio_win,
                                          "product_dirname_%s" % media_type)
            get_arch_dirname = getattr(virtio_win, "arch_dirname_%s" % media_type)
        except AttributeError:
            test.error("Not supported virtio win media type '%s'", media_type)
        viowin_ltr = get_drive_letter(session)
        if not viowin_ltr:
            test.error("Could not find virtio-win drive in guest")
        guest_name = get_product_dirname(session)
        if not guest_name:
            test.error("Could not get product dirname of the vm")
        guest_arch = get_arch_dirname(session)
        if not guest_arch:
            test.error("Could not get architecture dirname of the vm")

        exe_middle_path = ("{name}\\{arch}" if media_type == "iso"
                           else "{arch}\\{name}").format(name=guest_name,
                                                         arch=guest_arch)
        exe_file_name = "virtiofs.exe"
        exe_find_cmd = 'dir /b /s %s\\%s | findstr "\\%s\\\\"'
        exe_find_cmd %= (viowin_ltr, exe_file_name, exe_middle_path)
        exe_path = session.cmd(exe_find_cmd).strip()
        logging.info("Found exe file '%s'", exe_path)
        return exe_path

    # data io config
    cmd_dd = params.get('cmd_dd')
    cmd_md5 = params.get('cmd_md5')
    cmd_new_folder = params.get('cmd_new_folder')
    cmd_copy_file = params.get('cmd_copy_file')
    cmd_del_folder = params.get('cmd_del_folder')

    # pjdfs test config
    cmd_pjdfstest = params.get('cmd_pjdfstest')
    cmd_unpack = params.get('cmd_unpack')
    cmd_yum_deps = params.get('cmd_yum_deps')
    cmd_autoreconf = params.get('cmd_autoreconf')
    cmd_configure = params.get('cmd_configure')
    cmd_make = params.get('cmd_make')
    pjdfstest_pkg = params.get('pjdfstest_pkg')
    username = params.get('username')
    password = params.get('password')
    port = params.get('file_transfer_port')

    # fio config
    fio_options = params.get('fio_options')
    io_timeout = params.get_numeric('io_timeout')

    # xfstest config
    cmd_xfstest = params.get('cmd_xfstest')
    fs_dest_fs2 = params.get('fs_dest_fs2')
    cmd_download_xfstest = params.get('cmd_download_xfstest')
    cmd_yum_install = params.get('cmd_yum_install')
    cmd_make_xfs = params.get('cmd_make_xfs')
    cmd_setenv = params.get('cmd_setenv')
    cmd_setenv_nfs = params.get('cmd_setenv_nfs', '')
    cmd_useradd = params.get('cmd_useradd')
    fs_dest_fs1 = params.get('fs_dest_fs1')
    cmd_get_tmpfs = params.get('cmd_get_tmpfs')
    cmd_set_tmpfs = params.get('cmd_set_tmpfs')
    size_mem1 = params.get('size_mem1')

    # xfstest-nfs config
    setup_local_nfs = params.get('setup_local_nfs')

    if cmd_xfstest:
        # /dev/shm is the default memory-backend-file, the default value is the
        # half of the host memory. Increase it to guest memory size to avoid crash
        ori_tmpfs_size = process.run(cmd_get_tmpfs, shell=True).stdout_text.replace("\n", "")
        logging.debug("original tmpfs size is %s", ori_tmpfs_size)
        params["post_command"] = cmd_set_tmpfs % ori_tmpfs_size
        params["pre_command"] = cmd_set_tmpfs % size_mem1
        if setup_local_nfs:
            for fs in params.objects("filesystems"):
                nfs_params = params.object_params(fs)
                params["export_dir"] = nfs_params.get("export_dir")
                params["nfs_mount_src"] = nfs_params.get("nfs_mount_src")
                params["nfs_mount_dir"] = nfs_params.get("fs_source_dir")
                nfs_local = nfs.Nfs(params)
                nfs_local.setup()
        params["start_vm"] = "yes"
        env_process.preprocess(test, params, env)

    os_type = params.get("os_type")
    vm = env.get_vm(params.get("main_vm"))
    vm.verify_alive()
    session = vm.wait_for_login()
    host_addr = vm.get_address()

    if os_type == "windows":
        cmd_timeout = params.get_numeric("cmd_timeout", 120)
        driver_name = params["driver_name"]
        install_path = params["install_path"]
        check_installed_cmd = params["check_installed_cmd"] % install_path

        # Check whether windows driver is running,and enable driver verifier
        session = utils_test.qemu.windrv_check_running_verifier(session,
                                                                vm, test,
                                                                driver_name)
        # install winfsp tool
        error_context.context("Install winfsp for windows guest.",
                              logging.info)
        installed = session.cmd_status(check_installed_cmd) == 0
        if installed:
            logging.info("Winfsp tool is already installed.")
        else:
            install_cmd = utils_misc.set_winutils_letter(session,
                                                         params["install_cmd"])
            session.cmd(install_cmd, cmd_timeout)
            if not utils_misc.wait_for(lambda: not session.cmd_status(
                    check_installed_cmd), 60):
                test.error("Winfsp tool is not installed.")

    for fs in params.objects("filesystems"):
        fs_params = params.object_params(fs)
        fs_target = fs_params.get("fs_target")
        fs_dest = fs_params.get("fs_dest")

        fs_source = fs_params.get("fs_source_dir")
        base_dir = fs_params.get("fs_source_base_dir",
                                 data_dir.get_data_dir())
        if not os.path.isabs(fs_source):
            fs_source = os.path.join(base_dir, fs_source)

        host_data = os.path.join(fs_source, 'fs_test')

        if os_type == "linux":
            error_context.context("Create a destination directory %s "
                                  "inside guest." % fs_dest, logging.info)
            utils_misc.make_dirs(fs_dest, session)
            if not cmd_xfstest:
                error_context.context("Mount virtiofs target %s to %s inside"
                                      " guest." % (fs_target, fs_dest),
                                      logging.info)
                if not utils_disk.mount(fs_target, fs_dest, 'virtiofs', session=session):
                    test.fail('Mount virtiofs target failed.')

        else:
            error_context.context("Start virtiofs service in guest.", logging.info)
            viofs_sc_create_cmd = params["viofs_sc_create_cmd"]
            viofs_sc_start_cmd = params["viofs_sc_start_cmd"]
            viofs_sc_query_cmd = params["viofs_sc_query_cmd"]

            logging.info("Check if virtiofs service is registered.")
            status, output = session.cmd_status_output(viofs_sc_query_cmd)
            if "not exist as an installed service" in output:
                logging.info("Register virtiofs service in windows guest.")
                exe_path = get_viofs_exe(session)
                viofs_sc_create_cmd = viofs_sc_create_cmd % exe_path
                sc_create_s, sc_create_o = session.cmd_status_output(viofs_sc_create_cmd)
                if sc_create_s != 0:
                    test.fail("Failed to register virtiofs service, output is %s" % sc_create_o)

            logging.info("Check if virtiofs service is started.")
            status, output = session.cmd_status_output(viofs_sc_query_cmd)
            if "RUNNING" not in output:
                logging.info("Start virtiofs service.")
                sc_start_s, sc_start_o = session.cmd_status_output(viofs_sc_start_cmd)
                if sc_start_s != 0:
                    test.fail("Failed to start virtiofs service, output is %s" % sc_start_o)
            else:
                logging.info("Virtiofs service is running.")

            viofs_log_file_cmd = params.get("viofs_log_file_cmd")
            if viofs_log_file_cmd:
                error_context.context("Check if LOG file is created.", logging.info)
                log_dir_s = session.cmd_status(viofs_log_file_cmd)
                if log_dir_s != 0:
                    test.fail("Virtiofs log is not created.")

            # get fs dest for vm
            virtio_fs_disk_label = fs_target
            error_context.context("Get Volume letter of virtio fs target, the disk"
                                  "lable is %s." % virtio_fs_disk_label,
                                  logging.info)
            vol_con = "VolumeName='%s'" % virtio_fs_disk_label
            vol_func = utils_misc.get_win_disk_vol(session, condition=vol_con)
            volume_letter = utils_misc.wait_for(lambda: vol_func, cmd_timeout)
            if volume_letter is None:
                test.fail("Could not get virtio-fs mounted volume letter.")
            fs_dest = "%s:" % volume_letter

        guest_file = os.path.join(fs_dest, 'fs_test')
        logging.info("The guest file in shared dir is %s", guest_file)

        try:
            if cmd_dd:
                error_context.context("Creating file under %s inside "
                                      "guest." % fs_dest, logging.info)
                session.cmd(cmd_dd % guest_file, io_timeout)

                if os_type == "linux":
                    cmd_md5_vm = cmd_md5 % guest_file
                else:
                    guest_file_win = guest_file.replace("/", "\\")
                    cmd_md5_vm = cmd_md5 % (volume_letter, guest_file_win)
                md5_guest = session.cmd_output(cmd_md5_vm, io_timeout).strip().split()[0]

                logging.info(md5_guest)
                md5_host = process.run("md5sum %s" % host_data,
                                       io_timeout).stdout_text.strip().split()[0]
                if md5_guest != md5_host:
                    test.fail('The md5 value of host is not same to guest.')

            if cmd_new_folder and cmd_copy_file and cmd_del_folder:
                error_context.context("Folder test under %s inside "
                                      "guest." % fs_dest, logging.info)
                session.cmd(cmd_new_folder % fs_dest)
                test_file = guest_file if os_type == "linux" \
                    else "%s:\\%s" % (volume_letter, 'fs_test')
                session.cmd(cmd_copy_file % (test_file, fs_dest))
                session.cmd(cmd_del_folder % fs_dest)

            if fio_options:
                error_context.context("Run fio on %s." % fs_dest, logging.info)
                fio = generate_instance(params, vm, 'fio')
                try:
                    fio.run(fio_options % guest_file, io_timeout)
                finally:
                    fio.clean()
                vm.verify_dmesg()

            if cmd_pjdfstest:
                error_context.context("Run pjdfstest on %s." % fs_dest, logging.info)
                host_path = os.path.join(data_dir.get_deps_dir('pjdfstest'), pjdfstest_pkg)
                scp_to_remote(host_addr, port, username, password, host_path, fs_dest)
                session.cmd(cmd_unpack.format(fs_dest), 180)
                session.cmd(cmd_yum_deps, 180)
                session.cmd(cmd_autoreconf % fs_dest, 180)
                session.cmd(cmd_configure.format(fs_dest), 180)
                session.cmd(cmd_make % fs_dest, io_timeout)
                session.cmd(cmd_pjdfstest % fs_dest, io_timeout)

            if cmd_xfstest:
                error_context.context("Run xfstest on guest.", logging.info)
                utils_misc.make_dirs(fs_dest_fs2, session)
                if session.cmd_status(cmd_download_xfstest, 360):
                    test.error("Failed to download xfstests-dev")
                session.cmd(cmd_yum_install, 180)
                session.cmd(cmd_make_xfs, 360)
                session.cmd(cmd_setenv, 180)
                session.cmd(cmd_setenv_nfs, 180)
                session.cmd(cmd_useradd, 180)

                try:
                    output = session.cmd_output(cmd_xfstest, io_timeout)
                    logging.info("%s", output)
                    if 'Failed' in output:
                        test.fail('The xfstest failed.')
                    else:
                        break
                except (aexpect.ShellStatusError, aexpect.ShellTimeoutError):
                    test.fail('The xfstest failed.')

        finally:
            if os_type == "linux":
                utils_disk.umount(fs_target, fs_dest, 'virtiofs', session=session)
                utils_misc.safe_rmdir(fs_dest, session=session)
            if setup_local_nfs:
                session.close()
                vm.destroy()
                for fs in params.objects("filesystems"):
                    nfs_params = params.object_params(fs)
                    params["export_dir"] = nfs_params.get("export_dir")
                    params["nfs_mount_dir"] = nfs_params.get("fs_source_dir")
                    params["rm_export_dir"] = nfs_params.get("export_dir")
                    params["rm_mount_dir"] = nfs_params.get("fs_source_dir")
                    nfs_local = nfs.Nfs(params)
                    nfs_local.cleanup()
                    utils_misc.safe_rmdir(params["export_dir"])

    # during all virtio fs is mounted, reboot vm
    if params.get('reboot_guest', 'no') == 'yes':
        def get_vfsd_num():
            """
            Get virtiofsd daemon number during vm boot up.
            :return: virtiofsd daemon count.
            """
            cmd_ps_virtiofsd = params.get('cmd_ps_virtiofsd')
            vfsd_num = 0
            for device in vm.devices:
                if isinstance(device, qdevices.QVirtioFSDev):
                    sock_path = device.get_param('sock_path')
                    cmd_ps_virtiofsd = cmd_ps_virtiofsd % sock_path
                    vfsd_ps = process.system_output(cmd_ps_virtiofsd, shell=True)
                    vfsd_num += len(vfsd_ps.strip().splitlines())
            return vfsd_num

        error_context.context("Check virtiofs daemon before reboot vm.",
                              logging.info)

        vfsd_num_bf = get_vfsd_num()
        error_context.context("Reboot guest and check virtiofs daemon.",
                              logging.info)
        vm.reboot()
        if not vm.is_alive():
            test.fail("After rebooting vm quit unexpectedly.")
        vfsd_num_af = get_vfsd_num()

        if vfsd_num_bf != vfsd_num_af:
            test.fail("Virtiofs daemon is different before and after reboot.\n"
                      "Before reboot: %s\n"
                      "After reboot: %s\n", (vfsd_num_bf, vfsd_num_af))
Ejemplo n.º 24
0
def run(test, params, env):
    """
        Test throttle relevant properties feature.

        1) Boot up guest with throttle groups.
        There are two throttle groups. One have two disks,other is empty.
        2) Build fio operation options and expected result
         according to throttle properties.
        3) Execute single disk throttle testing on  first group.
        4) Execute group relevant testing for example:
        Change throttle group attribute or move disk to other group
        5) Or Execute other operation testing for example:
        Reboot guest or stop-resume guest
        6) Execute throttle testing on all groups.
    """
    def negative_test():
        """negative test for the group option"""
        all_groups = params.get("groups", "group2")
        for name in all_groups.split():
            props = json.loads(params.get(name, "{}"))
            err_msg = params.object_params(name)["err_msg"]
            try:
                tgm.update_throttle_group("group1", props)
            except QMPCmdError as err:
                qmp_desc = err.data["desc"]
                if qmp_desc.find(err_msg) >= 0:
                    logging.info("Find expected result for %s", name)
                    continue
                logging.error(
                    "Cannot got expected wrong result on %s: %s in %s", name,
                    err_msg, qmp_desc)
                raise err
            else:
                test.fail("Can not got expected wrong result")

    def group_change():
        """change group attributes testing"""
        props = json.loads(params["throttle_group_parameters_group2"])

        tgm.update_throttle_group("group1", props)

    def group_move():
        """Move disk to other group"""
        tgm.change_throttle_group("stg2", "group2")

    def operation_reboot():
        """Guest reboot test"""
        vm.reboot(session)

    def operation_stop_resume():
        """Guest stop resume test"""
        vm.pause()
        vm.resume()

    def operation_hotplug():
        """
        relevant operation:
        unplug throttle group
        plug throttle group
        add disk into exist throttle group
        add disk into plugged throttle group
        """
        opts = json.loads(params.get("throttle_group_parameters_group2", "{}"))
        tgm.delete_throttle_group("group2")
        tgm.add_throttle_group("group2", opts)
        plug = BlockDevicesPlug(vm)
        plug.hotplug_devs_serial("stg3")
        plug.hotplug_devs_serial("stg4")

    error_context.context("Get the main VM", logging.info)
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=360)

    error_context.context("Deploy fio", logging.info)
    fio = generate_instance(params, vm, 'fio')

    tgm = ThrottleGroupManager(vm)
    groups = params["throttle_groups"].split()
    operation = params["operation"]

    # simple test on group1
    error_context.context("Execute simple test on group1", logging.info)
    tester = ThrottleTester(test, params, vm, session, "group1", ["stg1"])
    tester.build_default_option()
    tester.build_images_fio_option()
    tester.set_fio(fio)
    tester.start()

    # execute relevant operation
    error_context.context("Execute operation %s" % operation, logging.info)
    locals_var = locals()
    locals_var[operation]()
    # test after operation
    testers = []
    tgm = ThrottleGroupManager(vm)
    session = vm.wait_for_login(timeout=360)
    for group in groups:
        tgm.get_throttle_group_props(group)
        images = params.get("throttle_group_member_%s" % group, "").split()
        if len(images) == 0:
            logging.warning("No images in group %s", group)
            continue
        tester = ThrottleTester(test, params, vm, session, group, images)
        error_context.context("Build test stuff for %s:%s" % (group, images),
                              logging.info)
        tester.build_default_option()
        tester.build_images_fio_option()
        tester.set_fio(fio)
        testers.append(tester)

    error_context.context("Start groups testing:%s" % groups, logging.info)
    groups_tester = ThrottleGroupsTester(testers)

    groups_tester.start()
Ejemplo n.º 25
0
def run(test, params, env):
    """
    Test multi disk suport of guest, this case will:
    1) Create disks image in configuration file.
    2) Start the guest with those disks.
    3) Checks qtree vs. test params. (Optional)
    4) Create partition on those disks.
    5) Get disk dev filenames in guest.
    6) Format those disks in guest.
    7) Copy file into / out of those disks.
    8) Compare the original file and the copied file using md5 or fc comand.
    9) Repeat steps 3-5 if needed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def _add_param(name, value):
        """ Converts name+value to stg_params string """
        if value:
            value = re.sub(' ', '\\ ', value)
            return " %s:%s " % (name, value)
        else:
            return ''

    def _do_post_cmd(session):
        cmd = params.get("post_cmd")
        if cmd:
            session.cmd_status_output(cmd)
        session.close()

    error_context.context("Parsing test configuration", logging.info)
    stg_image_num = 0
    stg_params = params.get("stg_params", "")
    # Compatibility
    stg_params += _add_param("image_size", params.get("stg_image_size"))
    stg_params += _add_param("image_format", params.get("stg_image_format"))
    stg_params += _add_param("image_boot", params.get("stg_image_boot", "no"))
    stg_params += _add_param("drive_format", params.get("stg_drive_format"))
    stg_params += _add_param("drive_cache", params.get("stg_drive_cache"))
    if params.get("stg_assign_index") != "no":
        # Assume 0 and 1 are already occupied (hd0 and cdrom)
        stg_params += _add_param("drive_index", 'range(2,n)')
    param_matrix = {}

    stg_params = stg_params.split(' ')
    i = 0
    while i < len(stg_params) - 1:
        if not stg_params[i].strip():
            i += 1
            continue
        if stg_params[i][-1] == '\\':
            stg_params[i] = '%s %s' % (stg_params[i][:-1],
                                       stg_params.pop(i + 1))
        i += 1

    rerange = []
    has_name = False
    for i in range(len(stg_params)):
        if not stg_params[i].strip():
            continue
        (cmd, parm) = stg_params[i].split(':', 1)
        if cmd == "image_name":
            has_name = True
        if _RE_RANGE1.match(parm):
            parm = _range(parm)
            if parm is False:
                test.error("Incorrect cfg: stg_params %s looks "
                           "like range(..) but doesn't contain "
                           "numbers." % cmd)
            param_matrix[cmd] = parm
            if type(parm) is str:
                # When we know the stg_image_num, substitute it.
                rerange.append(cmd)
                continue
        else:
            # ',' separated list of values
            parm = parm.split(',')
            j = 0
            while j < len(parm) - 1:
                if parm[j][-1] == '\\':
                    parm[j] = '%s,%s' % (parm[j][:-1], parm.pop(j + 1))
                j += 1
            param_matrix[cmd] = parm
        stg_image_num = max(stg_image_num, len(parm))

    stg_image_num = int(params.get('stg_image_num', stg_image_num))
    for cmd in rerange:
        param_matrix[cmd] = _range(param_matrix[cmd], stg_image_num)
    # param_table* are for pretty print of param_matrix
    param_table = []
    param_table_header = ['name']
    if not has_name:
        param_table_header.append('image_name')
    for _ in param_matrix:
        param_table_header.append(_)

    stg_image_name = params.get('stg_image_name', 'images/%s')
    for i in range(stg_image_num):
        name = "stg%d" % i
        params['images'] += " %s" % name
        param_table.append([])
        param_table[-1].append(name)
        if not has_name:
            params["image_name_%s" % name] = stg_image_name % name
            param_table[-1].append(params.get("image_name_%s" % name))
        for parm in param_matrix.items():
            params['%s_%s' % (parm[0], name)] = str(parm[1][i % len(parm[1])])
            param_table[-1].append(params.get('%s_%s' % (parm[0], name)))

    if params.get("multi_disk_params_only") == 'yes':
        # Only print the test param_matrix and finish
        logging.info('Newly added disks:\n%s',
                     astring.tabular_output(param_table, param_table_header))
        return

    # Always recreate VMs and disks
    error_context.context("Start the guest with new disks", logging.info)
    for vm_name in params.objects("vms"):
        vm_params = params.object_params(vm_name)
        env_process.process_images(env_process.preprocess_image, test,
                                   vm_params)

    error_context.context("Start the guest with those disks", logging.info)
    vm = env.get_vm(params["main_vm"])
    vm.create(timeout=max(10, stg_image_num), params=params)
    login_timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=login_timeout)

    n_repeat = int(params.get("n_repeat", "1"))
    file_system = [_.strip() for _ in params["file_system"].split()]
    cmd_timeout = float(params.get("cmd_timeout", 360))
    black_list = params["black_list"].split()
    drive_letters = int(params.get("drive_letters", "26"))
    stg_image_size = params["stg_image_size"]
    dd_test = params.get("dd_test", "no")
    pre_command = params.get("pre_command", "")
    labeltype = params.get("labeltype", "gpt")
    iozone_target_num = int(params.get('iozone_target_num', '5'))
    iozone_options = params.get('iozone_options')
    iozone_timeout = float(params.get('iozone_timeout', '7200'))

    have_qtree = True
    out = vm.monitor.human_monitor_cmd("info qtree", debug=False)
    if "unknown command" in str(out):
        have_qtree = False

    if (params.get("check_guest_proc_scsi") == "yes") and have_qtree:
        error_context.context("Verifying qtree vs. test params")
        err = 0
        qtree = qemu_qtree.QtreeContainer()
        qtree.parse_info_qtree(vm.monitor.info('qtree'))
        disks = qemu_qtree.QtreeDisksContainer(qtree.get_nodes())
        (tmp1, tmp2) = disks.parse_info_block(vm.monitor.info_block())
        err += tmp1 + tmp2
        err += disks.generate_params()
        err += disks.check_disk_params(params)
        (tmp1, tmp2, _, _) = disks.check_guests_proc_scsi(
            session.cmd_output('cat /proc/scsi/scsi'))
        err += tmp1 + tmp2

        if err:
            test.fail("%s errors occurred while verifying qtree vs."
                      " params" % err)
        if params.get('multi_disk_only_qtree') == 'yes':
            return
    try:
        err_msg = "Set disks num: %d" % stg_image_num
        err_msg += ", Get disks num in guest: %d"
        ostype = params["os_type"]
        if ostype == "windows":
            error_context.context("Get windows disk index that to "
                                  "be formatted", logging.info)
            disks = utils_disk.get_windows_disks_index(session, stg_image_size)
            if len(disks) < stg_image_num:
                test.fail("Fail to list all the volumes"
                          ", %s" % err_msg % len(disks))
            if len(disks) > drive_letters:
                black_list.extend(utils_misc.get_winutils_vol(session))
                disks = random.sample(disks, drive_letters - len(black_list))
            error_context.context("Clear readonly for all disks and online "
                                  "them in windows guest.", logging.info)
            if not utils_disk.update_windows_disk_attributes(session, disks):
                test.fail("Failed to update windows disk attributes.")
            dd_test = "no"
        else:
            error_context.context("Get linux disk that to be "
                                  "formatted", logging.info)
            disks = sorted(utils_disk.get_linux_disks(session).keys())
            if len(disks) < stg_image_num:
                test.fail("Fail to list all the volumes"
                          ", %s" % err_msg % len(disks))
    except Exception:
        _do_post_cmd(session)
        raise
    try:
        if iozone_options:
            iozone = generate_instance(params, session, 'iozone')
            random.shuffle(disks)
        for i in range(n_repeat):
            logging.info("iterations: %s", (i + 1))
            for n, disk in enumerate(disks):
                error_context.context("Format disk in guest: '%s'" % disk,
                                      logging.info)
                # Random select one file system from file_system
                index = random.randint(0, (len(file_system) - 1))
                fstype = file_system[index].strip()
                partitions = utils_disk.configure_empty_disk(
                    session, disk, stg_image_size, ostype,
                    fstype=fstype, labeltype=labeltype)
                if not partitions:
                    test.fail("Fail to format disks.")
                cmd_list = params["cmd_list"]
                for partition in partitions:
                    orig_partition = partition
                    if "/" not in partition:
                        partition += ":"
                    else:
                        partition = partition.split("/")[-1]
                    error_context.context("Copy file into / out of partition:"
                                          " %s..." % partition, logging.info)
                    for cmd_l in cmd_list.split():
                        cmd = params.get(cmd_l)
                        if cmd:
                            session.cmd(cmd % partition, timeout=cmd_timeout)
                    cmd = params["compare_command"]
                    key_word = params["check_result_key_word"]
                    output = session.cmd_output(cmd)
                    if iozone_options and n < iozone_target_num:
                        iozone.run(iozone_options.format(orig_partition), iozone_timeout)
                    if key_word not in output:
                        test.fail("Files on guest os root fs and disk differ")
                    if dd_test != "no":
                        error_context.context("dd test on partition: %s..."
                                              % partition, logging.info)
                        status, output = session.cmd_status_output(
                            dd_test % (partition, partition), timeout=cmd_timeout)
                        if status != 0:
                            test.fail("dd test fail: %s" % output)
                    # When multiple SCSI disks are simulated by scsi_debug,
                    # they could be viewed as multiple paths to the same
                    # storage device. So need umount partition before operate
                    # next disk, in order to avoid corrupting the filesystem
                    # (xfs integrity checks error).
                    if ostype == "linux" and "scsi_debug add_host" in pre_command:
                        status, output = session.cmd_status_output(
                            "umount /dev/%s" % partition, timeout=cmd_timeout)
                        if status != 0:
                            test.fail("Failed to umount partition '%s': %s"
                                      % (partition, output))
            need_reboot = params.get("need_reboot", "no")
            need_shutdown = params.get("need_shutdown", "no")
            if need_reboot == "yes":
                error_context.context("Rebooting guest ...", logging.info)
                session = vm.reboot(session=session, timeout=login_timeout)
            if need_shutdown == "yes":
                error_context.context("Shutting down guest ...", logging.info)
                vm.graceful_shutdown(timeout=login_timeout)
                if vm.is_alive():
                    test.fail("Fail to shut down guest.")
                error_context.context("Start the guest again.", logging.info)
                vm = env.get_vm(params["main_vm"])
                vm.create(params=params)
                session = vm.wait_for_login(timeout=login_timeout)
            error_context.context("Delete partitions in guest.", logging.info)
            for disk in disks:
                utils_disk.clean_partition(session, disk, ostype)
    finally:
        if iozone_options:
            iozone.clean()
        _do_post_cmd(session)
Ejemplo n.º 26
0
def run(test, params, env):
    """
    Test multi disk suport of guest, this case will:
    1) Create disks image in configuration file.
    2) Start the guest with those disks.
    3) Checks qtree vs. test params. (Optional)
    4) Create partition on those disks.
    5) Get disk dev filenames in guest.
    6) Format those disks in guest.
    7) Copy file into / out of those disks.
    8) Compare the original file and the copied file using md5 or fc comand.
    9) Repeat steps 3-5 if needed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def _add_param(name, value):
        """ Converts name+value to stg_params string """
        if value:
            value = re.sub(' ', '\\ ', value)
            return " %s:%s " % (name, value)
        else:
            return ''

    def _do_post_cmd(session):
        cmd = params.get("post_cmd")
        if cmd:
            session.cmd_status_output(cmd)
        session.close()

    error_context.context("Parsing test configuration", logging.info)
    stg_image_num = 0
    stg_params = params.get("stg_params", "")
    # Compatibility
    stg_params += _add_param("image_size", params.get("stg_image_size"))
    stg_params += _add_param("image_format", params.get("stg_image_format"))
    stg_params += _add_param("image_boot", params.get("stg_image_boot", "no"))
    stg_params += _add_param("drive_format", params.get("stg_drive_format"))
    stg_params += _add_param("drive_cache", params.get("stg_drive_cache"))
    if params.get("stg_assign_index") != "no":
        # Assume 0 and 1 are already occupied (hd0 and cdrom)
        stg_params += _add_param("drive_index", 'range(2,n)')
    param_matrix = {}

    stg_params = stg_params.split(' ')
    i = 0
    while i < len(stg_params) - 1:
        if not stg_params[i].strip():
            i += 1
            continue
        if stg_params[i][-1] == '\\':
            stg_params[i] = '%s %s' % (stg_params[i][:-1],
                                       stg_params.pop(i + 1))
        i += 1

    rerange = []
    has_name = False
    for i in range(len(stg_params)):
        if not stg_params[i].strip():
            continue
        (cmd, parm) = stg_params[i].split(':', 1)
        if cmd == "image_name":
            has_name = True
        if _RE_RANGE1.match(parm):
            parm = _range(parm)
            if parm is False:
                test.error("Incorrect cfg: stg_params %s looks "
                           "like range(..) but doesn't contain "
                           "numbers." % cmd)
            param_matrix[cmd] = parm
            if type(parm) is str:
                # When we know the stg_image_num, substitute it.
                rerange.append(cmd)
                continue
        else:
            # ',' separated list of values
            parm = parm.split(',')
            j = 0
            while j < len(parm) - 1:
                if parm[j][-1] == '\\':
                    parm[j] = '%s,%s' % (parm[j][:-1], parm.pop(j + 1))
                j += 1
            param_matrix[cmd] = parm
        stg_image_num = max(stg_image_num, len(parm))

    stg_image_num = int(params.get('stg_image_num', stg_image_num))
    for cmd in rerange:
        param_matrix[cmd] = _range(param_matrix[cmd], stg_image_num)
    # param_table* are for pretty print of param_matrix
    param_table = []
    param_table_header = ['name']
    if not has_name:
        param_table_header.append('image_name')
    for _ in param_matrix:
        param_table_header.append(_)

    stg_image_name = params.get('stg_image_name', 'images/%s')
    for i in range(stg_image_num):
        name = "stg%d" % i
        params['images'] += " %s" % name
        param_table.append([])
        param_table[-1].append(name)
        if not has_name:
            params["image_name_%s" % name] = stg_image_name % name
            param_table[-1].append(params.get("image_name_%s" % name))
        for parm in param_matrix.items():
            params['%s_%s' % (parm[0], name)] = str(parm[1][i % len(parm[1])])
            param_table[-1].append(params.get('%s_%s' % (parm[0], name)))

    if params.get("multi_disk_params_only") == 'yes':
        # Only print the test param_matrix and finish
        logging.info('Newly added disks:\n%s',
                     astring.tabular_output(param_table, param_table_header))
        return

    # Always recreate VMs and disks
    error_context.context("Start the guest with new disks", logging.info)
    for vm_name in params.objects("vms"):
        vm_params = params.object_params(vm_name)
        env_process.process_images(env_process.preprocess_image, test,
                                   vm_params)

    error_context.context("Start the guest with those disks", logging.info)
    vm = env.get_vm(params["main_vm"])
    vm.create(timeout=max(10, stg_image_num), params=params)
    login_timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=login_timeout)

    n_repeat = int(params.get("n_repeat", "1"))
    file_system = [_.strip() for _ in params["file_system"].split()]
    cmd_timeout = float(params.get("cmd_timeout", 360))
    black_list = params["black_list"].split()
    drive_letters = int(params.get("drive_letters", "26"))
    stg_image_size = params["stg_image_size"]
    dd_test = params.get("dd_test", "no")
    pre_command = params.get("pre_command", "")
    labeltype = params.get("labeltype", "gpt")
    iozone_target_num = int(params.get('iozone_target_num', '5'))
    iozone_options = params.get('iozone_options')
    iozone_timeout = float(params.get('iozone_timeout', '7200'))

    have_qtree = True
    out = vm.monitor.human_monitor_cmd("info qtree", debug=False)
    if "unknown command" in str(out):
        have_qtree = False

    if (params.get("check_guest_proc_scsi") == "yes") and have_qtree:
        error_context.context("Verifying qtree vs. test params")
        err = 0
        qtree = qemu_qtree.QtreeContainer()
        qtree.parse_info_qtree(vm.monitor.info('qtree'))
        disks = qemu_qtree.QtreeDisksContainer(qtree.get_nodes())
        (tmp1, tmp2) = disks.parse_info_block(vm.monitor.info_block())
        err += tmp1 + tmp2
        err += disks.generate_params()
        err += disks.check_disk_params(params)
        (tmp1, tmp2, _, _) = disks.check_guests_proc_scsi(
            session.cmd_output('cat /proc/scsi/scsi'))
        err += tmp1 + tmp2

        if err:
            test.fail("%s errors occurred while verifying qtree vs."
                      " params" % err)
        if params.get('multi_disk_only_qtree') == 'yes':
            return
    try:
        err_msg = "Set disks num: %d" % stg_image_num
        err_msg += ", Get disks num in guest: %d"
        ostype = params["os_type"]
        if ostype == "windows":
            error_context.context(
                "Get windows disk index that to "
                "be formatted", logging.info)
            disks = utils_disk.get_windows_disks_index(session, stg_image_size)
            if len(disks) < stg_image_num:
                test.fail("Fail to list all the volumes"
                          ", %s" % err_msg % len(disks))
            if len(disks) > drive_letters:
                black_list.extend(utils_misc.get_winutils_vol(session))
                disks = random.sample(disks, drive_letters - len(black_list))
            error_context.context(
                "Clear readonly for all disks and online "
                "them in windows guest.", logging.info)
            if not utils_disk.update_windows_disk_attributes(session, disks):
                test.fail("Failed to update windows disk attributes.")
            dd_test = "no"
        else:
            error_context.context("Get linux disk that to be "
                                  "formatted", logging.info)
            disks = sorted(utils_disk.get_linux_disks(session).keys())
            if len(disks) < stg_image_num:
                test.fail("Fail to list all the volumes"
                          ", %s" % err_msg % len(disks))
    except Exception:
        _do_post_cmd(session)
        raise
    try:
        if iozone_options:
            iozone = generate_instance(params, session, 'iozone')
            random.shuffle(disks)
        for i in range(n_repeat):
            logging.info("iterations: %s", (i + 1))
            for n, disk in enumerate(disks):
                error_context.context("Format disk in guest: '%s'" % disk,
                                      logging.info)
                # Random select one file system from file_system
                index = random.randint(0, (len(file_system) - 1))
                fstype = file_system[index].strip()
                partitions = utils_disk.configure_empty_disk(
                    session,
                    disk,
                    stg_image_size,
                    ostype,
                    fstype=fstype,
                    labeltype=labeltype)
                if not partitions:
                    test.fail("Fail to format disks.")
                cmd_list = params["cmd_list"]
                for partition in partitions:
                    orig_partition = partition
                    if "/" not in partition:
                        partition += ":"
                    else:
                        partition = partition.split("/")[-1]
                    error_context.context(
                        "Copy file into / out of partition:"
                        " %s..." % partition, logging.info)
                    for cmd_l in cmd_list.split():
                        cmd = params.get(cmd_l)
                        if cmd:
                            session.cmd(cmd % partition, timeout=cmd_timeout)
                    cmd = params["compare_command"]
                    key_word = params["check_result_key_word"]
                    output = session.cmd_output(cmd)
                    if iozone_options and n < iozone_target_num:
                        iozone.run(iozone_options.format(orig_partition),
                                   iozone_timeout)
                    if key_word not in output:
                        test.fail("Files on guest os root fs and disk differ")
                    if dd_test != "no":
                        error_context.context(
                            "dd test on partition: %s..." % partition,
                            logging.info)
                        status, output = session.cmd_status_output(
                            dd_test % (partition, partition),
                            timeout=cmd_timeout)
                        if status != 0:
                            test.fail("dd test fail: %s" % output)
                    # When multiple SCSI disks are simulated by scsi_debug,
                    # they could be viewed as multiple paths to the same
                    # storage device. So need umount partition before operate
                    # next disk, in order to avoid corrupting the filesystem
                    # (xfs integrity checks error).
                    if ostype == "linux" and "scsi_debug add_host" in pre_command:
                        status, output = session.cmd_status_output(
                            "umount /dev/%s" % partition, timeout=cmd_timeout)
                        if status != 0:
                            test.fail("Failed to umount partition '%s': %s" %
                                      (partition, output))
            need_reboot = params.get("need_reboot", "no")
            need_shutdown = params.get("need_shutdown", "no")
            if need_reboot == "yes":
                error_context.context("Rebooting guest ...", logging.info)
                session = vm.reboot(session=session, timeout=login_timeout)
            if need_shutdown == "yes":
                error_context.context("Shutting down guest ...", logging.info)
                vm.graceful_shutdown(timeout=login_timeout)
                if vm.is_alive():
                    test.fail("Fail to shut down guest.")
                error_context.context("Start the guest again.", logging.info)
                vm = env.get_vm(params["main_vm"])
                vm.create(params=params)
                session = vm.wait_for_login(timeout=login_timeout)
            error_context.context("Delete partitions in guest.", logging.info)
            for disk in disks:
                utils_disk.clean_partition(session, disk, ostype)
    finally:
        if iozone_options:
            iozone.clean()
        _do_post_cmd(session)
Ejemplo n.º 27
0
def run(test, params, env):
    """
    Test hotplug of block devices.

    1) Boot up guest with virtio-blk or virtio-scsi system disk.
    2) Hoplug a virtio-blk or virtio-scsi data disk by qmp.
    3) Do read/write data on hotplug block.
    4) Unplug block device during serving block io, then verify devices.
    5) repeat step2~step4 100 times.

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def _check_iozone_status():
        ck_session = vm.wait_for_login(timeout=360)
        if not utils_misc.wait_for(lambda: check_cmd[os_type].split(
        )[-1].lower() in ck_session.cmd_output(check_cmd[os_type]).lower(),
                                   180,
                                   step=3.0):
            test.fail("Iozone is not alive!")
        ck_session.close()

    def _run_iozone_background():
        logging.info("Start iozone under background.")
        thread = utils_misc.InterruptedThread(
            iozone.run, (params['iozone_options'].format(mount_point),
                         float(params['iozone_timeout'])))
        thread.start()
        _check_iozone_status()
        return thread

    check_cmd = {
        'linux': 'pgrep -lx iozone',
        'windows': 'TASKLIST /FI "IMAGENAME eq IOZONE.EXE'
    }
    os_type = params['os_type']
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(timeout=360)

    iozone = generate_instance(params, vm, 'iozone')
    plug = BlockDevicesPlug(vm)
    need_format = True
    try:
        for i in range(int(params['repeat_time'])):
            logging.info('Start to run testing.(iteration: %d).', (i + 1))
            plug.hotplug_devs_serial()
            if need_format:
                if os_type == 'windows':
                    utils_disk.update_windows_disk_attributes(session, plug[0])
                mount_point = utils_disk.configure_empty_disk(
                    session, plug[0], params['image_size_stg0'], os_type)[0]
                if os_type == 'windows':
                    need_format = False
            iozone_thread = _run_iozone_background()
            time.sleep(float(params['sleep_time']))
            _check_iozone_status()
            plug.unplug_devs_serial()
            iozone_thread.join(suppress_exception=True)
    finally:
        iozone.clean(force=True)
        session.close()
Ejemplo n.º 28
0
def run(test, params, env):
    """
    Test virtio-fs by sharing the data between host and guest.
    Steps:
        1. Create shared directories on the host.
        2. Run virtiofsd daemons on the host.
        3. Boot a guest on the host with virtiofs options.
        4. Log into guest then mount the virtiofs targets.
        5. Generate files or run stress on the mount points inside guest.

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    cmd_dd = params.get('cmd_dd')
    cmd_md5 = params.get('cmd_md5')

    cmd_pjdfstest = params.get('cmd_pjdfstest')
    cmd_unpack = params.get('cmd_unpack')
    cmd_yum_deps = params.get('cmd_yum_deps')
    cmd_autoreconf = params.get('cmd_autoreconf')
    cmd_configure = params.get('cmd_configure')
    cmd_make = params.get('cmd_make')
    pjdfstest_pkg = params.get('pjdfstest_pkg')

    fio_options = params.get('fio_options')
    io_timeout = params.get_numeric('io_timeout')

    username = params.get('username')
    password = params.get('password')
    port = params.get('file_transfer_port')

    vm = env.get_vm(params.get("main_vm"))
    vm.verify_alive()
    session = vm.wait_for_login()
    host_addr = vm.get_address()

    for fs in params.objects("filesystems"):
        fs_params = params.object_params(fs)
        fs_target = fs_params.get("fs_target")
        fs_dest = fs_params.get("fs_dest")

        fs_source = fs_params.get("fs_source_dir")
        base_dir = fs_params.get("fs_source_base_dir", data_dir.get_data_dir())
        if not os.path.isabs(fs_source):
            fs_source = os.path.join(base_dir, fs_source)
        guest_data = os.path.join(fs_dest, 'fs_test')
        host_data = os.path.join(fs_source, 'fs_test')

        error_context.context(
            "Create a destination directory %s "
            "inside guest." % fs_dest, logging.info)
        utils_misc.make_dirs(fs_dest, session)

        error_context.context(
            "Mount virtiofs target %s to %s inside guest." %
            (fs_target, fs_dest), logging.info)
        utils_disk.mount(fs_target, fs_dest, 'virtiofs', session=session)

        try:
            if cmd_dd:
                logging.info("Creating file under %s inside guest." % fs_dest)
                session.cmd(cmd_dd % guest_data, io_timeout)
                logging.info("Compare the md5 between guest and host.")
                md5_guest = session.cmd(cmd_md5 % guest_data,
                                        io_timeout).strip().split()[0]
                logging.info(md5_guest)
                md5_host = process.run(
                    cmd_md5 % host_data,
                    io_timeout).stdout_text.strip().split()[0]
                if md5_guest != md5_host:
                    test.fail('The md5 value of host is not same to guest.')

            if fio_options:
                error_context.context("Run fio on %s." % fs_dest, logging.info)
                fio = generate_instance(params, vm, 'fio')
                try:
                    fio.run(fio_options % guest_data, io_timeout)
                finally:
                    fio.clean()
                vm.verify_dmesg()

            if cmd_pjdfstest:
                error_context.context("Run pjdfstest on %s." % fs_dest,
                                      logging.info)
                host_path = os.path.join(data_dir.get_deps_dir('pjdfstest'),
                                         pjdfstest_pkg)
                scp_to_remote(host_addr, port, username, password, host_path,
                              fs_dest)
                session.cmd(cmd_unpack.format(fs_dest), 180)
                session.cmd(cmd_yum_deps, 180)
                session.cmd(cmd_autoreconf % fs_dest, 180)
                session.cmd(cmd_configure.format(fs_dest), 180)
                session.cmd(cmd_make % fs_dest, io_timeout)
                session.cmd(cmd_pjdfstest % fs_dest, io_timeout)
        finally:
            utils_disk.umount(fs_target, fs_dest, 'virtiofs', session=session)
            utils_misc.safe_rmdir(fs_dest, session=session)
Ejemplo n.º 29
0
def run(test, params, env):
    """
    Test virtio-fs by sharing the data between host and guest.
    Steps:
        1. Create shared directories on the host.
        2. Run virtiofsd daemons on the host.
        3. Boot a guest on the host with virtiofs options.
        4. Log into guest then mount the virtiofs targets.
        5. Generate files or run stress on the mount points inside guest.

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    def get_viofs_exe(session):
        """
        Get viofs.exe from virtio win iso,such as E:\viofs\2k19\amd64
        """
        media_type = params["virtio_win_media_type"]
        try:
            get_drive_letter = getattr(virtio_win, "drive_letter_%s" % media_type)
            get_product_dirname = getattr(virtio_win,
                                          "product_dirname_%s" % media_type)
            get_arch_dirname = getattr(virtio_win, "arch_dirname_%s" % media_type)
        except AttributeError:
            test.error("Not supported virtio win media type '%s'", media_type)
        viowin_ltr = get_drive_letter(session)
        if not viowin_ltr:
            test.error("Could not find virtio-win drive in guest")
        guest_name = get_product_dirname(session)
        if not guest_name:
            test.error("Could not get product dirname of the vm")
        guest_arch = get_arch_dirname(session)
        if not guest_arch:
            test.error("Could not get architecture dirname of the vm")

        exe_middle_path = ("{name}\\{arch}" if media_type == "iso"
                           else "{arch}\\{name}").format(name=guest_name,
                                                         arch=guest_arch)
        exe_file_name = "virtiofs.exe"
        exe_find_cmd = 'dir /b /s %s\\%s | findstr "\\%s\\\\"'
        exe_find_cmd %= (viowin_ltr, exe_file_name, exe_middle_path)
        exe_path = session.cmd(exe_find_cmd).strip()
        logging.info("Found exe file '%s'", exe_path)
        return exe_path

    # data io config
    cmd_dd = params.get('cmd_dd')
    cmd_md5 = params.get('cmd_md5')

    # pjdfs test config
    cmd_pjdfstest = params.get('cmd_pjdfstest')
    cmd_unpack = params.get('cmd_unpack')
    cmd_yum_deps = params.get('cmd_yum_deps')
    cmd_autoreconf = params.get('cmd_autoreconf')
    cmd_configure = params.get('cmd_configure')
    cmd_make = params.get('cmd_make')
    pjdfstest_pkg = params.get('pjdfstest_pkg')
    username = params.get('username')
    password = params.get('password')
    port = params.get('file_transfer_port')

    # fio config
    fio_options = params.get('fio_options')
    io_timeout = params.get_numeric('io_timeout')

    os_type = params.get("os_type")
    vm = env.get_vm(params.get("main_vm"))
    vm.verify_alive()
    session = vm.wait_for_login()
    host_addr = vm.get_address()

    if os_type == "windows":
        cmd_timeout = params.get_numeric("cmd_timeout", 120)
        driver_name = params["driver_name"]
        install_path = params["install_path"]
        check_installed_cmd = params["check_installed_cmd"] % install_path

        # Check whether windows driver is running,and enable driver verifier
        session = utils_test.qemu.windrv_check_running_verifier(session,
                                                                vm, test,
                                                                driver_name)
        # install winfsp tool
        error_context.context("Install winfsp for windows guest.",
                              logging.info)
        installed = session.cmd_status(check_installed_cmd) == 0
        if installed:
            logging.info("Winfsp tool is already installed.")
        else:
            install_cmd = utils_misc.set_winutils_letter(session,
                                                         params["install_cmd"])
            session.cmd(install_cmd, cmd_timeout)
            if not utils_misc.wait_for(lambda: not session.cmd_status(
                    check_installed_cmd), 60):
                test.error("Winfsp tool is not installed.")

    for fs in params.objects("filesystems"):
        fs_params = params.object_params(fs)
        fs_target = fs_params.get("fs_target")
        fs_dest = fs_params.get("fs_dest")

        fs_source = fs_params.get("fs_source_dir")
        base_dir = fs_params.get("fs_source_base_dir",
                                 data_dir.get_data_dir())
        if not os.path.isabs(fs_source):
            fs_source = os.path.join(base_dir, fs_source)

        host_data = os.path.join(fs_source, 'fs_test')

        if os_type == "linux":
            error_context.context("Create a destination directory %s "
                                  "inside guest." % fs_dest, logging.info)
            utils_misc.make_dirs(fs_dest, session)

            error_context.context("Mount virtiofs target %s to %s inside"
                                  " guest." % (fs_target, fs_dest),
                                  logging.info)
            utils_disk.mount(fs_target, fs_dest, 'virtiofs', session=session)

        else:
            error_context.context("Start virtiofs service in guest.", logging.info)
            exe_path = get_viofs_exe(session)
            start_vfs_cmd = params["start_vfs_cmd"] % exe_path
            session.sendline(start_vfs_cmd)

            error_context.context("Check if virtiofs service is started.",
                                  logging.info)
            check_virtiofs_cmd = params["check_virtiofs_cmd"]

            if not utils_misc.wait_for(lambda: re.search("virtiofs",
                                                         session.cmd_output(
                                                             check_virtiofs_cmd),
                                                         re.IGNORECASE), 30):
                test.fail("Virtiofs service is failed to start.")

            virtio_fs_disk_label = fs_target
            error_context.context("Get Volume letter of virtio fs target, the disk"
                                  "lable is %s." % virtio_fs_disk_label,
                                  logging.info)
            vol_con = "VolumeName='%s'" % virtio_fs_disk_label
            vol_func = utils_misc.get_win_disk_vol(session, condition=vol_con)
            volume_letter = utils_misc.wait_for(lambda: vol_func, cmd_timeout)
            fs_dest = "%s:" % volume_letter

        guest_file = os.path.join(fs_dest, 'fs_test')
        logging.info("The guest file in shared dir is %s" % guest_file)

        try:
            if cmd_dd:
                logging.info("Creating file under %s inside guest." % fs_dest)
                session.cmd(cmd_dd % guest_file, io_timeout)

                if os_type == "linux":
                    cmd_md5_vm = cmd_md5 % guest_file
                else:
                    guest_file_win = guest_file.replace("/", "\\")
                    cmd_md5_vm = cmd_md5 % (volume_letter, guest_file_win)
                md5_guest = session.cmd_output(cmd_md5_vm, io_timeout).strip().split()[0]

                logging.info(md5_guest)
                md5_host = process.run("md5sum %s" % host_data,
                                       io_timeout).stdout_text.strip().split()[0]
                if md5_guest != md5_host:
                    test.fail('The md5 value of host is not same to guest.')

            if fio_options:
                error_context.context("Run fio on %s." % fs_dest, logging.info)
                fio = generate_instance(params, vm, 'fio')
                try:
                    fio.run(fio_options % guest_file, io_timeout)
                finally:
                    fio.clean()
                vm.verify_dmesg()

            if cmd_pjdfstest:
                error_context.context("Run pjdfstest on %s." % fs_dest, logging.info)
                host_path = os.path.join(data_dir.get_deps_dir('pjdfstest'), pjdfstest_pkg)
                scp_to_remote(host_addr, port, username, password, host_path, fs_dest)
                session.cmd(cmd_unpack.format(fs_dest), 180)
                session.cmd(cmd_yum_deps, 180)
                session.cmd(cmd_autoreconf % fs_dest, 180)
                session.cmd(cmd_configure.format(fs_dest), 180)
                session.cmd(cmd_make % fs_dest, io_timeout)
                session.cmd(cmd_pjdfstest % fs_dest, io_timeout)
        finally:
            if os_type == "linux":
                utils_disk.umount(fs_target, fs_dest, 'virtiofs', session=session)
                utils_misc.safe_rmdir(fs_dest, session=session)
Ejemplo n.º 30
0
def run(test, params, env):
    """
    Run IOzone for linux on a linux guest:
    1) Log into a guest.
    2) Execute the IOzone test.
    :param test: kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def _get_data_disks():
        """ Get the data disks by serial or wwn options. """
        disks = {}
        for data_image in params["images"].split()[1:]:
            extra_params = params.get("blk_extra_params_%s" % data_image, '')
            match = re.search(r"(serial|wwn)=(\w+)", extra_params, re.M)
            if match:
                drive_id = match.group(2)
            else:
                continue
            drive_path = utils_misc.get_linux_drive_path(session, drive_id)
            if not drive_path:
                test.error("Failed to get '%s' drive path" % data_image)
            disks[drive_path[5:]] = data_image
        return disks

    def _get_mounted_points():
        """ Get the mounted points. """
        points = []
        for id in re.finditer(r'(%s\d+)' % did, ' '.join(disks)):
            s = re.search(r'/dev/%s\s+(\S+)\s+' % id.group(1), mount_info, re.M)
            if s:
                points.append(s.group(1))
        return points

    def _wait_for_procs_done(timeout=1800):
        """ Wait all the processes are done. """
        if not utils_misc.wait_for(
                lambda: 'iozone' not in session.cmd_output('pgrep -xl iozone'),
                timeout, step=3.0):
            test.error('Not all iozone processes done in %s sec.' % timeout)

    iozone_test_dir = params.get('iozone_test_dir', '/home')
    iozone_cmd_options = params['iozone_cmd_options']
    iozone_timeout = float(params.get("iozone_timeout", 1800))
    n_partitions = params.get('partitions_num', 1)
    fstype = params.get('fstype', 'xfs')
    labeltype = params.get('labeltype', utils_disk.PARTITION_TABLE_TYPE_GPT)

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login(timeout=float(params.get("login_timeout", 360)))
    _wait_for_procs_done()
    error_context.context("Running IOzone command on guest.")
    try:
        iozone = generate_instance(params, session, 'iozone')
        dids = _get_data_disks()
        if dids:
            mount_info = session.cmd_output_safe('cat /proc/mounts | grep \'/dev/\'')
            disks = utils_disk.get_linux_disks(session, True)
            for did, image_name in dids.items():
                size = params.get('image_size_%s' % image_name)
                start = params.get('image_start_%s' % image_name, "0M")
                mounted_points = _get_mounted_points()
                if not mounted_points:
                    mounted_points = utils_disk.configure_empty_linux_disk(
                        session, did, size, start, n_partitions, fstype, labeltype)
                for mounted_point in mounted_points:
                    iozone.run(iozone_cmd_options % mounted_point, iozone_timeout)
                utils_disk.clean_partition_linux(session, did)
        else:
            iozone.run(iozone_cmd_options % iozone_test_dir, iozone_timeout)
    finally:
        iozone.clean()
        session.close()
Ejemplo n.º 31
0
def run(test, params, env):
    """
    Test usb host device passthrough

    :param test: kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def get_usb_host_dev():
        device_list = []
        for device in vm.devices:
            if isinstance(device, qdevices.QDevice):
                if device.get_param("driver") == "usb-host":
                    device_list.append(device)
        return device_list

    def get_vendorid_productid(bus, addr):
        out = process.getoutput("lsusb -v -s %s:%s" % (bus, addr))
        res = re.search(r"idVendor\s+0x(\w+).*idProduct\s+0x(\w+)", out, re.S)
        return (res.group(1), res.group(2))

    @error_context.context_aware
    def usb_dev_hotplug(dev):
        error_context.context("Hotplug usb-host device", logging.info)
        session.cmd_status("dmesg -c")
        vm.devices.simple_hotplug(dev, vm.monitor)
        session.cmd_status("sleep 2")
        session.cmd_status("udevadm settle")
        messages_add = session.cmd("dmesg")
        for line in messages_add.splitlines():
            logging.debug("[dmesg add] %s", line)
        if messages_add.find(match_add) == -1:
            test.fail("kernel didn't detect plugin")

    @error_context.context_aware
    def usb_dev_verify():
        error_context.context("Check usb device in guest", logging.info)
        session.cmd(lsusb_cmd)

    @error_context.context_aware
    def usb_dev_unplug(dev):
        error_context.context("Unplug usb-host device", logging.info)
        session.cmd("dmesg -c")
        vm.devices.simple_unplug(dev, vm.monitor)
        session.cmd_status("sleep 2")
        messages_del = session.cmd("dmesg -c")
        for line in messages_del.splitlines():
            logging.debug("[dmesg del] %s", line)
        if messages_del.find(match_del) == -1:
            test.fail("kernel didn't detect unplug")

    def _get_usb_mount_point():
        """ Get passthrough usb stick mount point """
        dmesg_cmd = "dmesg | grep 'Attached SCSI removable disk'"
        s, o = session.cmd_status_output(dmesg_cmd)
        if s:
            test.error("Fail to get passthrough usb stick in guest.")
        dev = re.findall(r'\[(sd\w+)\]', o)[0]
        mounts_cmd = "cat /proc/mounts | grep /dev/%s" % dev
        s, o = session.cmd_status_output(mounts_cmd)
        if not s:
            s, o = session.cmd_status_output('umount /dev/%s' % dev)
            if s:
                test.error("Fail to umount /dev/%s, output: %s" % (s, o))
        mkfs_cmd = "mkfs.vfat /dev/%s" % dev
        s, o = session.cmd_status_output(mkfs_cmd)
        if s:
            test.error("Fail to build filesystem on usb stick: %s" % o)
        mount_point = "/mnt"
        s, o = session.cmd_status_output("mount /dev/%s %s" %
                                         (dev, mount_point))
        if s:
            test.error("Fail to mount /dev/%s, output: %s" % (s, o))
        return mount_point

    def _usb_stick_io(mount_point, bg=False):
        """
        Do I/O operations on passthrough usb stick
        """
        error_context.context("Read and write on usb stick ", logging.info)
        testfile = os.path.join(mount_point, 'testfile')
        if bg:
            iozone_cmd = params.get("iozone_cmd_bg", " -az -I -g 1g -f %s")
            iozone_thread = BackgroundTest(iozone_test.run,
                                           (iozone_cmd % testfile, ))
            iozone_thread.start()
            if not utils_misc.wait_for(iozone_thread.is_alive, timeout=10):
                test.fail("Fail to start the iozone background test.")
            time.sleep(10)
        else:
            iozone_cmd = params.get("iozone_cmd",
                                    " -a -I -r 64k -s 1m -i 0 -i 1 -f %s")
            iozone_test.run(iozone_cmd % testfile)

    usb_params = {}

    if params.get("usb_negative_test", "no") != "no":
        # Negative test.
        vm = env.get_vm(params["main_vm"])
        vm.verify_alive()
        session = vm.wait_for_login()
        usb_reply_msg_list = params.get("usb_reply_msg").split(";")
        usb_host_device_list = params["usb_host_device_list"].split(",")
        for dev in usb_host_device_list:
            vid, pid = dev.split(":")
            usb_params["vendorid"] = vid
            usb_params["productid"] = pid
            dev = qdevices.QDevice("usb-host", usb_params)
            try:
                vm.devices.simple_hotplug(dev, vm.monitor)
            except QMPCmdError as detail:
                logging.warn(detail)
                for msg in usb_reply_msg_list:
                    if msg in detail.data['desc']:
                        break
                else:
                    test.fail("Could not get expected warning"
                              " msg in negative test, monitor"
                              " returns: '%s'" % detail)
            else:
                test.fail("Hotplug operation in negative test"
                          " should not succeed.")
        return

    usb_hostdev = params["usb_devices"].split()[-1]
    usb_options = params.get("options")
    if usb_options == "with_vendorid_productid":
        vendorid = params["usbdev_option_vendorid_%s" % usb_hostdev]
        productid = params["usbdev_option_productid_%s" % usb_hostdev]
        usb_params["vendorid"] = "0x%s" % vendorid
        usb_params["productid"] = "0x%s" % productid
    elif usb_options == "with_hostbus_hostaddr":
        hostbus = params["usbdev_option_hostbus_%s" % usb_hostdev]
        hostaddr = params["usbdev_option_hostaddr_%s" % usb_hostdev]
        usb_params["hostbus"] = hostbus
        usb_params["hostaddr"] = hostaddr
        (vendorid, productid) = get_vendorid_productid(hostbus, hostaddr)

    lsusb_cmd = "lsusb -v -d %s:%s" % (vendorid, productid)
    match_add = "New USB device found, "
    match_add += "idVendor=%s, idProduct=%s" % (vendorid, productid)
    match_del = "USB disconnect"
    usb_stick = "Mass Storage" in process.getoutput(lsusb_cmd)

    error_context.context("Log into guest", logging.info)
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    session = vm.wait_for_login()

    try:
        usb_dev_verify()
        if usb_stick:
            iozone_test = None
            mount_point = _get_usb_mount_point()
            iozone_test = generate_instance(params, vm, 'iozone')
            _usb_stick_io(mount_point)
        usb_devs = get_usb_host_dev()
        for dev in usb_devs:
            usb_dev_unplug(dev)

        repeat_times = int(params.get("usb_repeat_times", "1"))
        for i in range(repeat_times):
            msg = "Hotplug (iteration %d)" % (i + 1)
            usb_params["id"] = "usbhostdev%s" % i
            if params.get("usb_check_isobufs", "no") == "yes":
                # The value of isobufs could only be in '4, 8, 16'
                isobufs = (2 << (i % 3 + 1))
                usb_params["isobufs"] = isobufs
                msg += ", with 'isobufs' option set to %d." % isobufs
            error_context.context(msg, logging.info)
            usb_dev = qdevices.QDevice("usb-host", usb_params)
            usb_dev_hotplug(usb_dev)
            usb_dev_verify()
            if usb_stick:
                mount_point = _get_usb_mount_point()
                _usb_stick_io(mount_point, bg=True)
            usb_dev_unplug(usb_dev)
    finally:
        if usb_stick and iozone_test:
            iozone_test.clean()
        session.close()
def run(test, params, env):
    """
    Test hotplug of block devices.

    1) Boot up a guest with a system disk and a data disk.
    2) Do IO stress test on data disk.
    3) Unplug data disk during io stress.
    4) Reboot guest.

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def _check_stress_status():
        """ Check the status of stress. """
        ck_session = vm.wait_for_login(timeout=360)
        proc_name = check_cmd[os_type].split()[-1]
        cmd = check_cmd[os_type]
        if not utils_misc.wait_for(lambda: proc_name.lower() in ck_session.
                                   cmd_output(cmd).lower(),
                                   180,
                                   step=3.0):
            test.fail("%s is not alive!" % proc_name)
        ck_session.close()

    def _get_data_disk():
        """ Get the data disk. """
        extra_params = params["blk_extra_params_%s" %
                              params['images'].split()[-1]]
        if windows:
            return sorted(
                session.cmd('wmic diskdrive get index').split()[1:])[-1]
        drive_id = re.search(r"(serial|wwn)=(\w+)", extra_params,
                             re.M).group(2)
        return utils_misc.get_linux_drive_path(session, drive_id)

    def _run_stress_background():
        """ Run stress under background. """
        logging.info("Start io stress under background.")
        thread = utils_misc.InterruptedThread(target[os_type]['name'],
                                              (target[os_type]['args'], ))
        thread.start()
        _check_stress_status()
        return thread

    check_cmd = {
        'linux': 'pgrep -lx dd',
        'windows': 'TASKLIST /FI "IMAGENAME eq IOZONE.EXE'
    }
    os_type = params['os_type']
    args = params['stress_args']
    windows = os_type == 'windows'
    target = {}
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=360)
    disk = _get_data_disk()
    if windows:
        iozone = generate_instance(params, vm, 'iozone')
        utils_disk.update_windows_disk_attributes(session, disk)
        disk_letter = utils_disk.configure_empty_disk(
            session, disk, params['image_size_stg0'], os_type)[0]
        target[os_type] = {
            'name': iozone.run,
            'args': args.format(disk_letter)
        }
    else:
        target[os_type] = {'name': session.cmd, 'args': args.format(disk)}

    stress_thread = _run_stress_background()
    time.sleep(float(params['sleep_time']))
    _check_stress_status()
    BlockDevicesPlug(vm).unplug_devs_serial()
    stress_thread.join(suppress_exception=True)
    session.close()
    vm.monitor.system_reset()
    logging.info('Login guest after reboot.')
    session = vm.wait_for_login(timeout=360)
def run(test, params, env):

    """
    Special hardware test case.
    FC host: ibm-x3650m4-05.lab.eng.pek2.redhat.com
    Disk serial name: scsi-360050763008084e6e0000000000001a4
    # multipath -ll
    mpathb (360050763008084e6e0000000000001a8) dm-4 IBM,2145
    size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
    |-+- policy='service-time 0' prio=50 status=active
    | `- 2:0:1:0 sde 8:64 active ready running
    `-+- policy='service-time 0' prio=10 status=enabled
      `- 2:0:0:0 sdd 8:48 active ready running
    mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
    size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
    |-+- policy='service-time 0' prio=50 status=active
    | `- 1:0:1:0 sdc 8:32 active ready running
    `-+- policy='service-time 0' prio=10 status=enabled
      `- 1:0:0:0 sdb 8:16 active ready running
    Customer Bug ID: 1720047  1753992

    format passthrough disk and do iozone test on it.

    1) pass-through /dev/sdb
    2) format it and do iozone test
    3) pass-through /dev/sg1
    4) format it and do iozone test
    5) pass-through /dev/mapper/mpatha
    6) format it and do iozone test

    :param test: kvm test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """

    def get_multipath_disks(mpath_name="mpatha"):

        """
        Get all disks of multiple paths.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16  active ready running

        :param mpath_name: multi-path name.
        :return: a list. if get disks successfully or raise a error
        """
        disks = []
        disk_str = []
        outputs = process.run("multipath -ll", shell=True).stdout.decode()
        outputs = outputs.split(mpath_name)[-1]
        disk_str.append("active ready running")
        disk_str.append("active faulty offline")
        disk_str.append("failed faulty offline")
        for line in outputs.splitlines():
            if disk_str[0] in line or disk_str[1] in line or disk_str[2] in line:
                disks.append(line.split()[-5])
        if not disks:
            test.fail("Failed to get disks by 'multipath -ll'")
        else:
            return disks

    def get_multipath_disks_status(mpath_name="mpatha"):

        """
        Get status of multiple paths.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16  active ready running

        :param mpath_name: multi-path name.
        :return: a list. if get status successfully or raise a error
        """
        disks = get_multipath_disks(mpath_name)
        disks_status = []
        outputs = process.run("multipath -ll", shell=True).stdout.decode()
        outputs = outputs.split(mpath_name)[-1]
        for line in outputs.splitlines():
            for i in range(len(disks)):
                if disks[i] in line:
                    disks_status.append(line.strip().split()[-1])
                    break
        if not disks_status or len(disks_status) != len(disks):
            test.fail("Failed to get disks status by 'multipath -ll'")
        else:
            return disks_status

    def compare_multipath_status(status, mpath_name="mpatha"):

        """
        Compare status whether equal to the given status.
        This function just focus on all paths are running or all are offline.

        :param status: the state of disks.
        :param mpath_name: multi-path name.
        :return: True, if equal to the given status or False
        """
        status_list = get_multipath_disks_status(mpath_name)
        if len(set(status_list)) == 1 and status_list[0] == status:
            return True
        else:
            return False

    def set_disk_status_to_online_offline(disk, status):

        """
        set disk state to online/offline.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16 failed faulty offline

        :param disk: disk name.
        :param status: the state of disk.
        :return: by default
        """
        error_context.context("Set disk '%s' to status '%s'."
                              % (disk, status), logging.info)
        process.run("echo %s >  /sys/block/%s/device/state"
                    % (status, disk), shell=True)

    def set_multipath_disks_status(disks, status):

        """
        set multiple paths to same status. all disks online or offline.
        multipath like below:
        mpatha (360050763008084e6e0000000000001a4) dm-3 IBM,2145
        size=100G features='1 queue_if_no_path' hwhandler='1 alua' wp=rw
        |-+- policy='service-time 0' prio=50 status=active
        | `- 1:0:1:0 sdc 8:32  active ready running
        `-+- policy='service-time 0' prio=10 status=enabled
          `- 1:0:0:0 sdb 8:16 failed faulty offline

        :param disks: disk list.
        :param status: the state of disk. online/offline
        :return: by default
        """
        for disk in disks:
            set_disk_status_to_online_offline(disk, status)
        wait.wait_for(lambda: compare_multipath_status(status),
                      first=2, step=1.5, timeout=60)

    def _do_post_cmd(session):
        """
        do post command after test.

        :param session: A shell session object.
        :return: by default
        """
        cmd = params.get("post_cmd")
        if cmd:
            session.cmd_status_output(cmd)
        session.close()

    def get_disk_by_sg_map(image_name_stg):
        """
        get disk name by sg_map.

        :param image_name_stg: linux sg. e.g. /dev/sg1
        :return: disk name. e.g. sdb
        """
        outputs = process.run("sg_map", shell=True).stdout.decode().splitlines()
        for output in outputs:
            if image_name_stg in output:
                return output.strip().split()[-1].split("/")[-1]

    def _get_windows_disks_index(session, image_size):
        """
        Get all disks index which show in 'diskpart list disk'.
        except for system disk.
        in diskpart: if disk size < 8GB: it displays as MB
                     else: it displays as GB

        :param session: session object to guest.
        :param image_size: image size. e.g. 40M
        :return: a list with all disks index except for system disk.
        """
        disk = "disk_" + ''.join(random.sample(string.ascii_letters + string.digits, 4))
        disk_indexs = []
        list_disk_cmd = "echo list disk > " + disk
        list_disk_cmd += " && echo exit >> " + disk
        list_disk_cmd += " && diskpart /s " + disk
        list_disk_cmd += " && del /f " + disk
        disks = session.cmd_output(list_disk_cmd)
        size_type = image_size[-1] + "B"
        if size_type == "MB":
            disk_size = image_size[:-1] + " MB"
        elif size_type == "GB" and int(image_size[:-1]) < 8:
            disk_size = str(int(image_size[:-1]) * 1024) + " MB"
        else:
            disk_size = image_size[:-1] + " GB"
        regex_str = 'Disk (\d+).*?%s' % disk_size
        for disk in disks.splitlines():
            if disk.startswith("  Disk"):
                o = re.findall(regex_str, disk, re.I | re.M)
                if o:
                    disk_indexs.append(o[0])
        return disk_indexs

    def delete_partition_on_host(did):
        """
        Delete partitions on the given disk.

        :param did: disk ID. disk kname. e.g. 'sdb', 'nvme0n1'
        :return: by default.
        """
        # process.run("partprobe /dev/%s" % did, shell=True)
        list_disk_cmd = "lsblk -o KNAME,MOUNTPOINT"
        output = process.run(list_disk_cmd, shell=True).stdout.decode()
        regex_str = did + "\w*(\d+)"
        rm_cmd = 'parted -s "/dev/%s" rm %s'
        for line in output.splitlines():
            partition = re.findall(regex_str, line, re.I | re.M)
            if partition:
                if "/" in line.split()[-1]:
                    process.run("umount %s" % line.split()[-1], shell=True)
        list_partition_number = "parted -s /dev/%s print|awk '/^ / {print $1}'"
        partition_numbers = process.run(list_partition_number % did,
                                        shell=True).stdout.decode()
        ignore_err_msg = "unrecognised disk label"
        if ignore_err_msg in partition_numbers:
            logging.info("no partition to delete on %s" % did)
        else:
            partition_numbers = partition_numbers.splitlines()
            for number in partition_numbers:
                logging.info("remove partition %s on %s" % (number, did))
                process.run(rm_cmd % (did, number), shell=True)
            process.run("partprobe /dev/%s" % did, shell=True)

    def delete_multipath_partition_on_host(mpath_name="mpatha"):
        """
        Delete partitions on the given multipath.

        :param mpath_name: multi-path name.
        :return: by default.
        """
        # process.run("partprobe /dev/mapper/%s" % mpath_name, shell=True)
        output = process.run("lsblk", shell=True).stdout.decode()
        mpath_dict = {}
        pattern = r'%s(\d+)' % mpath_name
        rm_cmd = 'parted -s "/dev/mapper/%s" rm %s'
        for line in output.splitlines():
            for part_num in re.findall(pattern, line, re.I | re.M):
                if part_num not in mpath_dict.keys():
                    mpath_dict[part_num] = line.split()[-1]
        for key, value in mpath_dict.items():
            if "/" in value:
                process.run("umount %s" % value, shell=True)
            logging.info("remove partition %s on %s" % (key, mpath_name))
            process.run(rm_cmd % (mpath_name, key), shell=True)
        output = process.run("dmsetup ls", shell=True).stdout.decode()
        for line in output.splitlines():
            for key in mpath_dict.keys():
                if (mpath_name + key) in line:
                    process.run("dmsetup remove %s%s" % (mpath_name, key),
                                shell=True)
        process.run("partprobe /dev/mapper/%s" % mpath_name, shell=True)

    def clean_partition_on_host(mpath_name="mpatha"):
        """
        Delete partitions on multi-path disks.

        :param mpath_name: multi-path name.
        :return: by default
        """
        delete_multipath_partition_on_host(mpath_name)
        disks = get_multipath_disks(mpath_name)
        for disk in disks:
            delete_partition_on_host(disk)

    error_context.context("Get FC host name:", logging.info)
    hostname = process.run("hostname", shell=True).stdout.decode().strip()
    if hostname != params["special_host"]:
        test.cancel("The special host is not '%s', cancel the test."
                    % params["special_host"])
    error_context.context("Get FC disk serial name:", logging.info)
    stg_serial_name = params["stg_serial_name"]
    image_name_stg = params["image_name_stg"].split("/")[-1]
    if "mpath" not in image_name_stg:
        if "sg" in image_name_stg:
            image_name_stg = get_disk_by_sg_map(image_name_stg)
            if not image_name_stg:
                test.cancel("Failed to get disk by sg_map,"
                            " output is '%s'" % image_name_stg)
        query_cmd = "udevadm info -q property -p /sys/block/%s" % image_name_stg
        outputs = process.run(query_cmd, shell=True).stdout.decode().splitlines()
        for output in outputs:
            # ID_SERIAL=360050763008084e6e0000000000001a4
            if stg_serial_name in output and output.startswith("ID_SERIAL="):
                break
        else:
            test.cancel("The special disk is not '%s', cancel the test."
                        % stg_serial_name)
    else:
        outputs = process.run("multipath -ll", shell=True).stdout.decode().splitlines()
        for output in outputs:
            if stg_serial_name in output and image_name_stg in output:
                break
        else:
            test.cancel("The special disk is not '%s', cancel the test."
                        % stg_serial_name)
        mpath_name = image_name_stg
        multi_disks = get_multipath_disks(mpath_name)
        error_context.context("Get all disks for '%s': %s"
                              % (mpath_name, multi_disks), logging.info)
        error_context.context("Verify all paths are running for %s before "
                              "start vm." % mpath_name, logging.info)
        if compare_multipath_status("running", mpath_name):
            logging.info("All paths are running for %s." % mpath_name)
        else:
            logging.info("Not all paths are running for %s, set "
                         "them to running." % mpath_name)
            set_multipath_disks_status(multi_disks, "running")
    error_context.context("Delete partitions on host before testing.",
                          logging.info)
    clean_partition_on_host(params["mpath_name"])
    vm = env.get_vm(params["main_vm"])
    try:
        vm.create(params=params)
    except Exception as e:
        test.error("failed to create VM: %s" % six.text_type(e))
    session = vm.wait_for_login(timeout=int(params.get("timeout", 240)))
    file_system = [_.strip() for _ in params["file_system"].split()]
    labeltype = params.get("labeltype", "gpt")
    iozone_target_num = int(params.get('iozone_target_num', '5'))
    iozone_options = params.get('iozone_options')
    iozone_timeout = float(params.get('iozone_timeout', '7200'))
    image_num_stg = int(params["image_num_stg"])
    image_size_stg = params["image_size_stg"]
    ostype = params["os_type"]
    try:
        if ostype == "windows":
            error_context.context("Get windows disk index that to "
                                  "be formatted", logging.info)
            # disks = utils_disk.get_windows_disks_index(session, image_size_stg)
            disks = _get_windows_disks_index(session, image_size_stg)
            if len(disks) != image_num_stg:
                test.fail("Failed to list all disks by image size. The expected "
                          "is %s, actual is %s" % (image_num_stg, len(disks)))
            error_context.context("Clear readonly for all disks and online "
                                  "them in windows guest.", logging.info)
            if not utils_disk.update_windows_disk_attributes(session, disks):
                test.fail("Failed to update windows disk attributes.")
        else:
            error_context.context("Get linux disk that to be "
                                  "formatted", logging.info)
            disks = sorted(utils_disk.get_linux_disks(session).keys())
            if len(disks) != image_num_stg:
                test.fail("Failed to list all disks by image size. The expected "
                          "is %s, actual is %s" % (image_num_stg, len(disks)))
            # logging.info("Get data disk by serial name: '%s'" % stg_serial_name)
            # drive_path = utils_misc.get_linux_drive_path(session, stg_serial_name)
            # if not drive_path:
            #     test.fail("Failed to get data disk by serial name: %s"
            #               % stg_serial_name)
    except Exception:
        _do_post_cmd(session)
        raise
    if iozone_options:
        iozone = generate_instance(params, vm, 'iozone')
    try:
        error_context.context("Make sure guest is running before test",
                              logging.info)
        vm.resume()
        vm.verify_status("running")
        for n, disk in enumerate(disks):
            error_context.context("Format disk in guest: '%s'" % disk,
                                  logging.info)
            # Random select one file system from file_system
            index = random.randint(0, (len(file_system) - 1))
            fstype = file_system[index].strip()
            partitions = utils_disk.configure_empty_disk(
                session, disk, image_size_stg, ostype,
                fstype=fstype, labeltype=labeltype)
            if not partitions:
                test.fail("Fail to format disks.")
            for partition in partitions:
                if iozone_options and n < iozone_target_num:
                    iozone.run(iozone_options.format(partition), iozone_timeout)
        error_context.context("Reboot guest after format disk "
                              "and iozone test.", logging.info)
        session = vm.reboot(session=session, timeout=int(params.get("timeout", 240)))
        error_context.context("Shutting down guest after reboot it.", logging.info)
        vm.graceful_shutdown(timeout=int(params.get("timeout", 240)))
        if vm.is_alive():
            test.fail("Fail to shut down guest.")
        error_context.context("Start the guest again.", logging.info)
        vm = env.get_vm(params["main_vm"])
        vm.create(params=params)
        session = vm.wait_for_login(timeout=int(params.get("timeout", 240)))
        error_context.context("Delete partitions in guest.", logging.info)
        for disk in disks:
            utils_disk.clean_partition(session, disk, ostype)
        error_context.context("Inform the OS of partition table changes "
                              "after testing.", logging.info)
        if "sg1" in params["image_name_stg"]:
            image_name_stg = get_disk_by_sg_map(params["image_name_stg"])
            process.run("partprobe /dev/%s" % image_name_stg, shell=True)
        else:
            process.run("partprobe %s" % params["image_name_stg"], shell=True)
    finally:
        if iozone_options:
            iozone.clean()
        _do_post_cmd(session)