Beispiel #1
0
def run(test, params, env):
    """
    cpuinfo query test:
    1). run query cmd. e.g -cpu ?cpuid
    2). check the expected info is inclued in the cmd output.
    3). raise error if defined info is missing.
    """
    qemu_binary = utils_misc.get_qemu_binary(params)

    error.context("run query cmd")
    qcmd = params.get("query_cmd")
    if qcmd is None:
        raise error.TestError("query cmd is missing,"
                              "pls check query_cmd in config file")
    cmd = qemu_binary + qcmd
    output = utils.system_output(cmd)

    error.context("check if expected info is included in output of %s " % cmd)
    cpuinfos = params.get("cpu_info", "Conroe").split(",")
    missing = []
    for cpuinfo in cpuinfos:
        if cpuinfo not in output:
            missing.append(cpuinfo)
    if missing:
        raise error.TestFail("%s is missing in the output\n %s" %
                             (", ".join(missing), output))
Beispiel #2
0
    def check_watchdog_support():
        """
        check the host qemu-kvm support watchdog device
        Test Step:
        1. Send qemu command 'qemu -watchdog ?'
        2. Check the watchdog type that the host support.
        """
        qemu_binary = utils_misc.get_qemu_binary(params)

        watchdog_type_check = params.get(
            "watchdog_type_check", " -watchdog '?'")
        qemu_cmd = qemu_binary + watchdog_type_check

        # check the host support watchdog types.
        error_context.context("Checking whether or not the host support"
                              " WDT '%s'" % watchdog_device_type, logging.info)
        watchdog_device = process.system_output("%s 2>&1" % qemu_cmd,
                                                shell=True).decode()
        if watchdog_device:
            if re.findall(watchdog_device_type, watchdog_device, re.I):
                logging.info("The host support '%s' type watchdog device" %
                             watchdog_device_type)
            else:
                logging.info("The host support watchdog device type is: '%s'"
                             % watchdog_device)
                test.cancel("watdog %s isn't supported" % watchdog_device_type)
        else:
            test.cancel("No watchdog device supported by the host!")
Beispiel #3
0
    def check_watchdog_support():
        """
        check the host qemu-kvm support watchdog device
        Test Step:
        1. Send qemu command 'qemu -watchdog ?'
        2. Check the watchdog type that the host support.
        """
        qemu_binary = utils_misc.get_qemu_binary(params)

        watchdog_type_check = params.get(
            "watchdog_type_check", " -watchdog '?'")
        qemu_cmd = qemu_binary + watchdog_type_check

        # check the host support watchdog types.
        error.context("Checking whether or not the host support WDT '%s'"
                      % watchdog_device_type, logging.info)
        watchdog_device = utils.system_output("%s 2>&1" % qemu_cmd,
                                              retain_output=True)
        if watchdog_device:
            if re.findall(watchdog_device_type, watchdog_device, re.I):
                logging.info("The host support '%s' type watchdog device" %
                             watchdog_device_type)
            else:
                raise error.TestFail("Host not support watchdog device type %s "
                                     % watchdog_device_type)
                logging.info("The host support watchdog device type is: '%s'"
                             % watchdog_device)
        else:
            raise error.TestFail("No watchdog device support in the host!")
Beispiel #4
0
def run(test, params, env):
    """
    Boot latest cpu model on old host

    :param test: QEMU test object.
    :param params: Dictionary with test parameters.
    :param env: Dictionary with the test environment.
    """
    def start_with_model(test_model):
        """
        Start vm with tested model
        :param test_model: The model been tested
        """
        vm = None
        params['cpu_model'] = test_model
        logging.info('Start vm with cpu model %s' % test_model)
        try:
            env_process.preprocess_vm(test, params, env, vm_name)
            vm = env.get_vm(vm_name)
            output = vm.process.get_output()
            if warning_text not in output:
                test.fail("Qemu should output warning for lack flags"
                          " while it does not.")
        except Exception as e:
            if boot_expected == 'no':
                logging.info('Expect vm boot up failed when enforce is set.')
                if warning_text not in str(e):
                    raise
            else:
                raise
        else:
            if boot_expected == 'no':
                test.fail('The vm should not boot successfully'
                          ' when cpu enforce mode is on')
        finally:
            if vm and vm.is_alive():
                vm.verify_kernel_crash()
                vm.destroy()

    fd = open("/proc/cpuinfo")
    cpu_info = fd.read()
    fd.close()
    vendor = cpu.get_cpu_vendor(cpu_info)
    cpu_model_list = cpu.CPU_TYPES.get(vendor)
    latest_cpu_model = cpu_model_list[-1]
    for cpu_model in cpu_model_list:
        qemu_binary = utils_misc.get_qemu_binary(params)
        if cpu_model in cpu.get_qemu_cpu_models(qemu_binary):
            latest_cpu_model = cpu_model
            break

    host_cpu_model = cpu.get_qemu_best_cpu_model(params)
    if host_cpu_model.startswith(latest_cpu_model):
        test.cancel('The host cpu is not old enough for this test.')

    vm_name = params['main_vm']
    warning_text = params.get('warning_text')
    boot_expected = params.get('boot_expected', 'yes')
    params['start_vm'] = 'yes'
    start_with_model(latest_cpu_model)
Beispiel #5
0
    def run_test(qemu_src_dir):
        """
        run QEMU I/O test suite

        :qemu_src_dir: path of qemu source code
        """
        iotests_root = params.get("iotests_root", "tests/qemu-iotests")
        extra_options = params.get("qemu_io_extra_options", "")
        image_format = params.get("qemu_io_image_format")
        result_pattern = params.get("iotests_result_pattern")
        error_context.context("running qemu-iotests for image format %s"
                              % image_format, logging.info)
        os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params)
        os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params)
        os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params)
        os.environ["QEMU_NBD_PROG"] = utils_misc.get_binary('qemu-nbd', params)
        os.chdir(os.path.join(qemu_src_dir, iotests_root))
        cmd = './check'
        if extra_options:
            cmd += " %s" % extra_options
        cmd += " -%s" % image_format
        output = process.system_output(cmd, ignore_status=True, shell=True)
        match = re.search(result_pattern, output, re.I | re.M)
        if match:
            iotests_log_file = "qemu_iotests_%s.log" % image_format
            iotests_log_file = utils_misc.get_path(test.debugdir, iotests_log_file)
            with open(iotests_log_file, 'w+') as log:
                log.write(output)
                log.flush()
            msg = "Total test %s cases, %s failed"
            raise exceptions.TestFail(msg % (match.group(2), match.group(1)))
Beispiel #6
0
def run_cpuinfo_query(test, params, env):
    """
    cpuinfo query test:
    1). run query cmd. e.g -cpu ?cpuid
    2). check the expected info is inclued in the cmd output.
    3). raise error if defined info is missing.
    """
    qemu_binary = utils_misc.get_qemu_binary(params)

    error.context("run query cmd")
    qcmd = params.get("query_cmd")
    if qcmd is None:
        raise error.TestError("query cmd is missing,"
                              "pls check query_cmd in config file")
    cmd = qemu_binary + qcmd
    output = utils.system_output(cmd)

    error.context("check if expected info is included in output of %s " % cmd)
    cpuinfos = params.get("cpu_info", "Conroe").split(",")
    missing = []
    for cpuinfo in cpuinfos:
        if not cpuinfo in output:
            missing.append(cpuinfo)
    if missing:
        raise error.TestFail("%s is missing in the output\n %s" %
                             (", ".join(missing), output))
Beispiel #7
0
 def wait_mirror_jobs_done(self):
     qemu_binary = utils_misc.get_qemu_binary(self.params)
     qemu_version = utils_qemu.get_qemu_version(qemu_binary)[0]
     required_qemu_version = self.params["required_qemu_version"]
     if qemu_version in VersionInterval(required_qemu_version):
         self.wait_mirror_jobs_cancelled()
     else:
         self.wait_mirror_jobs_auto_completed()
Beispiel #8
0
def run(test, params, env):
    """
    KVM Seabios bin file test:
    1) Get available bin files
    2) Get supported machine types
    3) Check bin file in use

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

    bin_dict = {
        'rhel6': 'bios.bin',
        'rhel7': 'bios-256k.bin',
        'rhel8': 'bios-256k.bin',
        '4.2': 'bios-256k.bin',
        '2.11': 'bios-256k.bin'
    }

    error_context.context("Get available bin files", logging.info)
    output = process.system_output('ls /usr/share/seabios',
                                   shell=True).decode()
    bin_file_skip = params.get("bin_file_skip", "")
    for value in bin_dict.values():
        if value not in output and value != bin_file_skip:
            test.fail("%s is not available" % value)

    error_context.context("Get supported machine types", logging.info)
    qemu_binary = utils_misc.get_qemu_binary(params)
    machine_type_cmd = qemu_binary + " -machine help | awk '{ print $1 }'"
    output = process.system_output(machine_type_cmd, shell=True).decode()
    machine_types = output.splitlines()
    machine_type_remove = params['machine_type_remove'].split()
    for i in machine_type_remove:
        machine_types.remove(i)
    logging.info(machine_types)

    for machine in machine_types:
        error_context.context("Check bin file with machine type: %s" % machine,
                              logging.info)
        for key in bin_dict:
            if key in machine:
                bin_file = bin_dict[key]
                break
        else:
            test.error("Uncertain which bin file in use for machine type: %s" %
                       machine)

        params['machine_type'] = machine
        params['start_vm'] = 'yes'
        env_process.preprocess_vm(test, params, env, params.get("main_vm"))
        vm = env.get_vm(params["main_vm"])
        info_roms = vm.monitor.info("roms")
        if bin_file not in info_roms:
            test.fail("Checking bin file fails with %s, info roms: %s" %
                      (machine, info_roms))
        vm.destroy()
Beispiel #9
0
def get_qemu_version(params, target):
    """Get installed QEMU version."""
    LOG_JOB.debug("check QEMU version")
    qemu_binary = utils_misc.get_qemu_binary(params)
    cmd = "%s --version" % qemu_binary
    line = process.run(cmd).stdout_text.splitlines()[0]
    version = line.split()[-1].strip("()")
    LOG_JOB.debug("QEMU version: %s", version)
    target.send(version)
Beispiel #10
0
def run(test, params, env):
    """
    QEMU support options check test

    Test Step:
        1) Get qemu support device options
        2) Check whether qemu have output

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    def get_qemu_support_device(qemu_binary):
        """
        Get qemu support device list
        """
        support_device = process.system_output("%s -device ? 2>&1" %
                                               qemu_binary,
                                               timeout=10,
                                               ignore_status=True,
                                               shell=True)
        if not support_device:
            test.cancel("Can not get qemu support device list")
        device_list = re.findall(r'name\s+"(.*)",', support_device)
        device_list_alias = re.findall(r'alias\s+"(.*?)"', support_device)
        device_list.extend(device_list_alias)
        return device_list

    def get_device_option(qemu_binary, device_name):
        """
        Get qemu device 'device_name' support options
        """
        if device_name not in get_qemu_support_device(qemu_binary):
            err_msg = "Oops, Your qemu version doesn't support devic '%s', "
            err_msg += "make sure you have inputted a correct device name"
            test.cancel(err_msg % device_name)
        device_support_option = process.run("%s -device %s,? 2>&1" %
                                            (qemu_binary, device_name),
                                            timeout=10,
                                            ignore_status=True,
                                            shell=True)
        if device_support_option.exit_status:
            test.error("Oops, output status is wrong")
        if not re.findall(r"%s\.(.*)=(.*)" % device_name,
                          device_support_option.stdout):
            test.fail("Qemu option check Failed")
        logging.info("Qemu options check successful. output is:\n%s" %
                     device_support_option.stdout)

    device_name = params.get("device_name")
    qemu_binary = utils_misc.get_qemu_binary(params)

    error_context.context("Get qemu support %s device options" % device_name,
                          logging.info)
    get_device_option(qemu_binary, device_name)
def run(test, params, env):
    """
    boot with different machine type:
    1) get supported machine type
    2) boot guest with different machine types

    :param test: kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    error_context.context("Get supported machine type", logging.info)
    qemu_binary = utils_misc.get_qemu_binary(params)
    machine_types = []
    machine_type_mapping = {
        "pc": ["i440FX", "RHEL 6"],
        "q35": ["Q35"],
        "pseries": ["pSeries"],
        "arm64-pci:virt": ["ARM"],
        "arm64-mmio:virt": ["ARM"],
        "s390-ccw-virtio": ["S390"]
    }
    for m_type, s_name in zip(
            *utils_misc.get_support_machine_type(qemu_binary)[:2]):
        for item in machine_type_mapping[params["machine_type"]]:
            if item in s_name:
                if "arm64" in params["machine_type"]:
                    m_type = re.sub(r'(?<=:)\w+', m_type,
                                    params["machine_type"])
                machine_types.append(m_type)
    if not machine_types:
        test.fail("Failed to get machine types")
    else:
        logging.info("Actual supported machine types are: %s",
                     ', '.join(map(str, machine_types)))

        for m_type in machine_types:
            params["machine_type"] = m_type
            params["start_vm"] = "yes"
            vm_name = params['main_vm']
            error_context.context("Start vm with machine type '%s'" % m_type,
                                  logging.info)
            env_process.preprocess(test, params, env)
            vm = env.get_vm(vm_name)
            vm.verify_alive()
            timeout = int(params.get("login_timeout", 360))
            session = vm.wait_for_login(timeout=timeout)
            if not session.is_responsive():
                session.close()
                test.fail("Start vm with machine type:%s fail" % m_type)

            session.close()
            error_context.context(
                "Quit guest and check the process quit normally", logging.info)
            vm.destroy(gracefully=False)
Beispiel #12
0
def run_qemu_option_check(test, params, env):
    """
    QEMU support options check test

    Test Step:
        1) Get qemu support device options
        2) Check whether qemu have output

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    def get_qemu_support_device(qemu_binary):
        """
        Get qemu support device list
        """
        support_device = utils.system_output("%s -device ? 2>&1"
                                              % qemu_binary, timeout=10,
                                              ignore_status=True)
        if not support_device:
            raise error.TestNAError("Can not get qemu support device list")
        device_list = re.findall(r'name\s+"(.*)",', support_device)
        device_list_alias = re.findall(r'alias\s+"(.*?)"', support_device)
        device_list.extend(device_list_alias)
        return device_list


    def get_device_option(qemu_binary, device_name):
        """
        Get qemu device 'device_name' support options
        """
        if device_name not in get_qemu_support_device(qemu_binary):
            err_msg = "Oops, Your qemu version doesn't support devic '%s', "
            err_msg += "make sure you have inputted a correct device name"
            raise error.TestNAError(err_msg % device_name)
        device_support_option = utils.run("%s -device %s,? 2>&1" %
                                          (qemu_binary, device_name),
                                           timeout=10,
                                           ignore_status=True)
        if device_support_option.exit_status:
            raise error.TestError("Oops, output status is wrong")
        if not re.findall(r"%s\.(.*)=(.*)" % device_name,
                          device_support_option.stdout):
            raise error.TestFail("Qemu option check Failed")
        logging.info("Qemu options check successfull. output is:\n%s" %
                     device_support_option.stdout)


    device_name = params.get("device_name")
    qemu_binary = utils_misc.get_qemu_binary(params)

    error.context("Get qemu support %s device options" % device_name,
                  logging.info)
    get_device_option(qemu_binary, device_name)
Beispiel #13
0
def run(test, params, env):
    """
    KVM Seabios bin file test:
    1) Get available bin files
    2) Get supported machine types
    3) Check bin file in use

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

    bin_dict = {'rhel6': 'bios.bin', 'rhel7': 'bios-256k.bin'}

    error_context.context("Get available bin files", logging.info)
    output = process.system_output('ls /usr/share/seabios', shell=True).decode()
    for value in bin_dict.values():
        if value not in output:
            test.fail("%s is not available" % value)

    error_context.context("Get supported machine types", logging.info)
    qemu_binary = utils_misc.get_qemu_binary(params)
    machine_type_cmd = qemu_binary + " -machine help | awk '{ print $1 }'"
    output = process.system_output(machine_type_cmd, shell=True).decode()
    machine_types = output.splitlines()
    machine_type_remove = params['machine_type_remove'].split()
    for i in machine_type_remove:
        machine_types.remove(i)
    logging.info(machine_types)

    for machine in machine_types:
        error_context.context("Check bin file with machine type: %s" % machine,
                              logging.info)
        for key in bin_dict:
            if key in machine:
                bin_file = bin_dict[key]
                break
        else:
            test.error("Uncertain which bin file in use for machine type: %s"
                       % machine)

        params['machine_type'] = machine
        params['start_vm'] = 'yes'
        env_process.preprocess_vm(test, params, env, params.get("main_vm"))
        vm = env.get_vm(params["main_vm"])
        info_roms = vm.monitor.info("roms")
        if bin_file not in info_roms:
            test.fail("Checking bin file fails with %s, info roms: %s"
                      % (machine, info_roms))
        vm.destroy()
Beispiel #14
0
 def get_all_support_flags():
     """
     Get all supported flags with qemu query cmd.
     """
     qemu_binary = utils_misc.get_qemu_binary(params)
     cmd = qemu_binary + params.get("query_cmd", " -cpu ?")
     output = utils.system_output(cmd)
     flags_re = re.compile(params.get("pattern", "flags:(.*)"))
     flag_list = flags_re.search(output)
     flags = []
     if flag_list:
         for flag in flag_list.groups():
             flags += flag
     return set(map(utils_misc.Flag, flags))
Beispiel #15
0
def run(test, params, env):
    """
    Runs CPU negative test:

    1. Launch qemu with improper cpu configuration
    2. Verify qemu failed to start

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

    enforce_flag = params.get('enforce_flag')
    if enforce_flag and 'CPU_MODEL' in params['wrong_cmd']:
        if enforce_flag in cpu.get_host_cpu_models():
            test.cancel('This case only test on the host without the flag'
                        ' %s.' % enforce_flag)
        cpu_model = cpu.get_qemu_best_cpu_model(params)
        params['wrong_cmd'] = params['wrong_cmd'].replace(
            'CPU_MODEL', cpu_model)

    qemu_bin = utils_misc.get_qemu_binary(params)
    if 'OUT_OF_RANGE' in params['wrong_cmd']:
        machine_type = params['machine_type'].split(':')[-1]
        m_types = utils_qemu.get_machines_info(qemu_bin)[machine_type]
        m_type = re.search(r'\(alias of (\S+)\)', m_types)[1]
        max_value = utils_qemu.get_maxcpus_hard_limit(qemu_bin, m_type)
        smp = str(max_value + 1)
        params['wrong_cmd'] = params['wrong_cmd'].replace(
            'MACHINE_TYPE', machine_type).replace('OUT_OF_RANGE', smp)
        msg = params['warning_msg'].replace('SMP_VALUE', smp).replace(
            'MAX_VALUE', str(max_value)).replace('MACHINE_TYPE', m_type)
        params['warning_msg'] = msg

    warning_msg = params['warning_msg']
    wrong_cmd = '%s %s' % (qemu_bin, params['wrong_cmd'])
    logging.info('Start qemu with command: %s', wrong_cmd)
    status, output = process.getstatusoutput(wrong_cmd)
    logging.info('Qemu prompt output:\n%s', output)
    if status == 0:
        test.fail('Qemu guest boots up while it should not.')
    if warning_msg not in output:
        test.fail('Does not get expected warning message.')
    else:
        logging.info('Test passed as qemu does not boot up and'
                     ' prompts expected message.')
Beispiel #16
0
def run(test, params, env):
    """
    Fetch from git and run qemu-iotests using the qemu binaries under test.

    1) Fetch qemu-io from git
    3) Run test for the file format detected
    4) Report any errors found to test

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    # First, let's get qemu-io
    std = "http://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git"
    uri = params.get("qemu_io_uri", std)
    branch = params.get("qemu_io_branch", 'master')
    lbranch = params.get("qemu_io_lbranch", 'master')
    commit = params.get("qemu_io_commit", None)
    base_uri = params.get("qemu_io_base_uri", None)
    iotests_dir = params.get("qemu_iotests_dir", "tests/qemu-iotests")
    destination_dir = os.path.join(test.workdir, "qemu_io_tests")
    git.get_repo(uri=uri,
                 branch=branch,
                 lbranch=lbranch,
                 commit=commit,
                 destination_dir=destination_dir,
                 base_uri=base_uri)

    # Then, set the qemu paths for the use of the testsuite
    os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params)
    os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params)
    os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params)

    # qemu-iotests has merged into tests/qemu_iotests folder
    os.chdir(os.path.join(destination_dir, iotests_dir))
    image_format = params["qemu_io_image_format"]
    extra_options = params.get("qemu_io_extra_options", "")

    cmd = './check'
    if extra_options:
        cmd += extra_options

    error_context.context("running qemu-iotests for image format %s" %
                          image_format)
    process.system("%s -%s" % (cmd, image_format), shell=True)
def run(test, params, env):
    """
    boot with different machine type:
    1) get supported machine type
    2) boot guest with different machine types

    :param test: kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    error_context.context("Get supported machine type", logging.info)
    qemu_binary = utils_misc.get_qemu_binary(params)
    machine_types = []
    machine_type_mapping = {"pc": ["i440FX", "RHEL 6"], "q35": ["Q35"], "pseries": ["pSeries"],
                            "arm64-pci:virt": ["ARM"], "arm64-mmio:virt": ["ARM"], "s390-ccw-virtio": ["S390"]}
    for m_type, s_name in zip(*utils_misc.get_support_machine_type(qemu_binary)):
        for item in machine_type_mapping[params["machine_type"]]:
            if item in s_name:
                if "arm64" in params["machine_type"]:
                    m_type = re.sub(r'(?<=:)\w+', m_type, params["machine_type"])
                machine_types.append(m_type)
    if not machine_types:
        test.fail("Failed to get machine types")
    else:
        logging.info("Actual supported machine types are: " + ', '.join(map(str, machine_types)))

        for m_type in machine_types:
            params["machine_type"] = m_type
            params["start_vm"] = "yes"
            vm_name = params['main_vm']
            error_context.context("Start vm with machine type '%s'"
                                  % m_type, logging.info)
            env_process.preprocess(test, params, env)
            vm = env.get_vm(vm_name)
            vm.verify_alive()
            timeout = int(params.get("login_timeout", 360))
            session = vm.wait_for_login(timeout=timeout)
            if not session.is_responsive():
                session.close()
                test.fail("Start vm with machine type:%s fail" % m_type)

            session.close()
            error_context.context("Quit guest and check the process quit normally",
                                  logging.info)
            vm.destroy(gracefully=False)
Beispiel #18
0
    def verify_machine_type():
        f_fail = []
        cmd = params.get("check_machine_type_cmd")
        fail_log = ""

        if cmd is None:
            return f_fail

        status, actual_mtype = session.cmd_status_output(cmd)
        if status != 0:
            test.error("Failed to get machine type from vm")

        machine_type_cmd = "%s -M ?" % utils_misc.get_qemu_binary(params)
        machine_types = process.system_output(machine_type_cmd,
                                              ignore_status=True).decode()
        machine_types = machine_types.split(':')[-1]
        machine_type_map = {}
        for machine_type in machine_types.splitlines():
            if not machine_type:
                continue
            type_pair = re.findall(r"([\w\.-]+)\s+([^(]+).*", machine_type)
            if len(type_pair) == 1 and len(type_pair[0]) == 2:
                machine_type_map[type_pair[0][0]] = type_pair[0][1]
            else:
                logging.warn("Unexpect output from qemu-kvm -M "
                             "?: '%s'", machine_type)
        try:
            expect_mtype = machine_type_map[params['machine_type']].strip()
        except KeyError:
            logging.warn(
                "Can not find machine type '%s' from qemu-kvm -M ?"
                " output. Skip this test.", params['machine_type'])
            return f_fail

        if expect_mtype not in actual_mtype:
            fail_log += "    Assigned to VM: '%s' \n" % expect_mtype
            fail_log += "    Reported by OS: '%s'" % actual_mtype
            f_fail.append(fail_log)
            logging.error(fail_log)
        else:
            logging.info("MachineType check pass. Expected: %s, Actual: %s",
                         expect_mtype, actual_mtype)
        return f_fail
Beispiel #19
0
def run_qemu_iotests(test, params, env):
    """
    Fetch from git and run qemu-iotests using the qemu binaries under test.

    1) Fetch qemu-io from git
    3) Run test for the file format detected
    4) Report any errors found to autotest

    @param test:   QEMU test object.
    @param params: Dictionary with the test parameters.
    @param env:    Dictionary with test environment.
    """
    # First, let's get qemu-io
    std = "git://git.kernel.org/pub/scm/linux/kernel/git/hch/qemu-iotests.git"
    uri = params.get("qemu_io_uri", std)
    branch = params.get("qemu_io_branch", 'master')
    lbranch = params.get("qemu_io_lbranch", 'master')
    commit = params.get("qemu_io_commit", None)
    base_uri = params.get("qemu_io_base_uri", None)
    destination_dir = os.path.join(test.srcdir, "qemu_io_tests")
    git.get_repo(uri=uri,
                 branch=branch,
                 lbranch=lbranch,
                 commit=commit,
                 destination_dir=destination_dir,
                 base_uri=base_uri)

    # Then, set the qemu paths for the use of the testsuite
    os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params)
    os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params)
    os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params)

    os.chdir(destination_dir)
    image_format = params["qemu_io_image_format"]
    extra_options = params.get("qemu_io_extra_options", "")

    cmd = './check'
    if extra_options:
        cmd += extra_options

    error.context("running qemu-iotests for image format %s" % image_format)
    utils.system("%s -%s" % (cmd, image_format))
    def verify_machine_type():
        f_fail = []
        cmd = params.get("check_machine_type_cmd")
        fail_log = ""

        if cmd is None:
            return f_fail

        status, actual_mtype = session.cmd_status_output(cmd)
        if status != 0:
            raise error.TestError("Failed to get machine type from vm")

        machine_type_cmd = "%s -M ?" % utils_misc.get_qemu_binary(params)
        machine_types = utils.system_output(machine_type_cmd,
                                            ignore_status=True)
        machine_types = machine_types.split(':')[-1]
        machine_type_map = {}
        for machine_type in machine_types.splitlines():
            if not machine_type:
                continue
            type_pair = re.findall("([\w\.-]+)\s+([^(]+).*", machine_type)
            if len(type_pair) == 1 and len(type_pair[0]) == 2:
                machine_type_map[type_pair[0][0]] = type_pair[0][1]
            else:
                logging.warn("Unexpect output from qemu-kvm -M "
                             "?: '%s'" % machine_type)
        try:
            expect_mtype = machine_type_map[params['machine_type']].strip()
        except KeyError:
            logging.warn("Can not find machine type '%s' from qemu-kvm -M ?"
                         " output. Skip this test." % params['machine_type'])
            return f_fail

        if expect_mtype not in actual_mtype:
            fail_log += "    Assigned to VM: '%s' \n" % expect_mtype
            fail_log += "    Reported by OS: '%s'" % actual_mtype
            f_fail.append(fail_log)
            logging.error(fail_log)
        else:
            logging.info("MachineType check pass. Expected: %s, Actual: %s" %
                        (expect_mtype, actual_mtype))
        return f_fail
 def _verify_map_output(output):
     """"Verify qemu map output."""
     qemu_path = utils_misc.get_qemu_binary(params)
     qemu_version = env_process._get_qemu_version(qemu_path)
     match = re.search(r'[0-9]+\.[0-9]+\.[0-9]+(\-[0-9]+)?', qemu_version)
     host_qemu = match.group(0)
     if host_qemu in VersionInterval('[6.1.0,)'):
         expected = {
             "length":
             int(
                 utils_numeric.normalize_data_size(params["write_size"],
                                                   "B")),
             "start":
             0,
             "depth":
             0,
             "present":
             True,
             "zero":
             True,
             "data":
             False
         }
     else:
         expected = {
             "length":
             int(
                 utils_numeric.normalize_data_size(params["write_size"],
                                                   "B")),
             "start":
             0,
             "depth":
             0,
             "zero":
             True,
             "data":
             False
         }
     if expected not in json.loads(output.stdout_text):
         test.fail("Commit failed, data from 0 to %s are not zero" %
                   params["write_size"])
 def stream_to_invalid_node(self):
     snapshot_tags = self.params.get("snapshot_tags").split()
     stream_node_tag = random.choice(snapshot_tags)
     device_node = self.get_node_name(stream_node_tag)
     try:
         cmd, arguments = backup_utils.blockdev_stream_qmp_cmd(device_node)
         self.main_vm.monitor.cmd(cmd, arguments)
     except QMPCmdError as e:
         qemu_binary = utils_misc.get_qemu_binary(self.params)
         qemu_version = utils_qemu.get_qemu_version(qemu_binary)[0]
         required_qemu_version = self.params["required_qemu_version"]
         if qemu_version in VersionInterval(required_qemu_version):
             qmp_error_msg = self.params[
                 "qmp_error_since_6_1"] % self.device_node
         else:
             qmp_error_msg = self.params[
                 "qmp_error_before_6_1"] % self.device_node
         if qmp_error_msg not in str(e.data):
             self.test.fail(str(e))
     else:
         self.test.fail("Can stream to an invalid node:%s" % device_node)
 def reopen_backing_image(self, node_name):
     opts = []
     fmt_node = self.main_vm.devices.get_by_qid(node_name)[0]
     file_node = fmt_node.get_param("file")
     driver = fmt_node.get_param("driver")
     item = {
         "driver": driver,
         "node-name": node_name,
         "file": file_node,
         "read-only": False
     }
     qemu_binary = utils_misc.get_qemu_binary(self.params)
     qemu_version = utils_qemu.get_qemu_version(qemu_binary)[0]
     required_qemu_version = self.params["required_qemu_version"]
     if qemu_version in VersionInterval(required_qemu_version):
         opts.append(item)
         args = {"options": opts}
         self.main_vm.monitor.blockdev_reopen(args)
     else:
         args = item
         self.main_vm.monitor.x_blockdev_reopen(args)
Beispiel #24
0
def run_qemu_iotests(test, params, env):
    """
    Fetch from git and run qemu-iotests using the qemu binaries under test.

    1) Fetch qemu-io from git
    3) Run test for the file format detected
    4) Report any errors found to autotest

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    # First, let's get qemu-io
    std = "http://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git"
    uri = params.get("qemu_io_uri", std)
    branch = params.get("qemu_io_branch", 'master')
    lbranch = params.get("qemu_io_lbranch", 'master')
    commit = params.get("qemu_io_commit", None)
    base_uri = params.get("qemu_io_base_uri", None)
    iotests_dir = params.get("qemu_iotests_dir", "tests/qemu-iotests")
    destination_dir = os.path.join(test.srcdir, "qemu_io_tests")
    git.get_repo(uri=uri, branch=branch, lbranch=lbranch, commit=commit,
                 destination_dir=destination_dir, base_uri=base_uri)

    # Then, set the qemu paths for the use of the testsuite
    os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params)
    os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params)
    os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params)

    # qemu-iotests has merged into tests/qemu_iotests folder
    os.chdir(os.path.join(destination_dir, iotests_dir))
    image_format = params["qemu_io_image_format"]
    extra_options = params.get("qemu_io_extra_options", "")

    cmd = './check'
    if extra_options:
        cmd += extra_options

    error.context("running qemu-iotests for image format %s" % image_format)
    utils.system("%s -%s" % (cmd, image_format))
 def do_full_backup(self):
     """
     Backup source image to target image
     """
     src = self._source_nodes[0]
     dst = self._full_bk_nodes[0]
     backup_cmd = backup_utils.blockdev_backup_qmp_cmd
     cmd, arguments = backup_cmd(src, dst, **self._full_backup_options)
     try:
         self.main_vm.monitor.cmd(cmd, arguments)
     except QMPCmdError as e:
         sync_mode = self._full_backup_options.get("sync")
         qemu_binary = utils_misc.get_qemu_binary(self.params)
         qemu_version = utils_qemu.get_qemu_version(qemu_binary)[0]
         required_qemu_version = self.params["required_qemu_version"]
         if qemu_version in VersionInterval(required_qemu_version):
             qmp_error_msg = self.params["qmp_error_after_6_2"] % sync_mode
         else:
             qmp_error_msg = self.params["qmp_error_before_6_2"] % sync_mode
         if not re.search(qmp_error_msg, str(e.data)):
             self.test.fail(str(e))
     else:
         self.test.fail("Do full backup with an invalid sync mode")
Beispiel #26
0
def get_qemu_best_cpu_model(params):
    """
    Try to find out the best CPU model available for qemu.

    This function can't be in qemu_vm, because it is used in env_process,
    where there's no vm object available yet, and env content is synchronized
    in multi host testing.

    1) Get host CPU model
    2) Verify if host CPU model is in the list of supported qemu cpu models
    3) If so, return host CPU model
    4) If not, return the default cpu model set in params, if none defined,
        return 'qemu64'.
    """
    host_cpu_models = get_host_cpu_models()
    qemu_binary = utils_misc.get_qemu_binary(params)
    qemu_cpu_models = get_qemu_cpu_models(qemu_binary)
    # Let's try to find a suitable model on the qemu list
    for host_cpu_model in host_cpu_models:
        if host_cpu_model in qemu_cpu_models:
            return host_cpu_model
    # If no host cpu model can be found on qemu_cpu_models, choose the default
    return params.get("default_cpu_model", None)
Beispiel #27
0
    def install_test(build_root):
        """
        Download src rpm, unpack src code and applying patches

        :param build_root: build path of rpmbuild
        :return: A tuple containing directory of qemu source code
                 and qemu-kvm spec
        """
        error_context.context("Get qemu source code", logging.info)
        os.chdir(test.tmpdir)
        query_format = params["query_format"]
        download_rpm_cmd = params["download_rpm_cmd"]
        get_src_cmd = params["get_src_cmd"]
        qemu_spec = params.get("qemu_spec", 'SPECS/qemu-kvm.spec')
        get_rpm_name_cmd = ("rpm -qf %s --queryformat=%s" %
                            (utils_misc.get_qemu_binary(params), query_format))
        src_rpm_name = process.system_output(get_rpm_name_cmd, shell=True)
        retry_command(download_rpm_cmd % src_rpm_name)
        spec = os.path.join(build_root, qemu_spec)
        build_dir = os.path.join(build_root, 'BUILD')
        cmd = get_src_cmd % (src_rpm_name, spec)
        process.system(cmd, shell=True)
        src_dir = os.listdir(build_dir)[0]
        return (os.path.join(build_dir, src_dir), spec)
 def _verify_qemu_img_map(output, str_len):
     """Verify qemu-img map's output."""
     logging.info("Verify the dumped mete-data of the unaligned image.")
     qemu_path = utils_misc.get_qemu_binary(params)
     qemu_version = env_process._get_qemu_version(qemu_path)
     match = re.search(r'[0-9]+\.[0-9]+\.[0-9]+(\-[0-9]+)?', qemu_version)
     host_qemu = match.group(0)
     if host_qemu in VersionInterval('[6.1.0,)'):
         expected = [
             {"start": 0, "length": str_len, "depth": 0, "present": True,
              "zero": False, "data": True, "offset": 0},
             {"start": str_len, "length": 512 - (str_len % 512), "depth": 0,
              "present": True, "zero": True, "data": False,
              "offset": str_len}]
     else:
         expected = [{"start": 0, "length": str_len, "depth": 0,
                      "zero": False, "data": True, "offset": 0},
                     {"start": str_len, "length": 512 - (str_len % 512),
                      "depth": 0, "zero": True, "data": False,
                      "offset": str_len}]
     res = json.loads(output)
     if res != expected:
         test.fail("The dumped mete-data of the unaligned "
                   "image '%s' is not correct." % img.image_filename)
Beispiel #29
0
def run(test, params, env):
    """
    KVM nfs performance test:
    1) boot guest over virtio driver.
    2) mount nfs server in guest with tcp protocol.
    3) test write performance in guest using dd commands.
    4) test read performance in guest using dd commands.

    Note: This test is used for performance benchmark test,
          not for the functional test usage. The result of
          this test depends on the regression.py tool,
          though you can run it during function testing,
          you may not get any possible error report from
          this script directly.

    :param test: kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment
    """
    def _do_clean_up(func, *args):
        try:
            if args:
                func(*args)
            else:
                func()
        except Exception as e:
            logging.warn("Failed to execute function '%s'."
                         " error message:\n%s", func.__name__, e)

    def _clean_up(step_cnt):
        error_context.context("Clean up", logging.info)
        if step_cnt >= STEP_5:
            # remove test file.
            cmd = "rm -f %s" % " ".join(test_file_list)
            _do_clean_up(session.cmd, cmd)
        if step_cnt >= STEP_4:
            # umount nfs partition.
            cmd = "umount %s" % mnt_point
            _do_clean_up(session.cmd, cmd)
        if step_cnt >= STEP_3:
            # remove mount ponit directory.
            cmd = "rm -rf %s" % mnt_point
            _do_clean_up(session.cmd, cmd)
        if step_cnt >= STEP_2:
            # close result file.
            _do_clean_up(result_file.close)
        if step_cnt >= STEP_1:
            # close session.
            _do_clean_up(session.close)

    def _do_write_test(blk_size, test_file):
        # Clean up caches
        session.cmd("echo 3 >/proc/sys/vm/drop_caches")

        error_context.context("test %s size block write performance in guest"
                              " using dd commands" % blk_size, logging.info)
        dd_cmd = "dd"
        dd_cmd += " if=/dev/zero"
        dd_cmd += " of=%s" % test_file
        dd_cmd += " bs=%s" % blk_size
        dd_cmd += " oflag=direct"
        dd_cmd += " count=10000"
        try:
            out = session.cmd_output(dd_cmd, timeout=test_timeout)
        except Exception:
            _clean_up(STEP_4)
            raise

        return out

    def _do_read_test(blk_size, test_file):
        # Clean up caches
        session.cmd("echo 3 >/proc/sys/vm/drop_caches")

        error_context.context("test %s size block read performance in guest"
                              " using dd commands" % blk_size, logging.info)
        dd_cmd = "dd"
        dd_cmd += " if=%s" % test_file
        dd_cmd += " of=/dev/null"
        dd_cmd += " bs=%s" % blk_size
        dd_cmd += " iflag=direct"
        try:
            out = session.cmd_output(dd_cmd, timeout=test_timeout)
        except Exception:
            _clean_up(STEP_5)
            raise
        # After STEP 6

        return out

    if not hasattr(test, "write_perf_keyval"):
        test.cancel("There is no 'write_perf_keyval' method in"
                    " test object, skip this test")

    error_context.context("boot guest over virtio driver", logging.info)
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    test_timeout = int(params["test_timeout"])
    session = vm.wait_for_login(timeout=timeout)
    guest_ver = session.cmd_output("uname -r").strip()
    host_ver = os.uname()[2]

    kvm_userspace_ver_cmd = params.get("kvm_userspace_ver_cmd", "")
    if kvm_userspace_ver_cmd:
        try:
            cmd_result = process.run(kvm_userspace_ver_cmd, shell=True)
            qemu_version = cmd_result.stdout.strip()
        except process.CmdError:
            qemu_version = "Unknown"
    else:
        qemu_path = utils_misc.get_qemu_binary(params)
        version_line = process.system_output("%s -help | head -n 1"
                                             % qemu_path, shell=True)
        matches = re.findall("version .*?,", version_line, re.I)
        if matches:
            qemu_version = " ".join(matches[0].split()[1:]).strip(",")
        else:
            qemu_version = "Unknown"
    # After STEP 1

    try:
        result_name = params.get("result_name", "nfs-perf.RHS")
        result_file_path = utils_misc.get_path(test.resultsdir, result_name)
        result_file = open(result_file_path, 'w')
    except Exception:
        _clean_up(STEP_1)
        raise
    # After STEP 2

    error_context.context("mount nfs server in guest with tcp protocol",
                          logging.info)
    nfs_server = params.get("nfs_server")
    nfs_path = params.get("nfs_path")
    mnt_option = params.get("mnt_option")
    mnt_point = "/tmp/nfs_perf_%s" % utils_misc.generate_random_string(4)
    test_file_prefix = os.path.join(mnt_point, "test_%si_" %
                                    utils_misc.generate_random_string(4))

    blk_size_list = params.get("blk_size_list", "8k").split()
    test_file_list = list(map(lambda x: test_file_prefix + x, blk_size_list))

    if (not nfs_server) or (not nfs_path) or (not mnt_point):
        _clean_up(STEP_2)
        test.error("Missing configuration for nfs partition."
                   " Check your config files")

    try:
        session.cmd("mkdir -p %s" % mnt_point)
    except Exception:
        _clean_up(STEP_2)
        raise
    # After STEP 3
    # Prepare nfs partition.
    mnt_cmd = "mount"
    mnt_cmd += " -t nfs"
    if mnt_option:
        mnt_cmd += " -o %s" % mnt_option
    mnt_cmd += " %s:%s" % (nfs_server, nfs_path)
    mnt_cmd_out = mnt_cmd + " /tmp/***_****_****"
    mnt_cmd += " %s" % mnt_point
    try:
        session.cmd(mnt_cmd)
    except Exception:
        _clean_up(STEP_3)
        raise
    # After STEP 4

    # Record mount command in result file.
    try:
        result_file.write("### kvm-userspace-ver : %s\n" % qemu_version)
        result_file.write("### kvm_version : %s\n" % host_ver)
        result_file.write("### guest-kernel-ver : %s\n" % guest_ver)
        result_file.write("### %s\n" % mnt_cmd_out)
        result_file.write("Category:ALL\n")
    except (IOError, ValueError) as e:
        logging.error("Failed to write to result file,"
                      " error message:\n%s", e)

    result_list = ["%s|%016s|%016s" % ("blk_size", "Write", "Read")]
    speed_pattern = r"(\d+ bytes).*?([\d\.]+ s).*?([\d\.]+ [KkMmGgTt])B/s"
    try:
        prefix = "nfs"
        for blk_size in blk_size_list:
            prefix += "--%s" % blk_size
            test_file = test_file_list[blk_size_list.index(blk_size)]
            result = "%08s|" % blk_size[:-1]
            # Get write test result.
            out = _do_write_test(blk_size, test_file)
            tmp_list = re.findall(speed_pattern, out)
            if not tmp_list:
                _clean_up(STEP_5)
                test.error("Could not get correct write result."
                           " dd cmd output:\n%s" % out)
            _, _, speed = tmp_list[0]
            speed = utils_misc.normalize_data_size(speed)
            result += "%016s|" % speed
            test.write_perf_keyval({"%s--%s" % (prefix, "write"): speed})

            # Get read test result.
            out = _do_read_test(blk_size, test_file)
            tmp_list = re.findall(speed_pattern, out)
            if not tmp_list:
                _clean_up(STEP_6)
                test.error("Could not get correct read result."
                           " dd cmd output:\n%s" % out)
            _, _, speed = tmp_list[0]
            speed = utils_misc.normalize_data_size(speed)
            result += "%016s" % speed
            test.write_perf_keyval({"%s--%s" % (prefix, "read"): speed})
            # Append result into result list.
            result_list.append(result)
    finally:
        try:
            result_file.write("\n".join(result_list))
        except (IOError, ValueError) as e:
            logging.error("Failed to write to result file,"
                          " error message:\n%s", e)

    _clean_up(STEP_6)
Beispiel #30
0
def run(test, params, env):
    """
    Boot guest with different cpu_models and cpu flags and check if guest works correctly.

    :param test: kvm test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    qemu_binary = utils_misc.get_qemu_binary(params)

    cpu_model = params.get("cpu_model", "qemu64")

    xfail = False
    if (params.get("xfail") is not None) and (params.get("xfail") == "yes"):
        xfail = True

    def cpu_models_to_test():
        """Return the list of CPU models to be tested, based on the
        cpu_models and cpu_model config options.

        Config option "cpu_model" may be used to ask a single CPU model
        to be tested. Config option "cpu_models" may be used to ask
        multiple CPU models to be tested.

        If cpu_models is "*", all CPU models reported by QEMU will be tested.
        """
        models_opt = params.get("cpu_models")
        model_opt = params.get("cpu_model")

        if (models_opt is None and model_opt is None):
            test.error("No cpu_models or cpu_model option is set")

        cpu_models = set()

        if models_opt == '*':
            cpu_models.update(utils_misc.get_qemu_cpu_models(qemu_binary))
        elif models_opt:
            cpu_models.update(models_opt.split())

        if model_opt:
            cpu_models.add(model_opt)

        return cpu_models

    def test_qemu_cpu_models_list(self):
        """
        check CPU models returned by <qemu> -cpu '?' are what is expected
        """
        """
        test method
        """
        cpu_models = cpu_models_to_test()
        qemu_models = utils_misc.get_qemu_cpu_models(qemu_binary)
        missing = set(cpu_models) - set(qemu_models)
        if missing:
            test.fail("Some CPU models not in QEMU CPU model list: %r" %
                      (missing))
        added = set(qemu_models) - set(cpu_models)
        if added:
            logging.info("Extra CPU models in QEMU CPU listing: %s", added)

    def compare_cpuid_output(a, b):
        """
        Generates a list of (bit, va, vb) tuples for
        each bit that is different between a and b.
        """
        for bit in range(32):
            ba = (a & (1 << bit)) >> bit
            if b is not None:
                bb = (b & (1 << bit)) >> bit
            else:
                bb = None
            if ba != bb:
                yield (bit, ba, bb)

    def parse_cpuid_dump(output):
        dbg("parsing cpuid dump: %r", output)
        cpuid_re = re.compile(
            "^ *(0x[0-9a-f]+) +0x([0-9a-f]+): +eax=0x([0-9a-f]+) ebx=0x([0-9a-f]+) ecx=0x([0-9a-f]+) edx=0x([0-9a-f]+)$"
        )
        output_match = re.search('(==START TEST==.*==END TEST==)', output,
                                 re.M | re.DOTALL)
        if output_match is None:
            dbg("cpuid dump doesn't follow expected pattern")
            return None
        output = output_match.group(1)
        out_lines = output.splitlines()
        if out_lines[0] != '==START TEST==' or out_lines[-1] != '==END TEST==':
            dbg("cpuid dump doesn't have expected delimiters")
            return None
        if out_lines[1] != 'CPU:':
            dbg("cpuid dump doesn't start with 'CPU:' line")
            return None
        result = {}
        for l in out_lines[2:-1]:
            m = cpuid_re.match(l)
            if m is None:
                dbg("invalid cpuid dump line: %r", l)
                return None
            in_eax = int(m.group(1), 16)
            in_ecx = int(m.group(2), 16)
            result[in_eax, in_ecx, 'eax'] = int(m.group(3), 16)
            result[in_eax, in_ecx, 'ebx'] = int(m.group(4), 16)
            result[in_eax, in_ecx, 'ecx'] = int(m.group(5), 16)
            result[in_eax, in_ecx, 'edx'] = int(m.group(6), 16)
        return result

    def get_test_kernel_cpuid(self, vm):
        vm.resume()

        timeout = float(params.get("login_timeout", 240))
        logging.debug("Will wait for CPUID serial output at %r",
                      vm.serial_console)
        if not utils_misc.wait_for(
                lambda: re.search("==END TEST==", vm.serial_console.get_output(
                )), timeout, 1):
            test.fail("Could not get test complete message.")

        test_output = parse_cpuid_dump(vm.serial_console.get_output())
        logging.debug("Got CPUID serial output: %r", test_output)
        if test_output is None:
            test.fail("Test output signature not found in "
                      "output:\n %s", vm.serial_console.get_output())
        vm.destroy(gracefully=False)
        return test_output

    def find_cpu_obj(vm):
        """Find path of a valid VCPU object"""
        roots = ['/machine/icc-bridge/icc', '/machine/unattached/device']
        for root in roots:
            for child in vm.monitor.cmd('qom-list', dict(path=root)):
                logging.debug('child: %r', child)
                if child['type'].rstrip('>').endswith('-cpu'):
                    return root + '/' + child['name']

    def get_qom_cpuid(self, vm):
        assert vm.monitor.protocol == "qmp"
        cpu_path = find_cpu_obj(vm)
        logging.debug('cpu path: %r', cpu_path)
        r = {}
        for prop in 'feature-words', 'filtered-features':
            words = vm.monitor.cmd('qom-get', dict(path=cpu_path,
                                                   property=prop))
            logging.debug('%s property: %r', prop, words)
            for w in words:
                reg = w['cpuid-register'].lower()
                key = (w['cpuid-input-eax'], w.get('cpuid-input-ecx', 0), reg)
                r.setdefault(key, 0)
                r[key] |= w['features']
        return r

    def get_guest_cpuid(self,
                        cpu_model,
                        feature=None,
                        extra_params=None,
                        qom_mode=False):
        if not qom_mode:
            test_kernel_dir = os.path.join(data_dir.get_deps_dir(), "cpuid",
                                           "src")
            build.make(test_kernel_dir, extra_args="cpuid_dump_kernel.bin")

        vm_name = params['main_vm']
        params_b = params.copy()
        if not qom_mode:
            params_b["kernel"] = os.path.join(test_kernel_dir,
                                              "cpuid_dump_kernel.bin")
        params_b["cpu_model"] = cpu_model
        params_b["cpu_model_flags"] = feature
        del params_b["images"]
        del params_b["nics"]
        if extra_params:
            params_b.update(extra_params)
        env_process.preprocess_vm(self, params_b, env, vm_name)
        vm = env.get_vm(vm_name)
        dbg('is dead: %r', vm.is_dead())
        vm.create()
        self.vm = vm
        if qom_mode:
            return get_qom_cpuid(self, vm)
        else:
            return get_test_kernel_cpuid(self, vm)

    def cpuid_to_vendor(cpuid_dump, idx):
        dst = []
        map(
            lambda i: dst.append((chr(cpuid_dump[idx, 0, 'ebx'] >>
                                      (8 * i) & 0xff))), range(0, 4))
        map(
            lambda i: dst.append((chr(cpuid_dump[idx, 0, 'edx'] >>
                                      (8 * i) & 0xff))), range(0, 4))
        map(
            lambda i: dst.append((chr(cpuid_dump[idx, 0, 'ecx'] >>
                                      (8 * i) & 0xff))), range(0, 4))
        return ''.join(dst)

    def default_vendor(self):
        """
        Boot qemu with specified cpu models and
        verify that CPU vendor matches requested
        """
        cpu_models = cpu_models_to_test()

        vendor = params.get("vendor")
        if vendor is None or vendor == "host":
            cmd = "grep 'vendor_id' /proc/cpuinfo | head -n1 | awk '{print $3}'"
            cmd_result = process.run(cmd, ignore_status=True, shell=True)
            vendor = cmd_result.stdout.strip()

        ignore_cpus = set(params.get("ignore_cpu_models", "").split(' '))
        cpu_models = cpu_models - ignore_cpus

        for cpu_model in cpu_models:
            out = get_guest_cpuid(self, cpu_model)
            guest_vendor = cpuid_to_vendor(out, 0x00000000)
            logging.debug("Guest's vendor: " + guest_vendor)
            if guest_vendor != vendor:
                test.fail("Guest vendor [%s], doesn't match "
                          "required vendor [%s] for CPU [%s]" %
                          (guest_vendor, vendor, cpu_model))

    def custom_vendor(self):
        """
        Boot qemu with specified vendor
        """
        has_error = False
        vendor = params["vendor"]

        try:
            out = get_guest_cpuid(self, cpu_model, "vendor=" + vendor)
            guest_vendor0 = cpuid_to_vendor(out, 0x00000000)
            guest_vendor80000000 = cpuid_to_vendor(out, 0x80000000)
            logging.debug("Guest's vendor[0]: " + guest_vendor0)
            logging.debug("Guest's vendor[0x80000000]: " +
                          guest_vendor80000000)
            if guest_vendor0 != vendor:
                test.fail("Guest vendor[0] [%s], doesn't match "
                          "required vendor [%s] for CPU [%s]" %
                          (guest_vendor0, vendor, cpu_model))
            if guest_vendor80000000 != vendor:
                test.fail("Guest vendor[0x80000000] [%s], "
                          "doesn't match required vendor "
                          "[%s] for CPU [%s]" %
                          (guest_vendor80000000, vendor, cpu_model))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_to_level(cpuid_dump):
        r = cpuid_dump[0, 0]
        return r['eax']

    def custom_level(self):
        """
        Boot qemu with specified level
        """
        has_error = False
        level = params["level"]
        try:
            out = get_guest_cpuid(self, cpu_model, "level=" + level)
            guest_level = str(cpuid_to_level(out))
            if guest_level != level:
                test.fail("Guest's level [%s], doesn't match "
                          "required level [%s]" % (guest_level, level))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_to_family(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_dump[1, 0]['eax']
        family = (eax >> 8) & 0xf
        if family == 0xf:
            # extract extendend family
            return family + ((eax >> 20) & 0xff)
        return family

    def custom_family(self):
        """
        Boot qemu with specified family
        """
        has_error = False
        family = params["family"]
        try:
            out = get_guest_cpuid(self, cpu_model, "family=" + family)
            guest_family = str(cpuid_to_family(out))
            if guest_family != family:
                test.fail("Guest's family [%s], doesn't match "
                          "required family [%s]" % (guest_family, family))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_to_model(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_dump[1, 0]['eax']
        model = (eax >> 4) & 0xf
        # extended model
        model |= (eax >> 12) & 0xf0
        return model

    def custom_model(self):
        """
        Boot qemu with specified model
        """
        has_error = False
        model = params["model"]
        try:
            out = get_guest_cpuid(self, cpu_model, "model=" + model)
            guest_model = str(cpuid_to_model(out))
            if guest_model != model:
                test.fail("Guest's model [%s], doesn't match "
                          "required model [%s]" % (guest_model, model))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_to_stepping(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_dump[1, 0]['eax']
        stepping = eax & 0xf
        return stepping

    def custom_stepping(self):
        """
        Boot qemu with specified stepping
        """
        has_error = False
        stepping = params["stepping"]
        try:
            out = get_guest_cpuid(self, cpu_model, "stepping=" + stepping)
            guest_stepping = str(cpuid_to_stepping(out))
            if guest_stepping != stepping:
                test.fail("Guest's stepping [%s], doesn't match "
                          "required stepping [%s]" %
                          (guest_stepping, stepping))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_to_xlevel(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.2.1 Largest Extendend Function # (Function 80000000h)
        return cpuid_dump[0x80000000, 0x00]['eax']

    def custom_xlevel(self):
        """
        Boot qemu with specified xlevel
        """
        has_error = False
        xlevel = params["xlevel"]
        if params.get("expect_xlevel") is not None:
            xlevel = params.get("expect_xlevel")

        try:
            out = get_guest_cpuid(self, cpu_model,
                                  "xlevel=" + params.get("xlevel"))
            guest_xlevel = str(cpuid_to_xlevel(out))
            if guest_xlevel != xlevel:
                test.fail("Guest's xlevel [%s], doesn't match "
                          "required xlevel [%s]" % (guest_xlevel, xlevel))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_to_model_id(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.2.3 Processor Brand String (Functions 80000002h, 80000003h,
        # 80000004h)
        m_id = ""
        for idx in (0x80000002, 0x80000003, 0x80000004):
            regs = cpuid_dump[idx, 0]
            for name in ('eax', 'ebx', 'ecx', 'edx'):
                for shift in range(4):
                    c = ((regs[name] >> (shift * 8)) & 0xff)
                    if c == 0:  # drop trailing \0-s
                        break
                    m_id += chr(c)
        return m_id

    def custom_model_id(self):
        """
        Boot qemu with specified model_id
        """
        has_error = False
        model_id = params["model_id"]

        try:
            out = get_guest_cpuid(self, cpu_model, "model_id='%s'" % model_id)
            guest_model_id = cpuid_to_model_id(out)
            if guest_model_id != model_id:
                test.fail("Guest's model_id [%s], doesn't match "
                          "required model_id [%s]" %
                          (guest_model_id, model_id))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_regs_to_string(cpuid_dump, leaf, idx, regs):
        r = cpuid_dump[leaf, idx]
        signature = ""
        for i in regs:
            for shift in range(0, 4):
                c = chr((r[i] >> (shift * 8)) & 0xFF)
                if c in string.printable:
                    signature = signature + c
                else:
                    signature = "%s\\x%02x" % (signature, ord(c))
        logging.debug("(%s.%s:%s: signature: %s" %
                      (leaf, idx, str(regs), signature))
        return signature

    def cpuid_signature(self):
        """
        test signature in specified leaf:index:regs
        """
        has_error = False
        flags = params.get("flags", "")
        leaf = int(params.get("leaf", "0x40000000"), 0)
        idx = int(params.get("index", "0x00"), 0)
        regs = params.get("regs", "ebx ecx edx").split()
        signature = params["signature"]
        try:
            out = get_guest_cpuid(self, cpu_model, flags)
            _signature = cpuid_regs_to_string(out, leaf, idx, regs)
            if _signature != signature:
                test.fail("Guest's signature [%s], doesn't"
                          "match required signature [%s]" %
                          (_signature, signature))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_bit_test(self):
        """
        test bits in specified leaf:func:reg
        """
        has_error = False
        flags = params.get("flags", "")
        leaf = int(params.get("leaf", "0x40000000"), 0)
        idx = int(params.get("index", "0x00"), 0)
        reg = params.get("reg", "eax")
        bits = params["bits"].split()
        try:
            out = get_guest_cpuid(self, cpu_model, flags)
            r = out[leaf, idx][reg]
            logging.debug("CPUID(%s.%s).%s=0x%08x" % (leaf, idx, reg, r))
            for i in bits:
                if (r & (1 << int(i))) == 0:
                    test.fail("CPUID(%s.%s).%s[%s] is not set" %
                              (leaf, idx, reg, i))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def cpuid_reg_test(self):
        """
        test register value in specified leaf:index:reg
        """
        has_error = False
        flags = params.get("flags", "")
        leaf = int(params.get("leaf", "0x00"), 0)
        idx = int(params.get("index", "0x00"), 0)
        reg = params.get("reg", "eax")
        val = int(params["value"], 0)
        try:
            out = get_guest_cpuid(self, cpu_model, flags)
            r = out[leaf, idx][reg]
            logging.debug("CPUID(%s.%s).%s=0x%08x" % (leaf, idx, reg, r))
            if r != val:
                test.fail("CPUID(%s.%s).%s is not 0x%08x" %
                          (leaf, idx, reg, val))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            test.fail("Test was expected to fail, but it didn't")

    def check_cpuid_dump(self):
        """
        Compare full CPUID dump data
        """
        machine_type = params.get("machine_type_to_check", "")
        kvm_enabled = params.get("enable_kvm", "yes") == "yes"

        ignore_cpuid_leaves = params.get("ignore_cpuid_leaves", "")
        ignore_cpuid_leaves = ignore_cpuid_leaves.split()
        whitelist = []
        for leaf in ignore_cpuid_leaves:
            leaf = leaf.split(',')
            # syntax of ignore_cpuid_leaves:
            # <in_eax>[,<in_ecx>[,<register>[ ,<bit>]]] ...
            for i in 0, 1, 3:  # integer fields:
                if len(leaf) > i:
                    leaf[i] = int(leaf[i], 0)
            whitelist.append(tuple(leaf))

        if not machine_type:
            test.cancel("No machine_type_to_check defined")
        cpu_model_flags = params.get('cpu_model_flags', '')
        full_cpu_model_name = cpu_model
        if cpu_model_flags:
            full_cpu_model_name += ','
            full_cpu_model_name += cpu_model_flags.lstrip(',')
        ref_file = os.path.join(data_dir.get_deps_dir(), 'cpuid',
                                "cpuid_dumps", kvm_enabled and "kvm"
                                or "nokvm", machine_type,
                                '%s-dump.txt' % (full_cpu_model_name))
        if not os.path.exists(ref_file):
            test.cancel("no cpuid dump file: %s" % (ref_file))
        reference = open(ref_file, 'r').read()
        if not reference:
            test.cancel("no cpuid dump data on file: %s" % (ref_file))
        reference = parse_cpuid_dump(reference)
        if reference is None:
            test.cancel("couldn't parse reference cpuid dump from file; %s" %
                        (ref_file))
        qom_mode = params.get('qom_mode', "no").lower() == 'yes'
        if not qom_mode:
            cpu_model_flags += ',enforce'
        try:

            out = get_guest_cpuid(self,
                                  cpu_model,
                                  cpu_model_flags,
                                  extra_params=dict(machine_type=machine_type,
                                                    smp=1),
                                  qom_mode=qom_mode)
        except (virt_vm.VMStartError, virt_vm.VMCreateError) as e:
            output = getattr(e, 'reason', getattr(e, 'output', ''))
            if "host doesn't support requested feature:" in output \
                or ("host cpuid" in output and
                    ("lacks requested flag" in output or
                     "flag restricted to guest" in output)) \
                    or ("Unable to find CPU definition:" in output):
                test.cancel("Can't run CPU model %s on this host" %
                            (full_cpu_model_name))
            else:
                raise
        dbg('ref_file: %r', ref_file)
        dbg('ref: %r', reference)
        dbg('out: %r', out)
        ok = True
        for k in reference.keys():
            in_eax, in_ecx, reg = k
            diffs = compare_cpuid_output(reference[k], out.get(k))
            for d in diffs:
                bit, vreference, vout = d
                whitelisted = (in_eax,) in whitelist \
                    or (in_eax, in_ecx) in whitelist \
                    or (in_eax, in_ecx, reg) in whitelist \
                    or (in_eax, in_ecx, reg, bit) in whitelist
                silent = False

                if vout is None and params.get('ok_missing', 'no') == 'yes':
                    whitelisted = True
                    silent = True

                if not silent:
                    info(
                        "Non-matching bit: CPUID[0x%x,0x%x].%s[%d]: found %s instead of %s%s",
                        in_eax, in_ecx, reg, bit, vout, vreference,
                        whitelisted and " (whitelisted)" or "")

                if not whitelisted:
                    ok = False
        if not ok:
            test.fail("Unexpected CPUID data")

    # subtests runner
    test_type = params["test_type"]
    if test_type not in locals():
        test.error("Test function '%s' is not defined in test" % test_type)

    test_func = locals()[test_type]
    return test_func(test)
Beispiel #31
0
def run(test, params, env):
    """
    Test qmp event notification, this case will:
    1) Start VM with qmp enable.
    2) Connect to qmp port then run qmp_capabilities command.
    3) Initiate the qmp command defined in config (qmp_cmd)
    4) Verify that qmp command works as designed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """
    def check_result(qmp_o, output=None, exception_list=""):
        """
        Check test result with difference way accoriding to
        result_check.
        result_check = equal, will compare cmd_return_value with qmp
                       command output.
        result_check = contain, will try to find cmd_return_value in qmp
                       command output.
        result_check = m_equal_q, will compare key value in monitor command
                       output and qmp command output.
        result_check = m_in_q, will try to find monitor command output's key
                       value in qmp command output.
        result_check = m_format_q, will try to match the output's format with
                       check pattern.

        :param qmp_o: output from pre_cmd, qmp_cmd or post_cmd.
        :param o: output from pre_cmd, qmp_cmd or post_cmd or an execpt
        :param exception_list: element no need check.
        result set in config file.
        """
        if result_check == "equal":
            value = output
            if value != str(qmp_o):
                test.fail("QMP command return value does not match "
                          "the expect result. Expect result: '%s'\n"
                          "Actual result: '%s'" % (value, qmp_o))
        elif result_check == "contain":
            values = output.split(';')
            for value in values:
                if value in exception_list:
                    continue
                if value.strip() not in str(qmp_o):
                    test.fail("QMP command output does not contain "
                              "expect result. Expect result: '%s'\n"
                              "Actual result: '%s'" % (value, qmp_o))
        elif result_check == "not_contain":
            values = output.split(';')
            for value in values:
                if value in exception_list:
                    continue
                if value in str(qmp_o):
                    test.fail("QMP command output contains unexpect"
                              " result. Unexpect result: '%s'\n"
                              "Actual result: '%s'" % (value, qmp_o))
        elif result_check == "m_equal_q":
            msg = "QMP command ouput is not equal to in human monitor command."
            msg += "\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman command output: '%s'" % output
            res = output.splitlines(True)
            if type(qmp_o) != type(res):
                len_o = 1
            else:
                len_o = len(qmp_o)
            if len(res) != len_o:
                if res[0].startswith(' '):
                    test.fail("Human command starts with ' ', "
                              "there is probably some garbage in "
                              "the output.\n" + msg)
                res_tmp = []
                #(qemu)info block in RHEL7 divided into 3 lines
                for line in res:
                    if not line.startswith(' '):
                        res_tmp.append(line)
                    else:
                        res_tmp[-1] += line
                res = res_tmp
                if len(res) != len_o:
                    test.fail(msg)
            re_str = r'([^ \t\n\r\f\v=]*)=([^ \t\n\r\f\v=]*)'
            for i in range(len(res)):
                if qmp_cmd == "query-version":
                    version = qmp_o['qemu']
                    version = "%s.%s.%s" % (version['major'], version['minor'],
                                            version['micro'])
                    package = qmp_o['package']
                    re_str = r"([0-9]+\.[0-9]+\.[0-9]+)\s*(\(\S*\))?"
                    hmp_version, hmp_package = re.findall(re_str, res[i])[0]
                    if not hmp_package:
                        hmp_package = package
                    hmp_package = hmp_package.strip()
                    package = package.strip()
                    hmp_version = hmp_version.strip()
                    if version != hmp_version or package != hmp_package:
                        test.fail(msg)
                else:
                    matches = re.findall(re_str, res[i])
                    for key, val in matches:
                        if key in exception_list:
                            continue
                        if '0x' in val:
                            val = int(val, 16)
                            val_str = str(bin(val))
                            com_str = ""
                            for p in range(3, len(val_str)):
                                if val_str[p] == '1':
                                    com_str += '0'
                                else:
                                    com_str += '1'
                            com_str = "0b" + com_str
                            value = eval(com_str) + 1
                            if val_str[2] == '1':
                                value = -value
                            if value != qmp_o[i][key]:
                                msg += "\nValue in human monitor: '%s'" % value
                                msg += "\nValue in qmp: '%s'" % qmp_o[i][key]
                                test.fail(msg)
                        elif qmp_cmd == "query-block":
                            cmp_str = "u'%s': u'%s'" % (key, val)
                            cmp_s = "u'%s': %s" % (key, val)
                            if '0' == val:
                                cmp_str_b = "u'%s': False" % key
                            elif '1' == val:
                                cmp_str_b = "u'%s': True" % key
                            else:
                                cmp_str_b = cmp_str
                            if (cmp_str not in str(qmp_o[i]) and
                                    cmp_str_b not in str(qmp_o[i]) and
                                    cmp_s not in str(qmp_o[i])):
                                msg += ("\nCan not find '%s', '%s' or '%s' in "
                                        " QMP command output."
                                        % (cmp_s, cmp_str_b, cmp_str))
                                test.fail(msg)
                        elif qmp_cmd == "query-balloon":
                            if (int(val) * 1024 * 1024 != qmp_o[key] and
                                    val not in str(qmp_o[key])):
                                msg += ("\n'%s' is not in QMP command output"
                                        % val)
                                test.fail(msg)
                        else:
                            if (val not in str(qmp_o[i][key]) and
                                    str(bool(int(val))) not in str(qmp_o[i][key])):
                                msg += ("\n'%s' is not in QMP command output"
                                        % val)
                                test.fail(msg)
        elif result_check == "m_in_q":
            res = output.splitlines(True)
            msg = "Key value from human monitor command is not in"
            msg += "QMP command output.\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman monitor command output '%s'" % output
            for i in range(len(res)):
                params = res[i].rstrip().split()
                for param in params:
                    if param.rstrip() in exception_list:
                        continue
                    try:
                        str_o = str(qmp_o.values())
                    except AttributeError:
                        str_o = qmp_o
                    if param.rstrip() not in str(str_o):
                        msg += "\nKey value is '%s'" % param.rstrip()
                        test.fail(msg)
        elif result_check == "m_format_q":
            match_flag = True
            for i in qmp_o:
                if output is None:
                    test.error("QMP output pattern is missing")
                if re.match(output.strip(), str(i)) is None:
                    match_flag = False
            if not match_flag:
                msg = "Output does not match the pattern: '%s'" % output
                test.fail(msg)

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        test.cancel("Host qemu does not support qmp.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    module = params.get("modprobe_module")
    if module:
        logging.info("modprobe the module %s", module)
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
        test.error("Incorrect configuration, no QMP monitor found.")
    hmp_ports = vm.get_monitors_by_type('human')
    if hmp_ports:
        hmp_port = hmp_ports[0]
    else:
        test.error("Incorrect configuration, no QMP monitor found.")
    callback = {"host_cmd": lambda cmd: process.system_output(cmd, shell=True).decode(),
                "guest_cmd": session.cmd_output,
                "monitor_cmd": hmp_port.send_args_cmd,
                "qmp_cmd": qmp_port.send_args_cmd}

    def send_cmd(cmd):
        """ Helper to execute command on ssh/host/monitor """
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            test.error("cmd_type is not supported")

    pre_cmd = params.get("pre_cmd")
    qmp_cmd = params.get("qmp_cmd")
    cmd_type = params.get("event_cmd_type")
    post_cmd = params.get("post_cmd")
    result_check = params.get("cmd_result_check")
    cmd_return_value = params.get("cmd_return_value")
    exception_list = params.get("exception_list", "")

    # Pre command
    if pre_cmd is not None:
        logging.info("Run prepare command '%s'.", pre_cmd)
        pre_o = send_cmd(pre_cmd)
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)
    try:
        # Testing command
        logging.info("Run qmp command '%s'.", qmp_cmd)
        output = qmp_port.send_args_cmd(qmp_cmd)
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, output)
    except qemu_monitor.QMPCmdError as err:
        if params.get("negative_test") == 'yes':
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
                    test.fail("'%s' not in exception '%s'"
                              % (check_pattern, err))
        else:
            test.fail(err)
    except qemu_monitor.MonitorProtocolError as err:
        test.fail(err)
    except Exception as err:
        test.fail(err)

    # Post command
    if post_cmd is not None:
        logging.info("Run post command '%s'.", post_cmd)
        post_o = send_cmd(post_cmd)
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)

    if result_check is not None:
        txt = "Verify that qmp command '%s' works as designed." % qmp_cmd
        logging.info(txt)
        if result_check == "equal" or result_check == "contain":
            if qmp_cmd == "query-name":
                vm_name = params["main_vm"]
                check_result(output, vm_name, exception_list)
            elif qmp_cmd == "query-uuid":
                uuid_input = params["uuid"]
                check_result(output, uuid_input, exception_list)
            else:
                check_result(output, cmd_return_value, exception_list)
        elif result_check == "m_format_q":
            check_result(output, cmd_return_value, exception_list)
        elif 'post' in result_check:
            result_check = result_check.split('_', 1)[1]
            check_result(post_o, cmd_return_value, exception_list)
        else:
            check_result(output, post_o, exception_list)
    session.close()
Beispiel #32
0
def run(test, params, env):
    """
    cpuinfo query test:
    1). run query cmd. e.g -cpu ?cpuid
    2). check the expected info is included in the cmd output.
    3). Boot guest and check the output of qmp command "qom-list-types"
    4). Check the output of qmp command "query-cpu-definitions"
    5). Check the output of qmp command "query-cpu-model-expansion"
    """
    def remove_models(model_list):
        """
        Remove models from cpu_types
        :param model_list: The list of models to be removed
        """
        for model in model_list:
            try:
                cpu_types.remove(model)
            except ValueError:
                logging.warning('The model to be removed is not'
                                ' in the list: %s' % model)
                continue

    def get_patterns(p_list):
        """
        Return all possible patterns for given flags
        :param p_list: The list of flags
        """
        r_list = []
        replace_char = [('_', ''), ('_', '-'), ('.', '-'), ('.', ''),
                        ('.', '_')]
        for p in p_list:
            r_list.extend(list(map(lambda x: p.replace(*x), replace_char)))
        return set(r_list)

    cpu_types = []
    list(map(cpu_types.extend, list(cpu.CPU_TYPES.values())))

    qemu_path = utils_misc.get_qemu_binary(params)
    qemu_version = env_process._get_qemu_version(qemu_path)
    match = re.search(r'[0-9]+\.[0-9]+\.[0-9]+(\-[0-9]+)?', qemu_version)
    host_qemu = match.group(0)
    remove_models(params.objects('remove_list'))
    if host_qemu in VersionInterval('[,4.2.0)'):
        remove_models(params.objects('cpu_model_8'))
    if host_qemu in VersionInterval('[,3.1.0)'):
        remove_models(params.objects('cpu_model_3_1_0'))
    if host_qemu in VersionInterval('[,2.12.0)'):
        remove_models(params.objects('cpu_model_2_12_0'))
    qemu_binary = utils_misc.get_qemu_binary(params)
    logging.info('Query cpu models by qemu command')
    query_cmd = "%s -cpu ? | awk '{print $2}'" % qemu_binary
    qemu_binary_output = process.system_output(
        query_cmd, shell=True).decode().splitlines()
    cpuid_index = qemu_binary_output.index('CPUID')
    cpu_models_binary = qemu_binary_output[1:cpuid_index - 1]
    cpu_flags_binary = qemu_binary_output[cpuid_index + 1:]
    params['start_vm'] = 'yes'
    vm_name = params['main_vm']
    env_process.preprocess_vm(test, params, env, vm_name)
    vm = env.get_vm(vm_name)
    # query cpu model supported by qemu
    logging.info('Query cpu model supported by qemu by qemu monitor')
    qmp_model_output = str(vm.monitor.cmd('qom-list-types'))
    qmp_def_output = str(vm.monitor.cmd('query-cpu-definitions'))

    # Check if all the output contain expected cpu models
    output_list = {
        'qemu-kvm': cpu_models_binary,
        'qom-list-types': qmp_model_output,
        'query-cpu-definitions': qmp_def_output
    }
    missing = dict.fromkeys(output_list.keys(), [])
    for cpu_model in cpu_types:
        logging.info('Check cpu model %s from qemu command output and'
                     ' qemu monitor output' % cpu_model)
        for key, value in output_list.items():
            if cpu_model not in value:
                missing[key].append(cpu_model)
    for key, value in missing.items():
        if value:
            test.fail('%s is missing in the %s output: %s\n' %
                      (', '.join(value), key, output_list[key]))

    # Check if qemu command output matches qmp output
    missing = []
    logging.info('Check if qemu command output matches qemu monitor output')
    for cpu_model in cpu_models_binary:
        if cpu_model not in qmp_model_output:
            missing.append(cpu_model)
    if missing:
        test.fail('The qemu monitor output does not included all the cpu'
                  ' model in qemu command output, missing: \n %s' %
                  ', '.join(missing))

    # Check if the flags in qmp output matches expectation
    args = {'type': 'full', 'model': {'name': vm.cpuinfo.model}}
    output = vm.monitor.cmd('query-cpu-model-expansion', args)
    model = output.get('model')
    model_name = model.get('name')
    if model_name != vm.cpuinfo.model:
        test.fail('Command query-cpu-model-expansion return'
                  ' wrong model: %s' % model_name)
    model_prop = model.get('props')
    for flag in cpu.CPU_TYPES_RE.get(model_name).split(','):
        logging.info('Check flag %s from qemu monitor output' % flag)
        flags = get_patterns(flag.split('|'))
        for f in flags:
            if model_prop.get(f) is True:
                break
        else:
            test.fail('Check cpu model props failed, %s is not True' % flag)

    # Check if the flags in qmp output matches qemu command output
    missing = []
    logging.info('Check if the flags in qemu monitor output matches'
                 ' qemu command output')
    for flag in cpu_flags_binary:
        if flag not in str(output):
            missing.append(flag)
    if missing:
        test.fail('The monitor output does not included all the cpu flags'
                  ' in qemu  command output, missing: \n %s' %
                  ', '.join(missing))
Beispiel #33
0
def run(test, params, env):
    """
    Qemu reboot test:
    1) Get cpu model lists supported by host
    2) Check if current cpu model is in the supported lists, if no, cancel test
    3) Otherwise, boot guest with the cpu model
    4) Check cpu model name in guest
    5) Check cpu flags in guest(only for linux guest)
    6) Reboot guest

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    qemu_binary = utils_misc.get_qemu_binary(params)
    qmp_cmds = [
        '{"execute": "qmp_capabilities"}',
        '{"execute": "query-cpu-definitions", "id": "RAND91"}',
        '{"execute": "quit"}'
    ]
    cmd = "echo -e '{0}' | {1} -qmp stdio -vnc none -M none | grep return |"\
          "grep RAND91".format(r"\n".join(qmp_cmds), qemu_binary)
    output = process.run(cmd,
                         timeout=10,
                         ignore_status=True,
                         shell=True,
                         verbose=False).stdout_text
    out = json.loads(output)["return"]

    model = params["model"]
    model_pattern = params["model_pattern"]
    flags = params["flags"]
    if cpu.get_vendor() == 'intel':
        model_ib = "%s-IBRS" % model
        flag_ib = " ibpb ibrs"
        name_ib = ", IBRS( update)?"
    else:
        model_ib = "%s-IBPB" % model
        flag_ib = " ibpb"
        name_ib = " \\(with IBPB\\)"

    models = [x["name"] for x in out if not x["unavailable-features"]]
    if model_ib in models:
        cpu_model = model_ib
        guest_model = model_pattern % name_ib
        flags += flag_ib
    elif model in models:
        cpu_model = model
        guest_model = model_pattern % ""
    else:
        test.cancel("This host doesn't support cpu model %s" % model)

    params["cpu_model"] = cpu_model
    params["start_vm"] = "yes"
    vm_name = params['main_vm']
    env_process.preprocess_vm(test, params, env, vm_name)

    vm = env.get_vm(vm_name)
    error_context.context("Try to log into guest", logging.info)
    session = vm.wait_for_login()

    error_context.context("Check cpu model inside guest", logging.info)
    cmd = params["get_model_cmd"]
    out = session.cmd_output(cmd)
    if not re.search(guest_model, out):
        test.fail("Guest cpu model is not right")

    if params["os_type"] == "linux":
        check_cpu_flags(params, flags, test, session)

    if params.get("reboot_method"):
        error_context.context("Reboot guest '%s'." % vm.name, logging.info)
        session = vm.reboot(session=session)

    vm.verify_kernel_crash()
    session.close()
Beispiel #34
0
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    test_timeout = int(params["test_timeout"])
    session = vm.wait_for_login(timeout=timeout)
    guest_ver = session.cmd_output("uname -r").strip()
    host_ver = os.uname()[2]

    kvm_userspace_ver_cmd = params.get("kvm_userspace_ver_cmd", "")
    if kvm_userspace_ver_cmd:
        try:
            cmd_result = utils.run(kvm_userspace_ver_cmd)
            qemu_version = cmd_result.stdout.strip()
        except error.CmdError:
            qemu_version = "Unknown"
    else:
        qemu_path = utils_misc.get_qemu_binary(params)
        version_line = utils.system_output("%s -help | head -n 1" % qemu_path)
        matches = re.findall("version .*?,", version_line, re.I)
        if matches:
            qemu_version = " ".join(matches[0].split()[1:]).strip(",")
        else:
            qemu_version = "Unknown"
    # After STEP 1

    try:
        result_name = params.get("result_name", "nfs-perf.RHS")
        result_file_path = utils_misc.get_path(test.resultsdir, result_name)
        result_file = open(result_file_path, 'w')
    except Exception:
        _clean_up(STEP_1)
        raise
Beispiel #35
0
def run(test, params, env):
    """
    Check smbios table :
    1) Get the smbios table from config file,if there is no config option in
       config file, the script will generate the config parameters automately.
    2) Boot a guest with smbios options and/or -M option
    3) Verify if bios options have been emulated correctly.

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    smbios_type = params.get("smbios_type")
    notset_output = params.get("notset_output")
    dmidecode_exp = params.get("dmidecode_exp")
    login_timeout = float(params.get("login_timeout", 360))

    smbios = ""
    if params.get("smbios_type_disable", "no") == "no":
        # Set the smbios parameter, if you have set it in the config file,
        # it'll be honored, else, one will be generated.
        for sm_type in smbios_type.split():
            if sm_type == "Bios":
                smbios_type_number = 0
            elif sm_type == "System":
                smbios_type_number = 1
            smbios += " -smbios type=%s" % smbios_type_number
            dmidecode_key = params.object_params(sm_type).get("dmikeyword")
            dmidecode_key = dmidecode_key.split()
            for key in dmidecode_key:
                cmd = (dmidecode_exp % (smbios_type_number, key))
                default_key_para = decode_to_text(process.system_output(
                    cmd, shell=True).strip())
                smbios_key_para_set = params.object_params(sm_type).get(key,
                                                                        default_key_para)
                smbios += ",%s='%s'" % (key.lower(), smbios_key_para_set)

        if params.get("extra_params"):
            params["extra_params"] += smbios
        else:
            params["extra_params"] = smbios

    support_machine_types = []
    if params.get("traversal_machine_emulated", "no") == "no":
        support_machine_types.append(params.get("machine_type"))
    else:
        qemu_binary = utils_misc.get_qemu_binary(params)
        tmp = utils_misc.get_support_machine_type(qemu_binary, remove_alias=True)[:2]
        (support_machine_types, expect_system_versions) = tmp
        machine_type = params.get("machine_type", "")
        if ':' in machine_type:
            prefix = machine_type.split(':', 1)[0]
            support_machine_types = ["%s:%s" % (prefix, m_type)
                                     for m_type in support_machine_types]

    failures = []
    rhel_system_version = params.get('smbios_system_version') == 'rhel'
    if not rhel_system_version:
        re_pc_lt_2 = re.compile(r'^pc-(i440fx-)?[01].\d+$')
        host_dmidecode_system_version = decode_to_text(
            process.system_output("dmidecode -s system-version"))
    for m_type in support_machine_types:
        if m_type in ("isapc", "xenfv", "xenpv"):
            continue
        params["machine_type"] = m_type
        params["start_vm"] = "yes"

        error_context.context("Boot the vm using -M option:'-M %s', smbios "
                              "para: '%s'" % (m_type, smbios), logging.info)
        env_process.preprocess_vm(test, params, env, params.get("main_vm"))
        vm1 = env.get_vm(params["main_vm"])
        session = vm1.wait_for_login(timeout=login_timeout)

        error_context.context("Check smbios info on guest "
                              "is setted as expected")

        for sm_type in smbios_type.split():
            if sm_type == "Bios":
                smbios_type_number = 0
            elif sm_type == "System":
                smbios_type_number = 1
            dmidecode_key = params.object_params(sm_type).get("dmikeyword")
            dmidecode_key = dmidecode_key.split()
            for key in dmidecode_key:
                cmd = (dmidecode_exp % (smbios_type_number, key))
                smbios_get_para = session.cmd(cmd).strip()
                default_key_para = decode_to_text(process.system_output(
                    cmd, shell=True).strip())
                if params.get("smbios_type_disable", "no") == "no":
                    smbios_set_para = params.object_params(sm_type).get(key,
                                                                        default_key_para)
                else:
                    # The System.Version is different on RHEL and upstream
                    if (rhel_system_version or sm_type != 'System' or
                            key != 'Version'):
                        key_index = support_machine_types.index(m_type)
                        smbios_set_para = expect_system_versions[key_index]
                    elif re_pc_lt_2.match(m_type):
                        # pc<2.0 inherits host system-version
                        smbios_set_para = host_dmidecode_system_version
                    else:
                        # Newer use machine-type
                        smbios_set_para = m_type

                if smbios_get_para == notset_output:
                    smbios_get_para = default_key_para

                # make UUID check case insensitive
                if key == "UUID":
                    smbios_set_para = smbios_set_para.lower()
                    smbios_get_para = smbios_get_para.lower()

                if (smbios_set_para not in smbios_get_para):
                    e_msg = ("%s.%s mismatch, Set '%s' but guest is : '%s'"
                             % (sm_type, key, smbios_set_para,
                                smbios_get_para))
                    failures.append(e_msg)

        session.close()
        if params.get("traversal_machine_emulated", "no") == "yes":
            vm1.destroy(gracefully=False)

    error_context.context("")
    if failures:
        test.fail("smbios table test reported %s failures:\n%s" %
                  (len(failures), "\n".join(failures)))
Beispiel #36
0
def run(test, params, env):
    """
    Test qmp event notification, this case will:
    1) Start VM with qmp enable.
    2) Connect to qmp port then run qmp_capabilities command.
    3) Initiate the qmp command defined in config (qmp_cmd)
    4) Verify that qmp command works as designed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """
    def check_result(qmp_o, output=None):
        """
        Check test result with difference way accoriding to
        result_check.
        result_check = equal, will compare cmd_return_value with qmp
                       command output.
        result_check = contain, will try to find cmd_return_value in qmp
                       command output.
        result_check = m_equal_q, will compare key value in monitor command
                       output and qmp command output.
        result_check = m_in_q, will try to find monitor command output's key
                       value in qmp command output.
        result_check = m_format_q, will try to match the output's format with
                       check pattern.

        :param qmp_o: output from pre_cmd, qmp_cmd or post_cmd.
        :param o: output from pre_cmd, qmp_cmd or post_cmd or an execpt
        result set in config file.
        """
        if result_check == "equal":
            value = output
            if value != str(qmp_o):
                raise error.TestFail("QMP command return value does not match "
                                     "the expect result. Expect result: '%s'\n"
                                     "Actual result: '%s'" % (value, qmp_o))
        elif result_check == "contain":
            values = output.split(';')
            for value in values:
                if value.strip() not in str(qmp_o):
                    raise error.TestFail("QMP command output does not contain "
                                         "expect result. Expect result: '%s'\n"
                                         "Actual result: '%s'" %
                                         (value, qmp_o))
        elif result_check == "not_contain":
            values = output.split(';')
            for value in values:
                if value in str(qmp_o):
                    raise error.TestFail("QMP command output contains unexpect"
                                         " result. Unexpect result: '%s'\n"
                                         "Actual result: '%s'" %
                                         (value, qmp_o))
        elif result_check == "m_equal_q":
            msg = "QMP command ouput is not equal to in human monitor command."
            msg += "\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman command output: '%s'" % output
            res = output.splitlines(True)
            if type(qmp_o) != type(res):
                len_o = 1
            else:
                len_o = len(qmp_o)
            if len(res) != len_o:
                raise error.TestFail(msg)
            re_str = r'([^ \t\n\r\f\v=]*)=([^ \t\n\r\f\v=]*)'
            for i in range(len(res)):
                if qmp_cmd == "query-version":
                    version = qmp_o['qemu']
                    version = "%s.%s.%s" % (version['major'], version['minor'],
                                            version['micro'])
                    package = qmp_o['package']
                    re_str = r"([0-9]+\.[0-9]+\.[0-9]+)\s*(\(\S*\))?"
                    hmp_version, hmp_package = re.findall(re_str, res[i])[0]
                    if not hmp_package:
                        hmp_package = package
                    if version != hmp_version or package != hmp_package:
                        raise error.TestFail(msg)
                else:
                    matches = re.findall(re_str, res[i])
                    for key, val in matches:
                        if '0x' in val:
                            val = long(val, 16)
                            if val != qmp_o[i][key]:
                                msg += "\nValue in human monitor: '%s'" % val
                                msg += "\nValue in qmp: '%s'" % qmp_o[i][key]
                                raise error.TestFail(msg)
                        elif qmp_cmd == "query-block":
                            cmp_str = "u'%s': u'%s'" % (key, val)
                            cmp_s = "u'%s': %s" % (key, val)
                            if '0' == val:
                                cmp_str_b = "u'%s': False" % key
                            elif '1' == val:
                                cmp_str_b = "u'%s': True" % key
                            else:
                                cmp_str_b = cmp_str
                            if (cmp_str not in str(qmp_o[i])
                                    and cmp_str_b not in str(qmp_o[i])
                                    and cmp_s not in str(qmp_o[i])):
                                msg += ("\nCan not find '%s', '%s' or '%s' in "
                                        " QMP command output." %
                                        (cmp_s, cmp_str_b, cmp_str))
                                raise error.TestFail(msg)
                        elif qmp_cmd == "query-balloon":
                            if (int(val) * 1024 * 1024 != qmp_o[key]
                                    and val not in str(qmp_o[key])):
                                msg += ("\n'%s' is not in QMP command output" %
                                        val)
                                raise error.TestFail(msg)
                        else:
                            if (val not in str(qmp_o[i][key]) and str(
                                    bool(int(val))) not in str(qmp_o[i][key])):
                                msg += ("\n'%s' is not in QMP command output" %
                                        val)
                                raise error.TestFail(msg)
        elif result_check == "m_in_q":
            res = output.splitlines(True)
            msg = "Key value from human monitor command is not in"
            msg += "QMP command output.\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman monitor command output '%s'" % output
            for i in range(len(res)):
                params = res[i].rstrip().split()
                for param in params:
                    try:
                        str_o = str(qmp_o.values())
                    except AttributeError:
                        str_o = qmp_o
                    if param.rstrip() not in str(str_o):
                        msg += "\nKey value is '%s'" % param.rstrip()
                        raise error.TestFail(msg)
        elif result_check == "m_format_q":
            match_flag = True
            for i in qmp_o:
                if output is None:
                    raise error.TestError("QMP output pattern is missing")
                if re.match(output.strip(), str(i)) is None:
                    match_flag = False
            if not match_flag:
                msg = "Output does not match the pattern: '%s'" % output
                raise error.TestFail(msg)

    def qmp_cpu_check(output):
        """ qmp_cpu test check """
        last_cpu = int(params['smp']) - 1
        for out in output:
            cpu = out.get('CPU')
            if cpu is None:
                raise error.TestFail("'CPU' index is missing in QMP output "
                                     "'%s'" % out)
            else:
                current = out.get('current')
                if current is None:
                    raise error.TestFail("'current' key is missing in QMP "
                                         "output '%s'" % out)
                elif cpu < last_cpu:
                    if current is False:
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
                                             "'False', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
                elif cpu == last_cpu:
                    if current is True:
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
                                             "'True', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
                elif cpu <= last_cpu:
                    continue
                else:
                    raise error.TestFail("Incorrect CPU index '%s' (corrupted "
                                         "or higher than no_cpus).\n%s" %
                                         (cpu, out))

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        raise error.TestNAError("Host qemu does not support qmp.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    module = params.get("modprobe_module")
    if module:
        error.context("modprobe the module %s" % module, logging.info)
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
        raise error.TestError("Incorrect configuration, no QMP monitor found.")
    hmp_ports = vm.get_monitors_by_type('human')
    if hmp_ports:
        hmp_port = hmp_ports[0]
    else:
        raise error.TestError("Incorrect configuration, no QMP monitor found.")
    callback = {
        "host_cmd": utils.system_output,
        "guest_cmd": session.get_command_output,
        "monitor_cmd": hmp_port.send_args_cmd,
        "qmp_cmd": qmp_port.send_args_cmd
    }

    def send_cmd(cmd):
        """ Helper to execute command on ssh/host/monitor """
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            raise error.TestError("cmd_type is not supported")

    pre_cmd = params.get("pre_cmd")
    qmp_cmd = params.get("qmp_cmd")
    cmd_type = params.get("event_cmd_type")
    post_cmd = params.get("post_cmd")
    result_check = params.get("cmd_result_check")
    cmd_return_value = params.get("cmd_return_value")

    # HOOKs
    if result_check == 'qmp_cpu':
        pre_cmd = "cpu index=%d" % (int(params['smp']) - 1)

    # Pre command
    if pre_cmd is not None:
        error.context("Run prepare command '%s'." % pre_cmd, logging.info)
        pre_o = send_cmd(pre_cmd)
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)
    try:
        # Testing command
        error.context("Run qmp command '%s'." % qmp_cmd, logging.info)
        output = qmp_port.send_args_cmd(qmp_cmd)
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, output)
    except qemu_monitor.QMPCmdError, err:
        if params.get("negative_test") == 'yes':
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
                    raise error.TestFail("'%s' not in exception '%s'" %
                                         (check_pattern, err))
        else:
            raise error.TestFail(err)
Beispiel #37
0
def run(test, params, env):
    """
    Test hotplug of PCI devices.

    (Elements between [] are configurable test parameters)
    1) PCI add one/multi device (NIC / block) with(or without) repeat
    2) Compare output of monitor command 'info pci'.
    3) Compare output of guest command [reference_cmd].
    4) Verify whether pci_model is shown in [pci_find_cmd].
    5) Check whether the newly added PCI device works fine.
    6) PCI delete the device, verify whether could remove the PCI device.
    7) reboot VM after guest wakeup form S3/S4 status (Optional Step).

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    # Select an image file
    def find_image(pci_num):
        image_params = params.object_params("%s" % img_list[pci_num + 1])
        o = storage.get_image_filename(image_params, data_dir.get_data_dir())
        return o

    def pci_add_nic(pci_num):
        pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % pci_model
        return pci_add(pci_add_cmd)

    def pci_add_block(pci_num):
        image_filename = find_image(pci_num)
        pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
                       (image_filename, pci_model))
        return pci_add(pci_add_cmd)

    def pci_add(pci_add_cmd):
        error.context("Adding pci device with command 'pci_add'")
        add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        pci_info.append(['', '', add_output, pci_model])

        if "OK domain" not in add_output:
            raise error.TestFail("Add PCI device failed. "
                                 "Monitor command is: %s, Output: %r" %
                                 (pci_add_cmd, add_output))
        return vm.monitor.info("pci")

    def is_supported_device(dev):
        # Probe qemu to verify what is the supported syntax for PCI hotplug
        cmd_output = vm.monitor.human_monitor_cmd("?")
        if len(re.findall("\ndevice_add", cmd_output)) > 0:
            cmd_type = "device_add"
        elif len(re.findall("\npci_add", cmd_output)) > 0:
            cmd_type = "pci_add"
        else:
            raise error.TestError("Unknow version of qemu")

        # Probe qemu for a list of supported devices
        probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type)
        devices_supported = [j.strip('"') for j in
                             re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"',
                                        probe_output, re.MULTILINE)]
        logging.debug("QEMU reported the following supported devices for "
                      "PCI hotplug: %s", devices_supported)
        return (dev in devices_supported)

    def verify_supported_device(dev):
        if not is_supported_device(dev):
            raise error.TestError("%s doesn't support device: %s" %
                                  (cmd_type, dev))

    def device_add_nic(pci_num, queues=1):
        device_id = pci_type + "-" + utils_misc.generate_random_id()
        pci_info.append([device_id, device_id])

        pci_model = params.get("pci_model")
        if pci_model == "virtio":
            pci_model = "virtio-net-pci"
        verify_supported_device(pci_model)
        pci_add_cmd = "device_add id=%s,driver=%s" % (pci_info[pci_num][1],
                                                      pci_model)
        if queues > 1 and "virtio" in pci_model:
            pci_add_cmd += ",mq=on"
        return device_add(pci_num, pci_add_cmd)

    def device_add_block(pci_num, queues=1):
        device_id = pci_type + "-" + utils_misc.generate_random_id()
        pci_info.append([device_id, device_id])

        image_format = params.get("image_format_%s" % img_list[pci_num + 1])
        if not image_format:
            image_format = params.get("image_format", "qcow2")
        image_filename = find_image(pci_num)

        pci_model = params.get("pci_model")
        controller_model = None
        if pci_model == "virtio":
            pci_model = "virtio-blk-pci"

        if pci_model == "scsi":
            pci_model = "scsi-disk"
            if arch.ARCH == 'ppc64':
                controller_model = "spapr-vscsi"
            else:
                controller_model = "lsi53c895a"
            verify_supported_device(controller_model)
            controller_id = "controller-" + device_id
            controller_add_cmd = ("device_add %s,id=%s" %
                                  (controller_model, controller_id))
            error.context("Adding SCSI controller.")
            vm.monitor.send_args_cmd(controller_add_cmd)

        verify_supported_device(pci_model)
        if drive_cmd_type == "drive_add":
            driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        elif drive_cmd_type == "__com.redhat_drive_add":
            driver_add_cmd = ("%s file=%s,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        # add driver.
        error.context("Adding driver.")
        vm.monitor.send_args_cmd(driver_add_cmd, convert=False)

        pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" %
                       (pci_info[pci_num][1], pci_model, pci_info[pci_num][0]))
        return device_add(pci_num, pci_add_cmd)

    def device_add(pci_num, pci_add_cmd):
        error.context("Adding pci device with command 'device_add'")
        if vm.monitor.protocol == 'qmp':
            add_output = vm.monitor.send_args_cmd(pci_add_cmd)
        else:
            add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        pci_info[pci_num].append(add_output)
        pci_info[pci_num].append(pci_model)

        after_add = vm.monitor.info("pci")
        if pci_info[pci_num][1] not in str(after_add):
            logging.error("Could not find matched id in monitor:"
                          " %s" % pci_info[pci_num][1])
            raise error.TestFail("Add device failed. Monitor command is: %s"
                                 ". Output: %r" % (pci_add_cmd, add_output))
        return after_add

    # Hot add a pci device
    def add_device(pci_num, queues=1):
        info_pci_ref = vm.monitor.info("pci")
        reference = session.cmd_output(reference_cmd)

        try:
            # get function for adding device.
            add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)]
        except Exception:
            raise error.TestError("No function for adding '%s' dev with '%s'" %
                                  (pci_type, cmd_type))
        after_add = None
        if add_fuction:
            # Do add pci device.
            after_add = add_fuction(pci_num, queues)

        try:
            # Define a helper function to compare the output
            def _new_shown():
                o = session.cmd_output(reference_cmd)
                return o != reference

            # Define a helper function to catch PCI device string
            def _find_pci():
                output = session.cmd_output(params.get("find_pci_cmd"))
                output = map(string.strip, output.splitlines())
                ref = map(string.strip, reference.splitlines())
                output = [_ for _ in output if _ not in ref]
                output = "\n".join(output)
                if re.search(params.get("match_string"), output, re.I | re.M):
                    return True
                return False

            error.context("Start checking new added device")
            # Compare the output of 'info pci'
            if after_add == info_pci_ref:
                raise error.TestFail("No new PCI device shown after executing "
                                     "monitor command: 'info pci'")

            secs = int(params.get("wait_secs_for_hook_up"))
            if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3):
                raise error.TestFail("No new device shown in output of command "
                                     "executed inside the guest: %s" %
                                     reference_cmd)

            if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3):
                raise error.TestFail("PCI %s %s device not found in guest. "
                                     "Command was: %s" %
                                     (pci_model, pci_type,
                                      params.get("find_pci_cmd")))

            # Test the newly added device
            try:
                session.cmd(params.get("pci_test_cmd") % (pci_num + 1))
            except aexpect.ShellError, e:
                raise error.TestFail("Check for %s device failed after PCI "
                                     "hotplug. Output: %r" % (pci_type, e.output))

        except Exception:
            pci_del(pci_num, ignore_failure=True)
            raise

    # Hot delete a pci device
    def pci_del(pci_num, ignore_failure=False):
        def _device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != before_del

        before_del = vm.monitor.info("pci")
        if cmd_type == "pci_add":
            slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1])
            cmd = "pci_del pci_addr=%s" % hex(slot_id)
            vm.monitor.send_args_cmd(cmd, convert=False)
        elif cmd_type == "device_add":
            cmd = "device_del id=%s" % pci_info[pci_num][1]
            vm.monitor.send_args_cmd(cmd)

        if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1)
                and not ignore_failure):
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" %
                                 (pci_info[pci_num][3], cmd))

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=timeout)

    test_timeout = int(params.get("hotplug_timeout", 360))
    reference_cmd = params["reference_cmd"]
    # Test if it is nic or block
    pci_type = params["pci_type"]
    pci_model = params["pci_model"]

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
        session.cmd("modprobe %s" % module)

    # check monitor type
    qemu_binary = utils_misc.get_qemu_binary(params)
    qemu_binary = utils_misc.get_path(test.bindir, qemu_binary)
    # Probe qemu to verify what is the supported syntax for PCI hotplug
    if vm.monitor.protocol == 'qmp':
        cmd_output = vm.monitor.info("commands")
    else:
        cmd_output = vm.monitor.human_monitor_cmd("help", debug=False)

    cmd_type = utils_misc.find_substring(str(cmd_output), "device_add",
                                         "pci_add")
    if not cmd_output:
        raise error.TestError("Could find a suitable method for hotplugging"
                              " device in this version of qemu")

    # Determine syntax of drive hotplug
    # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6
    # drive_add == qemu-kvm-0.13 onwards
    drive_cmd_type = utils_misc.find_substring(str(cmd_output),
                                               "__com.redhat_drive_add", "drive_add")
    if not drive_cmd_type:
        raise error.TestError("Could find a suitable method for hotplugging"
                              " drive in this version of qemu")

    local_functions = locals()

    pci_num_range = int(params.get("pci_num"))
    queues = int(params.get("queues", 1))
    rp_times = int(params.get("repeat_times"))
    img_list = params.get("images").split()
    context_msg = "Running sub test '%s' %s"
    for j in range(rp_times):
        # pci_info is a list of list.
        # each element 'i' has 4 members:
        # pci_info[i][0] == device drive id, only used for device_add
        # pci_info[i][1] == device id, only used for device_add
        # pci_info[i][2] == output of device add command
        # pci_info[i][3] == device module name.
        pci_info = []
        for pci_num in xrange(pci_num_range):
            sub_type = params.get("sub_type_before_plug")
            if sub_type:
                error.context(context_msg % (sub_type, "before hotplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)

            error.context("Start hot-adding pci device, repeat %d" % j,
                          logging.info)
            add_device(pci_num, queues)

            sub_type = params.get("sub_type_after_plug")
            if sub_type:
                error.context(context_msg % (sub_type, "after hotplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)
        for pci_num in xrange(pci_num_range):
            sub_type = params.get("sub_type_before_unplug")
            if sub_type:
                error.context(context_msg % (sub_type, "before hotunplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)

            error.context("start hot-deleting pci device, repeat %d" % j,
                          logging.info)
            pci_del(-(pci_num + 1))

            sub_type = params.get("sub_type_after_unplug")
            if sub_type:
                error.context(context_msg % (sub_type, "after hotunplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)

    if params.get("reboot_vm", "no") == "yes":
        vm.reboot()
Beispiel #38
0
def run(test, params, env):
    """
    Test qmp event notification, this case will:
    1) Start VM with qmp enable.
    2) Connect to qmp port then run qmp_capabilities command.
    3) Initiate the qmp command defined in config (qmp_cmd)
    4) Verify that qmp command works as designed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """

    def check_list(qmp_o, key, val=None, check_item_in_pair=True):
        """
        Check if the expect key, val are contained in QMP output qmp_o.

        :param qmp_o: output of QMP command
        :type qmp_o: list
        :param key: expect result
        :type key: str
        :param val: expect result
        :type val: str or None(if check_item_in_pair=False)
        :param check_item_in_pair: If expect result is dict (True) or str (False)
        :type check_item_in_pair: bool.

        :return check result
        :rtype: bool
        """
        for element in qmp_o:
            if isinstance(element, dict):
                if _check_dict(element, key, val, check_item_in_pair):
                    return True
            elif isinstance(element, list):
                if check_list(element, key, val, check_item_in_pair):
                    return True
            elif element != '' and not check_item_in_pair:
                if strict_match:
                    if operator.eq(key, element):
                        return True
                else:
                    if key in str(element):
                        return True
        return False

    def _check_dict(dic, key, val, check_item_in_pair=True):
        """
        Check if the expect key, val are contained in QMP output dic.

        :param dic: content of QMP command return value
        :type dic: dict
        :param key: expect result
        :type key: str
        :param val: expect result
        :type val: str or None(if check_item_in_pair=False)
        :param check_item_in_pair: If expect result is dict or str
        :type check_item_in_pair: bool. Means expect result is dict or str.

        :return check result
        :rtype: bool
        """
        if key in dic and not check_item_in_pair:
            return True
        elif key in dic and val == dic[key]:
            return True
        else:
            for value in dic.values():
                if isinstance(value, dict):
                    if _check_dict(value, key, val, check_item_in_pair):
                        return True
                elif isinstance(value, list):
                    if check_list(value, key, val, check_item_in_pair):
                        return True
                elif value != '' and not check_item_in_pair:
                    if strict_match:
                        if operator.eq(key, value):
                            return True
                    else:
                        if key in str(value):
                            return True
            return False

    def check_result(qmp_o, expect_o=None):
        """
        Check test result with difference way according to result_check.
        result_check = equal, expect_o should equal to qmp_o.
        result_check = contain, expect_o should be contained in qmp_o
        result_check = not_contain, expect_o should not be contained in qmp_o.

        :param qmp_o: output from pre_cmd, qmp_cmd or post_cmd.
        :type qmp_o: list
        :param expect_o: the expect result.
        :type expect_o: list
        """
        logging.info("Expect result is %s" % expect_o)
        logging.info("Actual result that get from qmp_cmd/post_cmd is %s" % qmp_o)
        if result_check == "equal":
            if not operator.eq(qmp_o, expect_o):
                test.fail("QMP output does not equal to the expect result.\n "
                          "Expect result: '%s'\n"
                          "Actual result: '%s'" % (expect_o, qmp_o))
        elif result_check == "contain":
            for o in expect_o:
                if isinstance(o, dict):
                    for key, val in o.items():
                        result = check_list(qmp_o, key, val)
                        if not result:
                            break
                elif isinstance(o, str):
                    result = check_list(qmp_o, o, check_item_in_pair=False)

                if result:
                    logging.info("QMP output contain the expect value %s" % o)
                else:
                    test.fail("QMP output does not contain the expect value.\n"
                              "Missed expect value: '%s'\n"
                              "Actual result: '%s'\n" % (o, qmp_o))
        elif result_check == "not_contain":
            for o in expect_o:
                if isinstance(o, dict):
                    for key, val in o.items():
                        result = check_list(qmp_o, key, val)
                        if result:
                            break
                elif isinstance(o, str):
                    result = check_list(qmp_o, o, check_item_in_pair=False)

                if result:
                    test.fail("QMP output contain the unexpect result.\n"
                              "Unexpect result: '%s'\n"
                              "Actual result: '%s'" % (o, qmp_o))

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        test.cancel("Host qemu does not support qmp.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    module = params.get("modprobe_module")
    if module:
        logging.info("modprobe the module %s", module)
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
        test.error("Incorrect configuration, no QMP monitor found.")
    callback = {"host_cmd": lambda cmd: process.system_output(cmd, shell=True).decode(),
                "guest_cmd": session.cmd_output,
                "qmp_cmd": qmp_port.send_args_cmd}

    def send_cmd(cmd):
        """ Helper to execute command on host/ssh guest/qmp monitor """
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            test.error("cmd_type is not supported")

    pre_cmd = params.get("pre_cmd")
    qmp_cmd = params.get("qmp_cmd")
    post_cmd = params.get("post_cmd")
    cmd_type = params.get("event_cmd_type")
    result_check = params.get("cmd_result_check")
    strict_match = params.get("strict_match", "yes") == 'yes'
    expect_o = eval(params.get("cmd_return_value", "[]"))

    # Pre command
    if pre_cmd is not None:
        logging.info("Run prepare command '%s'.", pre_cmd)
        pre_o = send_cmd(pre_cmd)
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)

    # qmp command
    try:
        # Testing command
        logging.info("Run qmp command '%s'.", qmp_cmd)
        qmp_o = qmp_port.send_args_cmd(qmp_cmd)
        if not isinstance(qmp_o, list):
            qmp_o = [qmp_o]
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, qmp_o)
    except qemu_monitor.QMPCmdError as err:
        if params.get("negative_test") == 'yes':
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
                    test.fail("'%s' not in exception '%s'"
                              % (check_pattern, err))
        else:
            test.fail(err)
    except qemu_monitor.MonitorProtocolError as err:
        test.fail(err)
    except Exception as err:
        test.fail(err)

    # sleep 10s to make netdev_del take effect
    if 'netdev_del' in qmp_cmd:
        time.sleep(10)

    # Post command
    if post_cmd is not None:
        logging.info("Run post command '%s'.", post_cmd)
        post_o = send_cmd(post_cmd)
        if not isinstance(post_o, list):
            post_o = [post_o]
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)

    if result_check == "equal" or result_check == "contain":
        logging.info("Verify qmp command '%s' works as designed." % qmp_cmd)
        if qmp_cmd == "query-name":
            vm_name = params["main_vm"]
            expect_o = [{'name': vm_name}]
        elif qmp_cmd == "query-uuid":
            uuid_input = params["uuid"]
            expect_o = [{'UUID': uuid_input}]
        elif qmp_cmd == "query-version":
            qemu_version_cmd = "rpm -qa | grep -E 'qemu-kvm(-(rhev|ma))?-[0-9]' | head -n 1"
            host_arch = platform.machine()
            qemu_version = callback["host_cmd"](qemu_version_cmd).replace('.%s' % host_arch, '')
            expect_o = [str(qemu_version)]
        elif qmp_cmd == "query-block":
            images = params['images'].split()
            image_info = {}
            for image in images:
                image_params = params.object_params(image)
                image_format = image_params['image_format']
                image_drive = "drive_%s" % image
                image_info['device'] = image_drive
                image_info['qdev'] = image
                image_info['format'] = image_format
                expect_o.append(image_info)
        check_result(qmp_o, expect_o)
    elif result_check.startswith("post_"):
        logging.info("Verify post qmp command '%s' works as designed." % post_cmd)
        result_check = result_check.split('_', 1)[1]
        check_result(post_o, expect_o)
    session.close()
Beispiel #39
0
def run(test, params, env):
    """
    Test hotplug of PCI devices.

    (Elements between [] are configurable test parameters)
    1) PCI add one/multi device (NIC / block) with(or without) repeat
    2) Compare output of monitor command 'info pci'.
    3) Compare output of guest command [reference_cmd].
    4) Verify whether pci_model is shown in [pci_find_cmd].
    5) Check whether the newly added PCI device works fine.
    6) PCI delete the device, verify whether could remove the PCI device.
    7) reboot VM after guest wakeup form S3/S4 status (Optional Step).

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

    # Select an image file
    def find_image(pci_num):
        image_params = params.object_params("%s" % img_list[pci_num + 1])
        o = storage.get_image_filename(image_params, data_dir.get_data_dir())
        return o

    def pci_add_nic(pci_num):
        pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % pci_model
        return pci_add(pci_add_cmd)

    def pci_add_block(pci_num):
        image_filename = find_image(pci_num)
        pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
                       (image_filename, pci_model))
        return pci_add(pci_add_cmd)

    def pci_add(pci_add_cmd):
        error.context("Adding pci device with command 'pci_add'", logging.info)
        add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        pci_info.append(['', '', add_output, pci_model])

        if "OK domain" not in add_output:
            raise error.TestFail("Add PCI device failed. "
                                 "Monitor command is: %s, Output: %r" %
                                 (pci_add_cmd, add_output))
        return vm.monitor.info("pci")

    def is_supported_command(cmd1, cmd2):
        try:
            vm.monitor.verify_supported_cmd(cmd1)
            return cmd1
        except qemu_monitor.MonitorNotSupportedCmdError:
            try:
                vm.monitor.verify_supported_cmd(cmd2)
                return cmd2
            except qemu_monitor.MonitorNotSupportedCmdError:
                pass
        return None

    def is_supported_device(dev):
        # Probe qemu to verify what is the supported syntax for PCI hotplug
        cmd_type = is_supported_command("device_add", "pci_add")
        if not cmd_type:
            raise error.TestError("Unknown version of qemu")

        # Probe qemu for a list of supported devices
        probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type,
                                                    debug=False)
        devices_supported = [
            j.strip('"') for j in re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"',
                                             probe_output, re.MULTILINE)
        ]
        logging.debug(
            "QEMU reported the following supported devices for "
            "PCI hotplug: %s", devices_supported)
        return (dev in devices_supported)

    def verify_supported_device(dev):
        if not is_supported_device(dev):
            raise error.TestError("%s doesn't support device: %s" %
                                  (cmd_type, dev))

    def device_add_nic(pci_num, queues=1):
        device_id = pci_type + "-" + utils_misc.generate_random_id()
        pci_info.append([device_id, device_id])

        pci_model = params.get("pci_model")
        if pci_model == "virtio":
            pci_model = "virtio-net-pci"
        verify_supported_device(pci_model)
        pci_add_cmd = "device_add id=%s,driver=%s" % (pci_info[pci_num][1],
                                                      pci_model)
        if queues > 1 and "virtio" in pci_model:
            pci_add_cmd += ",mq=on"
        return device_add(pci_num, pci_add_cmd)

    def device_add_block(pci_num, queues=1):
        device_id = pci_type + "-" + utils_misc.generate_random_id()
        pci_info.append([device_id, device_id])

        image_format = params.get("image_format_%s" % img_list[pci_num + 1])
        if not image_format:
            image_format = params.get("image_format", "qcow2")
        image_filename = find_image(pci_num)

        pci_model = params.get("pci_model")
        controller_model = None
        if pci_model == "virtio":
            pci_model = "virtio-blk-pci"

        if pci_model == "scsi" or pci_model == "scsi-hd":
            if pci_model == "scsi":
                pci_model = "scsi-disk"
                if arch.ARCH in ('ppc64', 'ppc64le'):
                    controller_model = "spapr-vscsi"
                else:
                    controller_model = "lsi53c895a"
            if pci_model == "scsi-hd":
                controller_model = "virtio-scsi-pci"
            verify_supported_device(controller_model)
            controller_id = "controller-" + device_id
            if vm.monitor.protocol == "human":
                controller_add_cmd = ("device_add %s,id=%s" %
                                      (controller_model, controller_id))
            else:
                controller_add_cmd = ("device_add driver=%s,id=%s" %
                                      (controller_model, controller_id))
            error.context("Adding SCSI controller.", logging.info)
            vm.monitor.send_args_cmd(controller_add_cmd, convert=False)

        verify_supported_device(pci_model)
        if drive_cmd_type == "drive_add":
            driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        elif drive_cmd_type == "__com.redhat_drive_add":
            driver_add_cmd = ("%s file=%s,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        # add block device to vm device container
        image_name = img_list[pci_num + 1]
        image_params = params.object_params(image_name)
        image_name = pci_info[pci_num][0]
        blk_insert = vm.devices.images_define_by_params(
            image_name, image_params, 'disk')
        vm.devices.insert(blk_insert)
        env.register_vm(vm.name, vm)

        # add driver.
        error.context("Adding driver.", logging.info)
        vm.monitor.send_args_cmd(driver_add_cmd, convert=False)

        pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" %
                       (pci_info[pci_num][1], pci_model, pci_info[pci_num][0]))
        return device_add(pci_num, pci_add_cmd)

    def device_add(pci_num, pci_add_cmd):
        error.context("Adding pci device with command 'device_add'",
                      logging.info)
        if vm.monitor.protocol == 'qmp':
            add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        else:
            add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        pci_info[pci_num].append(add_output)
        pci_info[pci_num].append(pci_model)

        after_add = vm.monitor.info("pci")
        if pci_info[pci_num][1] not in str(after_add):
            logging.error("Could not find matched id in monitor:"
                          " %s" % pci_info[pci_num][1])
            raise error.TestFail("Add device failed. Monitor command is: %s"
                                 ". Output: %r" % (pci_add_cmd, add_output))
        return after_add

    # Hot add a pci device
    def add_device(pci_num, queues=1):
        info_pci_ref = vm.monitor.info("pci")
        reference = session.cmd_output(reference_cmd)

        try:
            # get function for adding device.
            add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)]
        except Exception:
            raise error.TestError("No function for adding '%s' dev with '%s'" %
                                  (pci_type, cmd_type))
        after_add = None
        if add_fuction:
            # Do add pci device.
            after_add = add_fuction(pci_num, queues)

        try:
            # Define a helper function to compare the output
            def _new_shown():
                o = session.cmd_output(reference_cmd)
                return o != reference

            # Define a helper function to catch PCI device string
            def _find_pci():
                output = session.cmd_output(params.get("find_pci_cmd"))
                output = map(string.strip, output.splitlines())
                ref = map(string.strip, reference.splitlines())
                output = [_ for _ in output if _ not in ref]
                output = "\n".join(output)
                if re.search(params.get("match_string"), output, re.I | re.M):
                    return True
                return False

            error.context("Start checking new added device", logging.info)
            # Compare the output of 'info pci'
            if after_add == info_pci_ref:
                raise error.TestFail("No new PCI device shown after executing "
                                     "monitor command: 'info pci'")

            secs = int(params.get("wait_secs_for_hook_up"))
            if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3):
                raise error.TestFail(
                    "No new device shown in output of command "
                    "executed inside the guest: %s" % reference_cmd)

            if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3):
                raise error.TestFail(
                    "PCI %s %s device not found in guest. "
                    "Command was: %s" %
                    (pci_model, pci_type, params.get("find_pci_cmd")))

            # Test the newly added device
            try:
                if params.get("pci_test_cmd"):
                    test_cmd = re.sub("PCI_NUM", "%s" % (pci_num + 1),
                                      params.get("pci_test_cmd"))
                    session.cmd(test_cmd, timeout=disk_op_timeout)
            except aexpect.ShellError, e:
                raise error.TestFail("Check for %s device failed after PCI "
                                     "hotplug. Output: %r" %
                                     (pci_type, e.output))

        except Exception:
            pci_del(pci_num, ignore_failure=True)
            raise

    # Hot delete a pci device
    def pci_del(pci_num, ignore_failure=False):
        def _device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != before_del

        before_del = vm.monitor.info("pci")
        blk_removed = []
        if cmd_type == "pci_add":
            slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1])
            cmd = "pci_del pci_addr=%s" % hex(slot_id)
            vm.monitor.send_args_cmd(cmd, convert=False)
            blk_removed.append(pci_info[pci_num][1])
        elif cmd_type == "device_add":
            if vm.monitor.protocol == "human":
                cmd = "device_del %s" % pci_info[pci_num][1]
            else:
                cmd = "device_del id=%s" % pci_info[pci_num][1]
            vm.monitor.send_args_cmd(cmd, convert=False)
            if params.get("cmd_after_unplug_dev"):
                cmd = re.sub("PCI_NUM", "%s" % (pci_num + 1),
                             params.get("cmd_after_unplug_dev"))
                session.cmd(cmd, timeout=disk_op_timeout)
            blk_removed.append(pci_info[pci_num][1])
            pci_model = params.get("pci_model")
            if pci_model == "scsi" or pci_model == "scsi-hd":
                controller_id = "controller-" + pci_info[pci_num][0]
                if vm.monitor.protocol == "human":
                    controller_del_cmd = "device_del %s" % controller_id
                else:
                    controller_del_cmd = "device_del id=%s" % controller_id
                error.context("Deleting SCSI controller.", logging.info)
                vm.monitor.send_args_cmd(controller_del_cmd, convert=False)
                blk_removed.append(controller_id)

        if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1)
                and not ignore_failure):
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" %
                                 (pci_info[pci_num][3], cmd))
        # Remove the device from vm device container
        for device in vm.devices:
            if device.str_short() in blk_removed:
                vm.devices.remove(device)
        env.register_vm(vm.name, vm)

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=timeout)

    test_timeout = int(params.get("hotplug_timeout", 360))
    disk_op_timeout = int(params.get("disk_op_timeout", 360))
    reference_cmd = params["reference_cmd"]
    # Test if it is nic or block
    pci_type = params["pci_type"]
    pci_model = params["pci_model"]

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
        session.cmd("modprobe %s" % module)

    # check monitor type
    qemu_binary = utils_misc.get_qemu_binary(params)
    qemu_binary = utils_misc.get_path(test.bindir, qemu_binary)
    # Probe qemu to verify what is the supported syntax for PCI hotplug
    cmd_type = is_supported_command("device_add", "pci_add")
    if not cmd_type:
        raise error.TestError("Could find a suitable method for hotplugging"
                              " device in this version of qemu")

    # Determine syntax of drive hotplug
    # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6
    # drive_add == qemu-kvm-0.13 onwards
    drive_cmd_type = is_supported_command("drive_add",
                                          "__com.redhat_drive_add")
    if not drive_cmd_type:
        raise error.TestError("Could find a suitable method for hotplugging"
                              " drive in this version of qemu")

    local_functions = locals()

    pci_num_range = int(params.get("pci_num"))
    queues = int(params.get("queues", 1))
    rp_times = int(params.get("repeat_times"))
    img_list = params.get("images").split()
    context_msg = "Running sub test '%s' %s"
    for j in range(rp_times):
        # pci_info is a list of list.
        # each element 'i' has 4 members:
        # pci_info[i][0] == device drive id, only used for device_add
        # pci_info[i][1] == device id, only used for device_add
        # pci_info[i][2] == output of device add command
        # pci_info[i][3] == device module name.
        pci_info = []
        for pci_num in xrange(pci_num_range):
            sub_type = params.get("sub_type_before_plug")
            if sub_type:
                error.context(context_msg % (sub_type, "before hotplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)

            error.context("Start hot-adding pci device, repeat %d" % j,
                          logging.info)
            add_device(pci_num, queues)

            sub_type = params.get("sub_type_after_plug")
            if sub_type:
                error.context(context_msg % (sub_type, "after hotplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)
        for pci_num in xrange(pci_num_range):
            sub_type = params.get("sub_type_before_unplug")
            if sub_type:
                error.context(context_msg % (sub_type, "before hotunplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)

            error.context("start hot-deleting pci device, repeat %d" % j,
                          logging.info)
            pci_del(-(pci_num + 1))

            sub_type = params.get("sub_type_after_unplug")
            if sub_type:
                error.context(context_msg % (sub_type, "after hotunplug"),
                              logging.info)
                utils_test.run_virt_sub_test(test, params, env, sub_type)

    if params.get("reboot_vm", "no") == "yes":
        vm.reboot()
Beispiel #40
0
def run(test, params, env):
    """
    Boot guest with different cpu flags and check if guest works correctly.

    :param test: kvm test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    utils_misc.Flag.aliases = utils_misc.kvm_map_flags_aliases
    qemu_binary = utils_misc.get_qemu_binary(params)

    cpuflags_src = os.path.join(data_dir.get_deps_dir("cpu_flags"), "src")
    cpuflags_def = os.path.join(data_dir.get_deps_dir("cpu_flags"),
                                "cpu_map.xml")
    smp = int(params.get("smp", 1))

    all_host_supported_flags = params.get("all_host_supported_flags", "no")

    mig_timeout = float(params.get("mig_timeout", "3600"))
    mig_protocol = params.get("migration_protocol", "tcp")
    mig_speed = params.get("mig_speed", "1G")

    cpu_model_black_list = params.get("cpu_model_blacklist", "").split(" ")

    multi_host_migration = params.get("multi_host_migration", "no")

    class HgFlags(object):

        def __init__(self, cpu_model, extra_flags=set([])):
            virtual_flags = set(map(utils_misc.Flag,
                                    params.get("guest_spec_flags", "").split()))
            self.hw_flags = set(map(utils_misc.Flag,
                                    params.get("host_spec_flags", "").split()))
            self.qemu_support_flags = get_all_qemu_flags()
            self.host_support_flags = set(map(utils_misc.Flag,
                                              utils_misc.get_cpu_flags()))
            self.quest_cpu_model_flags = (get_guest_host_cpuflags(cpu_model) -
                                          virtual_flags)

            self.supported_flags = (self.qemu_support_flags &
                                    self.host_support_flags)
            self.cpumodel_unsupport_flags = (self.supported_flags -
                                             self.quest_cpu_model_flags)

            self.host_unsupported_flags = (self.quest_cpu_model_flags -
                                           self.host_support_flags)

            self.all_possible_guest_flags = (self.quest_cpu_model_flags -
                                             self.host_unsupported_flags)
            self.all_possible_guest_flags |= self.cpumodel_unsupport_flags

            self.guest_flags = (self.quest_cpu_model_flags -
                                self.host_unsupported_flags)
            self.guest_flags |= extra_flags

            self.host_all_unsupported_flags = set([])
            self.host_all_unsupported_flags |= self.qemu_support_flags
            self.host_all_unsupported_flags -= (self.host_support_flags |
                                                virtual_flags)

    def start_guest_with_cpuflags(cpuflags, smp=None, migration=False,
                                  wait=True):
        """
        Try to boot guest with special cpu flags and try login in to them.
        """
        params_b = params.copy()
        params_b["cpu_model"] = cpuflags
        if smp is not None:
            params_b["smp"] = smp

        vm_name = "vm1-cpuflags"
        vm = qemu_vm.VM(vm_name, params_b, test.bindir, env['address_cache'])
        env.register_vm(vm_name, vm)
        if (migration is True):
            vm.create(migration_mode=mig_protocol)
        else:
            vm.create()

        session = None
        try:
            vm.verify_alive()

            if wait:
                session = vm.wait_for_login()
        except qemu_vm.ImageUnbootableError:
            vm.destroy(gracefully=False)
            raise

        return (vm, session)

    def get_guest_system_cpuflags(vm_session):
        """
        Get guest system cpuflags.

        :param vm_session: session to checked vm.
        :return: [corespond flags]
        """
        flags_re = re.compile(r'^flags\s*:(.*)$', re.MULTILINE)
        out = vm_session.cmd_output("cat /proc/cpuinfo")

        flags = flags_re.search(out).groups()[0].split()
        return set(map(utils_misc.Flag, flags))

    def get_guest_host_cpuflags_legacy(cpumodel):
        """
        Get cpu flags correspond with cpumodel parameters.

        :param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
        :return: [corespond flags]
        """
        cmd = qemu_binary + " -cpu ?dump"
        output = process.run(cmd).stdout
        re.escape(cpumodel)
        pattern = (r".+%s.*\n.*\n +feature_edx .+ \((.*)\)\n +feature_"
                   r"ecx .+ \((.*)\)\n +extfeature_edx .+ \((.*)\)\n +"
                   r"extfeature_ecx .+ \((.*)\)\n" % (cpumodel))
        flags = []
        model = re.search(pattern, output)
        if model is None:
            test.fail("Cannot find %s cpu model." % (cpumodel))
        for flag_group in model.groups():
            flags += flag_group.split()
        return set(map(utils_misc.Flag, flags))

    class ParseCpuFlags(object):

        def __init__(self, encoding=None):
            self.cpus = {}
            self.parser = expat.ParserCreate(encoding)
            self.parser.StartElementHandler = self.start_element
            self.parser.EndElementHandler = self.end_element
            self.last_arch = None
            self.last_model = None
            self.sub_model = False
            self.all_flags = []

        def start_element(self, name, attrs):
            if name == "cpus":
                self.cpus = {}
            elif name == "arch":
                self.last_arch = self.cpus[attrs['name']] = {}
            elif name == "model":
                if self.last_model is None:
                    self.last_model = self.last_arch[attrs['name']] = []
                else:
                    self.last_model += self.last_arch[attrs['name']]
                    self.sub_model = True
            elif name == "feature":
                if self.last_model is not None:
                    self.last_model.append(attrs['name'])
                else:
                    self.all_flags.append(attrs['name'])

        def end_element(self, name):
            if name == "arch":
                self.last_arch = None
            elif name == "model":
                if self.sub_model is False:
                    self.last_model = None
                else:
                    self.sub_model = False

        def parse_file(self, file_path):
            self.parser.ParseFile(open(file_path, 'r'))
            return self.cpus

    def get_guest_host_cpuflags_1350(cpumodel):
        """
        Get cpu flags correspond with cpumodel parameters.

        :param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
        :return: [corespond flags]
        """
        p = ParseCpuFlags()
        cpus = p.parse_file(cpuflags_def)
        flags = []
        for arch in cpus.values():
            if cpumodel in arch.keys():
                flags = arch[cpumodel]
        return set(map(utils_misc.Flag, flags))

    get_guest_host_cpuflags_BAD = get_guest_host_cpuflags_1350

    def get_all_qemu_flags_legacy():
        cmd = qemu_binary + " -cpu ?cpuid"
        output = process.run(cmd).stdout

        flags_re = re.compile(r".*\n.*f_edx:(.*)\n.*f_ecx:(.*)\n"
                              ".*extf_edx:(.*)\n.*extf_ecx:(.*)")
        m = flags_re.search(output)
        flags = []
        for a in m.groups():
            flags += a.split()

        return set(map(utils_misc.Flag, flags))

    def get_all_qemu_flags_1350():
        cmd = qemu_binary + " -cpu ?"
        output = process.run(cmd).stdout

        flags_re = re.compile(r".*Recognized CPUID flags:\n(.*)", re.DOTALL)
        m = flags_re.search(output)
        flags = []
        for a in m.groups():
            flags += a.split()

        return set(map(utils_misc.Flag, flags))

    def get_all_qemu_flags_BAD():
        """
        Get cpu flags correspond with cpumodel parameters.

        :param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
        :return: [corespond flags]
        """
        p = ParseCpuFlags()
        p.parse_file(cpuflags_def)
        return set(map(utils_misc.Flag, p.all_flags))

    def get_cpu_models_legacy():
        """
        Get all cpu models from qemu.

        :return: cpu models.
        """
        cmd = qemu_binary + " -cpu ?"
        output = process.run(cmd).stdout

        cpu_re = re.compile(r"\w+\s+\[?(\w+)\]?")
        return cpu_re.findall(output)

    def get_cpu_models_1350():
        """
        Get all cpu models from qemu.

        :return: cpu models.
        """
        cmd = qemu_binary + " -cpu ?"
        output = process.run(cmd).stdout

        cpu_re = re.compile(r"x86\s+\[?(\w+)\]?")
        return cpu_re.findall(output)

    get_cpu_models_BAD = get_cpu_models_1350

    def get_qemu_cpu_cmd_version():
        cmd = qemu_binary + " -cpu ?cpuid"
        try:
            process.run(cmd).stdout
            return "legacy"
        except:
            cmd = qemu_binary + " -cpu ?"
            output = process.run(cmd).stdout
            if "CPUID" in output:
                return "1350"
            else:
                return "BAD"

    qcver = get_qemu_cpu_cmd_version()

    get_guest_host_cpuflags = locals()["get_guest_host_cpuflags_%s" % qcver]
    get_all_qemu_flags = locals()["get_all_qemu_flags_%s" % qcver]
    get_cpu_models = locals()["get_cpu_models_%s" % qcver]

    def get_flags_full_name(cpu_flag):
        """
        Get all name of Flag.

        :param cpu_flag: Flag
        :return: all name of Flag.
        """
        cpu_flag = utils_misc.Flag(cpu_flag)
        for f in get_all_qemu_flags():
            if f == cpu_flag:
                return utils_misc.Flag(f)
        return []

    def parse_qemu_cpucommand(cpumodel):
        """
        Parse qemu cpu params.

        :param cpumodel: Cpu model command.
        :return: All flags which guest must have.
        """
        flags = cpumodel.split(",")
        cpumodel = flags[0]

        qemu_model_flag = get_guest_host_cpuflags(cpumodel)
        host_support_flag = set(map(utils_misc.Flag,
                                    utils_misc.get_cpu_flags()))
        real_flags = qemu_model_flag & host_support_flag

        for f in flags[1:]:
            if f[0].startswith("+"):
                real_flags |= set([get_flags_full_name(f[1:])])
            if f[0].startswith("-"):
                real_flags -= set([get_flags_full_name(f[1:])])

        return real_flags

    def check_cpuflags(cpumodel, vm_session):
        """
        Check if vm flags are same like flags select by cpumodel.

        :param cpumodel: params for -cpu param in qemu-kvm
        :param vm_session: session to vm to check flags.

        :return: ([excess], [missing]) flags
        """
        gf = get_guest_system_cpuflags(vm_session)
        rf = parse_qemu_cpucommand(cpumodel)

        logging.debug("Guest flags: %s", gf)
        logging.debug("Host flags: %s", rf)
        logging.debug("Flags on guest not defined by host: %s", (gf - rf))
        return rf - gf

    def get_cpu_models_supported_by_host():
        """
        Get all cpumodels which set of flags is subset of hosts flags.

        :return: [cpumodels]
        """
        cpumodels = []
        for cpumodel in get_cpu_models():
            flags = HgFlags(cpumodel)
            if flags.host_unsupported_flags == set([]):
                cpumodels.append(cpumodel)
        return cpumodels

    def disable_cpu(vm_session, cpu, disable=True):
        """
        Disable cpu in guest system.

        :param cpu: CPU id to disable.
        :param disable: if True disable cpu else enable cpu.
        """
        system_cpu_dir = "/sys/devices/system/cpu/"
        cpu_online = system_cpu_dir + "cpu%d/online" % (cpu)
        cpu_state = vm_session.cmd_output("cat %s" % cpu_online).strip()
        if disable and cpu_state == "1":
            vm_session.cmd("echo 0 > %s" % cpu_online)
            logging.debug("Guest cpu %d is disabled.", cpu)
        elif cpu_state == "0":
            vm_session.cmd("echo 1 > %s" % cpu_online)
            logging.debug("Guest cpu %d is enabled.", cpu)

    def check_online_cpus(vm_session, smp, disabled_cpu):
        """
        Disable cpu in guest system.

        :param smp: Count of cpu core in system.
        :param disable_cpu: List of disabled cpu.

        :return: List of CPUs that are still enabled after disable procedure.
        """
        online = [0]
        for cpu in range(1, smp):
            system_cpu_dir = "/sys/devices/system/cpu/"
            cpu_online = system_cpu_dir + "cpu%d/online" % (cpu)
            cpu_state = vm_session.cmd_output("cat %s" % cpu_online).strip()
            if cpu_state == "1":
                online.append(cpu)
        cpu_proc = vm_session.cmd_output("cat /proc/cpuinfo")
        cpu_state_proc = map(lambda x: int(x),
                             re.findall(r"processor\s+:\s*(\d+)\n", cpu_proc))
        if set(online) != set(cpu_state_proc):
            test.error("Some cpus are disabled but %s are still "
                       "visible like online in /proc/cpuinfo." %
                       (set(cpu_state_proc) - set(online)))

        return set(online) - set(disabled_cpu)

    def install_cpuflags_test_on_vm(vm, dst_dir):
        """
        Install stress to vm.

        :param vm: virtual machine.
        :param dst_dir: Installation path.
        """
        session = vm.wait_for_login()
        vm.copy_files_to(cpuflags_src, dst_dir)
        session.cmd("sync")
        session.cmd("cd %s; make EXTRA_FLAGS='';" %
                    os.path.join(dst_dir, "src"))
        session.cmd("sync")
        session.close()

    def check_cpuflags_work(vm, path, flags):
        """
        Check which flags work.

        :param vm: Virtual machine.
        :param path: Path of cpuflags_test
        :param flags: Flags to test.
        :return: Tuple (Working, not working, not tested) flags.
        """
        pass_Flags = []
        not_tested = []
        not_working = []
        session = vm.wait_for_login()
        for f in flags:
            try:
                for tc in utils_misc.kvm_map_flags_to_test[f]:
                    session.cmd("%s/cpuflags-test --%s" %
                                (os.path.join(path, "src"), tc))
                pass_Flags.append(f)
            except aexpect.ShellCmdError:
                not_working.append(f)
            except KeyError:
                not_tested.append(f)
        return (set(map(utils_misc.Flag, pass_Flags)),
                set(map(utils_misc.Flag, not_working)),
                set(map(utils_misc.Flag, not_tested)))

    def run_stress(vm, timeout, guest_flags):
        """
        Run stress on vm for timeout time.
        """
        ret = False
        install_path = "/tmp"
        install_cpuflags_test_on_vm(vm, install_path)
        flags = check_cpuflags_work(vm, install_path, guest_flags)
        dd_session = vm.wait_for_login()
        stress_session = vm.wait_for_login()
        dd_session.sendline("dd if=/dev/[svh]da of=/tmp/stressblock"
                            " bs=10MB count=100 &")
        try:
            stress_session.cmd("%s/cpuflags-test --stress %s%s" %
                               (os.path.join(install_path, "src"), smp,
                                utils_misc.kvm_flags_to_stresstests(flags[0])),
                               timeout=timeout)
        except aexpect.ShellTimeoutError:
            ret = True
        stress_session.close()
        dd_session.close()
        return ret

    def separe_cpu_model(cpu_model):
        try:
            (cpu_model, _) = cpu_model.split(":")
        except ValueError:
            cpu_model = cpu_model
        return cpu_model

    def parse_cpu_model():
        """
        Parse cpu_models from config file.

        :return: [(cpumodel, extra_flags)]
        """
        cpu_model = params.get("cpu_model", "")
        logging.debug("CPU model found: %s", str(cpu_model))

        try:
            (cpu_model, extra_flags) = cpu_model.split(":")
            extra_flags = set(map(utils_misc.Flag, extra_flags.split(",")))
        except ValueError:
            cpu_model = cpu_model
            extra_flags = set([])
        return (cpu_model, extra_flags)

    class MiniSubtest(object):

        def __new__(cls, *args, **kargs):
            self = super(MiniSubtest, cls).__new__(cls)
            ret = None
            if args is None:
                args = []
            try:
                ret = self.test(*args, **kargs)
            finally:
                if hasattr(self, "clean"):
                    self.clean()
            return ret

    def print_exception(called_object):
        exc_type, exc_value, exc_traceback = sys.exc_info()
        logging.error("In function (" + called_object.__name__ + "):")
        logging.error("Call from:\n" +
                      traceback.format_stack()[-2][:-1])
        logging.error("Exception from:\n" +
                      "".join(traceback.format_exception(
                              exc_type, exc_value,
                              exc_traceback.tb_next)))

    class Test_temp(MiniSubtest):

        def clean(self):
            logging.info("cleanup")
            vm = getattr(self, "vm", None)
            if vm:
                vm.destroy(gracefully=False)
            clone = getattr(self, "clone", None)
            if clone:
                clone.destroy(gracefully=False)

    # 1) <qemu-kvm-cmd> -cpu ?model
    class test_qemu_cpu_model(MiniSubtest):

        def test(self):
            if qcver == "legacy":
                cpu_models = params.get("cpu_models", "core2duo").split()
                cmd = qemu_binary + " -cpu ?model"
                result = process.run(cmd)
                missing = []
                cpu_models = map(separe_cpu_model, cpu_models)
                for cpu_model in cpu_models:
                    if cpu_model not in result.stdout:
                        missing.append(cpu_model)
                if missing:
                    test.fail("CPU models %s are not in output "
                              "'%s' of command \n%s" %
                              (missing, cmd, result.stdout))
            else:
                test.cancel("New qemu does not support -cpu "
                            "?model. (%s)" % qcver)

    # 2) <qemu-kvm-cmd> -cpu ?dump
    class test_qemu_dump(MiniSubtest):

        def test(self):
            if qcver == "legacy":
                cpu_models = params.get("cpu_models", "core2duo").split()
                cmd = qemu_binary + " -cpu ?dump"
                result = process.run(cmd)
                cpu_models = map(separe_cpu_model, cpu_models)
                missing = []
                for cpu_model in cpu_models:
                    if cpu_model not in result.stdout:
                        missing.append(cpu_model)
                if missing:
                    test.fail("CPU models %s are not in output "
                              "'%s' of command \n%s" %
                              (missing, cmd, result.stdout))
            else:
                test.cancel("New qemu does not support -cpu "
                            "?dump. (%s)" % qcver)

    # 3) <qemu-kvm-cmd> -cpu ?cpuid
    class test_qemu_cpuid(MiniSubtest):

        def test(self):
            if qcver == "legacy":
                cmd = qemu_binary + " -cpu ?cpuid"
                result = process.run(cmd)
                if result.stdout is "":
                    test.fail("There aren't any cpu Flag in output"
                              " '%s' of command \n%s" % (cmd, result.stdout))
            else:
                test.cancel("New qemu does not support -cpu "
                            "?cpuid. (%s)" % qcver)

    # 1) boot with cpu_model
    class test_boot_cpu_model(Test_temp):

        def test(self):
            cpu_model, _ = parse_cpu_model()
            logging.debug("Run tests with cpu model %s", cpu_model)
            flags = HgFlags(cpu_model)
            (self.vm, session) = start_guest_with_cpuflags(cpu_model)
            not_enable_flags = (check_cpuflags(cpu_model, session) -
                                flags.hw_flags)
            if not_enable_flags != set([]):
                test.fail("Flags defined on host but not found "
                          "on guest: %s" % (not_enable_flags))

    # 2) success boot with supported flags
    class test_boot_cpu_model_and_additional_flags(Test_temp):

        def test(self):
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            cpuf_model = cpu_model

            if all_host_supported_flags == "yes":
                for fadd in flags.cpumodel_unsupport_flags:
                    cpuf_model += ",+" + str(fadd)
            else:
                for fadd in extra_flags:
                    cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            if all_host_supported_flags == "yes":
                guest_flags = flags.all_possible_guest_flags
            else:
                guest_flags = flags.guest_flags

            (self.vm, session) = start_guest_with_cpuflags(cpuf_model)

            not_enable_flags = (check_cpuflags(cpuf_model, session) -
                                flags.hw_flags)
            if not_enable_flags != set([]):
                logging.info("Model unsupported flags: %s",
                             str(flags.cpumodel_unsupport_flags))
                logging.error("Flags defined on host but not on found "
                              "on guest: %s", str(not_enable_flags))
            logging.info("Check main instruction sets.")

            install_path = "/tmp"
            install_cpuflags_test_on_vm(self.vm, install_path)

            Flags = check_cpuflags_work(self.vm, install_path,
                                        flags.all_possible_guest_flags)
            logging.info("Woking CPU flags: %s", str(Flags[0]))
            logging.info("Not working CPU flags: %s", str(Flags[1]))
            logging.warning("Flags works even if not defined on guest cpu "
                            "flags: %s", str(Flags[0] - guest_flags))
            logging.warning("Not tested CPU flags: %s", str(Flags[2]))

            if Flags[1] & guest_flags:
                test.fail("Some flags do not work: %s" % (str(Flags[1])))

    # 3) fail boot unsupported flags
    class test_boot_warn_with_host_unsupported_flags(MiniSubtest):

        def test(self):
            # This is virtual cpu flags which are supported by
            # qemu but no with host cpu.
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Unsupported flags %s.",
                          str(flags.host_all_unsupported_flags))
            cpuf_model = cpu_model + ",check"

            # Add unsupported flags.
            for fadd in flags.host_all_unsupported_flags:
                cpuf_model += ",+" + str(fadd)

            vnc_port = utils_misc.find_free_port(5900, 6100) - 5900
            cmd = "%s -cpu %s -vnc :%d -enable-kvm" % (qemu_binary,
                                                       cpuf_model,
                                                       vnc_port)
            out = None

            try:
                try:
                    out = process.run(cmd, timeout=5, ignore_status=True).stderr
                    test.fail("Guest not boot with unsupported flags.")
                except process.CmdError as e:
                    out = e.result.stderr
            finally:
                uns_re = re.compile(r"^warning:.*flag '(.+)'", re.MULTILINE)
                nf_re = re.compile(
                    r"^CPU feature (.+) not found", re.MULTILINE)
                warn_flags = set([utils_misc.Flag(x)
                                  for x in uns_re.findall(out)])
                not_found = set([utils_misc.Flag(x)
                                 for x in nf_re.findall(out)])
                fwarn_flags = flags.host_all_unsupported_flags - warn_flags
                fwarn_flags -= not_found
                if fwarn_flags:
                    test.fail("Qemu did not warn the use of "
                              "flags %s" % str(fwarn_flags))

    # 3) fail boot unsupported flags
    class test_fail_boot_with_host_unsupported_flags(MiniSubtest):

        def test(self):
            # This is virtual cpu flags which are supported by
            # qemu but no with host cpu.
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)
            cpuf_model = cpu_model + ",enforce"

            logging.debug("Unsupported flags %s.",
                          str(flags.host_all_unsupported_flags))

            # Add unsupported flags.
            for fadd in flags.host_all_unsupported_flags:
                cpuf_model += ",+" + str(fadd)

            vnc_port = utils_misc.find_free_port(5900, 6100) - 5900
            cmd = "%s -cpu %s -vnc :%d -enable-kvm" % (qemu_binary,
                                                       cpuf_model,
                                                       vnc_port)
            out = None
            try:
                try:
                    out = process.run(cmd, timeout=5, ignore_status=True).stderr
                except process.CmdError:
                    logging.error("Host boot with unsupported flag")
            finally:
                uns_re = re.compile(r"^warning:.*flag '(.+)'", re.MULTILINE)
                nf_re = re.compile(
                    r"^CPU feature (.+) not found", re.MULTILINE)
                warn_flags = set([utils_misc.Flag(x)
                                  for x in uns_re.findall(out)])
                not_found = set([utils_misc.Flag(x)
                                 for x in nf_re.findall(out)])
                fwarn_flags = flags.host_all_unsupported_flags - warn_flags
                fwarn_flags -= not_found
                if fwarn_flags:
                    test.fail("Qemu did not warn the use of "
                              "flags %s" % str(fwarn_flags))

    # 4) check guest flags under load cpu, stress and system (dd)
    class test_boot_guest_and_try_flags_under_load(Test_temp):

        def test(self):
            logging.info("Check guest working cpuflags under load "
                         "cpu and stress and system (dd)")
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            cpuf_model = cpu_model

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))

            if all_host_supported_flags == "yes":
                logging.debug("Added flags %s.",
                              str(flags.cpumodel_unsupport_flags))

                # Add unsupported flags.
                for fadd in flags.cpumodel_unsupport_flags:
                    cpuf_model += ",+" + str(fadd)

                for fdel in flags.host_unsupported_flags:
                    cpuf_model += ",-" + str(fdel)

            (self.vm, _) = start_guest_with_cpuflags(cpuf_model, smp)

            if (not run_stress(self.vm, 60, flags.guest_flags)):
                test.fail("Stress test ended before end of test.")

    # 5) Online/offline CPU
    class test_online_offline_guest_CPUs(Test_temp):

        def test(self):
            cpu_model, extra_flags = parse_cpu_model()

            logging.debug("Run tests with cpu model %s.", (cpu_model))
            flags = HgFlags(cpu_model, extra_flags)

            (self.vm, session) = start_guest_with_cpuflags(cpu_model, smp)

            def encap(timeout):
                random.seed()
                begin = time.time()
                end = begin
                if smp > 1:
                    while end - begin < 60:
                        cpu = random.randint(1, smp - 1)
                        if random.randint(0, 1):
                            disable_cpu(session, cpu, True)
                        else:
                            disable_cpu(session, cpu, False)
                        end = time.time()
                    return True
                else:
                    logging.warning("For this test is necessary smp > 1.")
                    return False
            timeout = 60

            test_flags = flags.guest_flags
            if all_host_supported_flags == "yes":
                test_flags = flags.all_possible_guest_flags

            result = utils_misc.parallel([(encap, [timeout]),
                                          (run_stress, [self.vm, timeout,
                                                        test_flags])])
            if not (result[0] and result[1]):
                test.fail("Stress tests failed before end of testing.")

    # 6) migration test
    class test_migration_with_additional_flags(Test_temp):

        def test(self):
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            logging.debug("Added flags %s.",
                          str(flags.cpumodel_unsupport_flags))
            cpuf_model = cpu_model

            # Add unsupported flags.
            for fadd in flags.cpumodel_unsupport_flags:
                cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            (self.vm, _) = start_guest_with_cpuflags(cpuf_model, smp)

            install_path = "/tmp"
            install_cpuflags_test_on_vm(self.vm, install_path)
            flags = check_cpuflags_work(self.vm, install_path,
                                        flags.guest_flags)
            test.assertTrue(flags[0], "No cpuflags passed the check: %s"
                            % str(flags))
            test.assertFalse(flags[1], "Some cpuflags failed the check: %s"
                             % str(flags))
            dd_session = self.vm.wait_for_login()
            stress_session = self.vm.wait_for_login()

            dd_session.sendline("nohup dd if=$(echo /dev/[svh]da) of=/tmp/"
                                "stressblock bs=10MB count=100 &")
            cmd = ("nohup %s/cpuflags-test --stress  %s%s &" %
                   (os.path.join(install_path, "src"), smp,
                    utils_misc.kvm_flags_to_stresstests(flags[0])))
            stress_session.sendline(cmd)

            time.sleep(5)

            self.vm.monitor.migrate_set_speed(mig_speed)
            self.clone = self.vm.migrate(
                mig_timeout, mig_protocol, offline=False,
                not_wait_for_migration=True)

            time.sleep(5)

            try:
                self.vm.wait_for_migration(10)
            except virt_vm.VMMigrateTimeoutError:
                self.vm.monitor.migrate_set_downtime(1)
                self.vm.wait_for_migration(mig_timeout)

            self.clone.resume()
            self.vm.destroy(gracefully=False)

            stress_session = self.clone.wait_for_login()

            # If cpuflags-test hang up during migration test raise exception
            try:
                stress_session.cmd('killall cpuflags-test')
            except aexpect.ShellCmdError:
                test.fail("Stress cpuflags-test should be still "
                          "running after migration.")
            try:
                stress_session.cmd("ls /tmp/stressblock && "
                                   "rm -f /tmp/stressblock")
            except aexpect.ShellCmdError:
                test.fail("Background 'dd' command failed to "
                          "produce output file.")

    def net_send_object(socket, obj):
        """
        Send python object over network.

        :param ip_addr: ipaddres of waiter for data.
        :param obj: object to send
        """
        data = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
        socket.sendall("%6d" % len(data))
        socket.sendall(data)

    def net_recv_object(socket, timeout=60):
        """
        Receive python object over network.

        :param ip_addr: ipaddres of waiter for data.
        :param obj: object to send
        :return: object from network
        """
        try:
            time_start = time.time()
            data = ""
            d_len = int(socket.recv(6))

            while (len(data) < d_len and (time.time() - time_start) < timeout):
                data += socket.recv(d_len - len(data))

            data = pickle.loads(data)
            return data
        except:
            test.fail("Failed to receive python object over the network")

    class test_multi_host_migration(Test_temp):

        def test(self):
            """
            Test migration between multiple hosts.
            """
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            logging.debug("Added flags %s.",
                          str(flags.cpumodel_unsupport_flags))
            cpuf_model = cpu_model

            for fadd in extra_flags:
                cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            install_path = "/tmp"

            class testMultihostMigration(migration.MultihostMigration):

                def __init__(self, test, params, env):
                    migration.MultihostMigration.__init__(self, test, params,
                                                          env)

                def migration_scenario(self):
                    srchost = self.params.get("hosts")[0]
                    dsthost = self.params.get("hosts")[1]

                    def worker(mig_data):
                        vm = env.get_vm("vm1")
                        session = vm.wait_for_login(timeout=self.login_timeout)

                        install_cpuflags_test_on_vm(vm, install_path)

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s", str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))
                        session.sendline("nohup dd if=/dev/[svh]da of=/tmp/"
                                         "stressblock bs=10MB count=100 &")

                        cmd = ("nohup %s/cpuflags-test --stress  %s%s &" %
                               (os.path.join(install_path, "src"),
                                smp,
                                utils_misc.kvm_flags_to_stresstests(Flags[0] &
                                                                    flags.guest_flags)))
                        logging.debug("Guest_flags: %s",
                                      str(flags.guest_flags))
                        logging.debug("Working_flags: %s", str(Flags[0]))
                        logging.debug("Start stress on guest: %s", cmd)
                        session.sendline(cmd)

                    def check_worker(mig_data):
                        vm = env.get_vm("vm1")

                        vm.verify_illegal_instruction()

                        session = vm.wait_for_login(timeout=self.login_timeout)

                        try:
                            session.cmd('killall cpuflags-test')
                        except aexpect.ShellCmdError:
                            test.fail("The cpuflags-test program"
                                      " should be active after"
                                      " migration and it's not.")

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s",
                                     str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))

                    self.migrate_wait(["vm1"], srchost, dsthost,
                                      worker, check_worker)

            params_b = params.copy()
            params_b["cpu_model"] = cpu_model
            mig = testMultihostMigration(test, params_b, env)
            mig.run()

    class test_multi_host_migration_onoff_cpu(Test_temp):

        def test(self):
            """
            Test migration between multiple hosts.
            """
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            logging.debug("Added flags %s.",
                          str(flags.cpumodel_unsupport_flags))
            cpuf_model = cpu_model

            for fadd in extra_flags:
                cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            smp = int(params["smp"])
            disable_cpus = list(map(lambda cpu: int(cpu),
                                    params.get("disable_cpus", "").split()))

            install_path = "/tmp"

            class testMultihostMigration(migration.MultihostMigration):

                def __init__(self, test, params, env):
                    migration.MultihostMigration.__init__(self, test, params,
                                                          env)
                    self.srchost = self.params.get("hosts")[0]
                    self.dsthost = self.params.get("hosts")[1]
                    self.id = {'src': self.srchost,
                               'dst': self.dsthost,
                               "type": "disable_cpu"}
                    self.migrate_count = int(self.params.get('migrate_count',
                                                             '2'))

                def ping_pong_migrate(self, sync, worker, check_worker):
                    for _ in range(self.migrate_count):
                        logging.info("File transfer not ended, starting"
                                     " a round of migration...")
                        sync.sync(True, timeout=mig_timeout)
                        if self.hostid == self.srchost:
                            self.migrate_wait(["vm1"],
                                              self.srchost,
                                              self.dsthost,
                                              start_work=worker)
                        elif self.hostid == self.dsthost:
                            self.migrate_wait(["vm1"],
                                              self.srchost,
                                              self.dsthost,
                                              check_work=check_worker)
                        tmp = self.dsthost
                        self.dsthost = self.srchost
                        self.srchost = tmp

                def migration_scenario(self):
                    from autotest.client.shared.syncdata import SyncData

                    sync = SyncData(self.master_id(), self.hostid, self.hosts,
                                    self.id, self.sync_server)

                    def worker(mig_data):
                        vm = env.get_vm("vm1")
                        session = vm.wait_for_login(timeout=self.login_timeout)

                        install_cpuflags_test_on_vm(vm, install_path)

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s", str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))
                        for cpu in disable_cpus:
                            if cpu < smp:
                                disable_cpu(session, cpu, True)
                            else:
                                logging.warning("There is no enouth cpu"
                                                " in Guest. It is trying to"
                                                "remove cpu:%s from guest with"
                                                " smp:%s." % (cpu, smp))
                        logging.debug("Guest_flags: %s",
                                      str(flags.guest_flags))
                        logging.debug("Working_flags: %s", str(Flags[0]))

                    def check_worker(mig_data):
                        vm = env.get_vm("vm1")

                        vm.verify_illegal_instruction()

                        session = vm.wait_for_login(timeout=self.login_timeout)

                        really_disabled = check_online_cpus(session, smp,
                                                            disable_cpus)

                        not_disabled = set(really_disabled) & set(disable_cpus)
                        if not_disabled:
                            test.fail("Some of disabled cpus are "
                                      "online. This shouldn't "
                                      "happen. Cpus disabled on "
                                      "srchost:%s, Cpus not "
                                      "disabled on dsthost:%s" %
                                      (disable_cpus, not_disabled))

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s",
                                     str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))

                    self.ping_pong_migrate(sync, worker, check_worker)

            params_b = params.copy()
            params_b["cpu_model"] = cpu_model
            mig = testMultihostMigration(test, params_b, env)
            mig.run()

    test_type = params.get("test_type")
    if (test_type in locals()):
        tests_group = locals()[test_type]
        if params.get("cpu_model"):
            tests_group()
        else:
            cpu_models = (set(get_cpu_models_supported_by_host()) -
                          set(cpu_model_black_list))
            if not cpu_models:
                test.cancel("No cpu_models detected, nothing to test.")
            logging.info("Start test with cpu models %s" % (str(cpu_models)))
            failed = []
            for cpumodel in cpu_models:
                params["cpu_model"] = cpumodel
                try:
                    tests_group()
                except:
                    print_exception(tests_group)
                    failed.append(cpumodel)
            if failed != []:
                test.fail("Test of cpu models %s failed." % (str(failed)))
    else:
        test.fail("Test group '%s' is not defined in"
                  " cpuflags test" % test_type)
Beispiel #41
0
def run(test, params, env):
    """
    change a removable media:
    1) Boot VM with QMP/human monitor enabled.
    2) Connect to QMP/human monitor server.
    3) Eject original cdrom.
    4) Eject original cdrom for second time.
    5) Insert new image to cdrom.
    6) Eject device after add new image by change command.
    7) Insert original cdrom to cdrom.
    8) Try to eject non-removable device w/o force option.

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

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        logging.warn("qemu does not support qmp. Human monitor will be used.")
    qmp_used = False
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))
    logging.info("Wait until device is ready")
    time.sleep(10)
    if vm.monitor.protocol == "qmp":
        qmp_used = True

    orig_img_name = params.get("cdrom_cd1")
    p_dict = {"file": orig_img_name}
    device_name = vm.get_block(p_dict)
    if device_name is None:
        msg = "Fail to get device using image %s" % orig_img_name
        raise error.TestFail(msg)
    error.context("Eject original device.")
    eject_cmd = "eject device=%s" % device_name
    vm.monitor.send_args_cmd(eject_cmd)
    logging.info("Wait until device is ejected")
    time.sleep(10)
    blocks_info = vm.monitor.info("block")
    if orig_img_name in str(blocks_info):
        raise error.TestFail("Fail to eject cdrom %s. " % orig_img_name)

    error.context("Eject original device for second time")
    vm.monitor.send_args_cmd(eject_cmd)

    new_img_name = params.get("new_img_name")
    error.context("Insert new image to device.")
    change_cmd = "change device=%s,target=%s" % (device_name, new_img_name)
    vm.monitor.send_args_cmd(change_cmd)
    logging.info("Wait until device changed")
    time.sleep(10)
    blocks_info = vm.monitor.info("block")
    if new_img_name not in str(blocks_info):
        raise error.TestFail("Fail to chang cdrom to %s." % new_img_name)
    if qmp_used:
        eject_cmd = "eject device=%s, force=True" % device_name
    else:
        eject_cmd = "eject device=%s" % device_name
    error.context("Eject device after add new image by change command")
    vm.monitor.send_args_cmd(eject_cmd)
    logging.info("Wait until new image is ejected")
    time.sleep(10)

    blocks_info = vm.monitor.info("block")
    if new_img_name in str(blocks_info):
        raise error.TestFail("Fail to eject cdrom %s." % orig_img_name)

    error.context("Insert %s to device %s" % (orig_img_name, device_name))
    change_cmd = "change device=%s,target=%s" % (device_name, orig_img_name)
    vm.monitor.send_args_cmd(change_cmd)
    logging.info("Wait until device changed")
    time.sleep(10)
    blocks_info = vm.monitor.info("block")
    if orig_img_name not in str(blocks_info):
        raise error.TestFail("Fail to change cdrom to %s." % orig_img_name)

    error.context("Try to eject non-removable device")
    p_dict = {"removable": False}
    device_name = vm.get_block(p_dict)
    if device_name is None:
        raise error.TestFail("Could not find non-removable device")
    if params.get("force_eject", "no") == "yes":
        if not qmp_used:
            eject_cmd = "eject -f %s " % device_name
        else:
            eject_cmd = "eject device=%s, force=True" % device_name
    else:
        eject_cmd = "eject device=%s," % device_name
    try:
        vm.monitor.send_args_cmd(eject_cmd)
    except Exception, e:
        if "is not removable" not in str(e):
            raise error.TestFail(e)
        logging.debug("Catch exception message: %s" % e)
Beispiel #42
0
def run(test, params, env):
    """
    Check smbios table :
    1) Get the smbios table from config file,if there is no config option in
       config file, the script will generate the config parameters automately.
    2) Boot a guest with smbios options and/or -M option
    3) Verify if bios options have been emulated correctly.

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    smbios_type = params.get("smbios_type")
    notset_output = params.get("notset_output")
    dmidecode_exp = params.get("dmidecode_exp")
    login_timeout = float(params.get("login_timeout", 360))

    smbios = ""
    if params.get("smbios_type_disable", "no") == "no":
        # Set the smbios parameter, if you have set it in the config file,
        # it'll be honored, else, one will be generated.
        for sm_type in smbios_type.split():
            if sm_type == "Bios":
                smbios_type_number = 0
            elif sm_type == "System":
                smbios_type_number = 1
            smbios += " -smbios type=%s" % smbios_type_number
            dmidecode_key = params.object_params(sm_type).get("dmikeyword")
            dmidecode_key = dmidecode_key.split()
            for key in dmidecode_key:
                cmd = (dmidecode_exp % (smbios_type_number, key))
                default_key_para = utils.system_output(cmd).strip()
                smbios_key_para_set = params.object_params(sm_type).get(key,
                                                                        default_key_para)
                smbios += ",%s='%s'" % (key.lower(), smbios_key_para_set)

        if params.get("extra_params"):
            params["extra_params"] += smbios
        else:
            params["extra_params"] = smbios

    support_machine_types = []
    if params.get("traversal_machine_emulated", "no") == "no":
        support_machine_types.append(params.get("machine_type"))
    else:
        qemu_binary = utils_misc.get_qemu_binary(params)
        tmp = utils_misc.get_support_machine_type(qemu_binary, remove_alias=True)[:2]
        (support_machine_types, expect_system_versions) = tmp
        machine_type = params.get("machine_type", "")
        if ':' in machine_type:
            prefix = machine_type.split(':', 1)[0]
            support_machine_types = ["%s:%s" % (prefix, m_type)
                                     for m_type in support_machine_types]

    failures = []
    for m_type in support_machine_types:
        params["machine_type"] = m_type
        params["start_vm"] = "yes"

        error.context("Boot the vm using -M option:'-M %s',smbios para:'%s' "
                      % (m_type, smbios), logging.info)
        env_process.preprocess_vm(test, params, env, params.get("main_vm"))
        vm1 = env.get_vm(params["main_vm"])
        session = vm1.wait_for_login(timeout=login_timeout)

        error.context("Check smbios info on guest is setted as expected")

        for sm_type in smbios_type.split():
            if sm_type == "Bios":
                smbios_type_number = 0
            elif sm_type == "System":
                smbios_type_number = 1
            dmidecode_key = params.object_params(sm_type).get("dmikeyword")
            dmidecode_key = dmidecode_key.split()
            for key in dmidecode_key:
                cmd = (dmidecode_exp % (smbios_type_number, key))
                smbios_get_para = session.cmd(cmd).strip()
                default_key_para = utils.system_output(cmd).strip()
                if params.get("smbios_type_disable", "no") == "no":
                    smbios_set_para = params.object_params(sm_type).get(key,
                                                                        default_key_para)
                else:
                    key_index = support_machine_types.index(m_type)
                    smbios_set_para = expect_system_versions[key_index]

                if smbios_get_para == notset_output:
                    smbios_get_para = default_key_para

                if (smbios_set_para not in smbios_get_para):
                    e_msg = ("%s.%s mismatch, Set '%s' but guest is : '%s'"
                             % (sm_type, key, smbios_set_para,
                                smbios_get_para))
                    failures.append(e_msg)

        session.close()
        if params.get("traversal_machine_emulated", "no") == "yes":
            vm1.destroy(gracefully=False)

    error.context("")
    if failures:
        raise error.TestFail("smbios table test reported %s failures:\n%s" %
                             (len(failures), "\n".join(failures)))
Beispiel #43
0
def run(test, params, env):
    """
    Get qemu src code from src rpm and run qemu-iotests using the
    qemu binaries.

    1) Download src rpm from brew
    2) Unpack src code and apply patches
    3) Run test for the file format detected
    4) Check result

    :param test:   QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def retry_command(cmd):
        """
        Retry the command when it fails, and raise the error once
        retry has exceeded the maximum number

        :param cmd: command expect to be executed
        :return: output of the command
        """
        max_retry = int(params.get("max_retry", 3))
        retry = max_retry
        while retry:
            retry -= 1
            try:
                return process.system(cmd, shell=True)
            except process.CmdError as detail:
                msg = "Fail to execute command"
                logging.error("%s: %s." % (msg, detail))
        raise exceptions.TestError("%s after %s times retry: %s" %
                                   (msg, max_retry, detail))

    def install_test(build_root):
        """
        Download src rpm, unpack src code and applying patches

        :param build_root: build path of rpmbuild
        :return: A tuple containing directory of qemu source code
                 and qemu-kvm spec
        """
        error_context.context("Get qemu source code", logging.info)
        os.chdir(test.tmpdir)
        query_format = params["query_format"]
        download_rpm_cmd = params["download_rpm_cmd"]
        get_src_cmd = params["get_src_cmd"]
        qemu_spec = params.get("qemu_spec", 'SPECS/qemu-kvm.spec')
        get_rpm_name_cmd = ("rpm -qf %s --queryformat=%s" %
                            (utils_misc.get_qemu_binary(params), query_format))
        src_rpm_name = process.system_output(get_rpm_name_cmd, shell=True)
        retry_command(download_rpm_cmd % src_rpm_name)
        spec = os.path.join(build_root, qemu_spec)
        build_dir = os.path.join(build_root, 'BUILD')
        cmd = get_src_cmd % (src_rpm_name, spec)
        process.system(cmd, shell=True)
        src_dir = os.listdir(build_dir)[0]
        return (os.path.join(build_dir, src_dir), spec)

    def config_test(qemu_src_dir):
        """
        Generate common.env for test

        :qemu_src_dir: path of qemu source code
        """
        need_run_configure = params.get("need_run_configure", "no")
        if need_run_configure == "yes":
            make_socket_scm_helper = params.get("make_socket_scm_helper", "")
            logging.info("Generate common.env")
            os.chdir(qemu_src_dir)
            cmd = "./configure"
            if make_socket_scm_helper:
                cmd += " %s" % make_socket_scm_helper
            process.system(cmd, shell=True)

    def run_test(qemu_src_dir):
        """
        run QEMU I/O test suite

        :qemu_src_dir: path of qemu source code
        """
        iotests_root = params.get("iotests_root", "tests/qemu-iotests")
        extra_options = params.get("qemu_io_extra_options", "")
        image_format = params.get("qemu_io_image_format")
        result_pattern = params.get("iotests_result_pattern")
        error_context.context("running qemu-iotests for image format %s"
                              % image_format, logging.info)
        os.environ["QEMU_PROG"] = utils_misc.get_qemu_binary(params)
        os.environ["QEMU_IMG_PROG"] = utils_misc.get_qemu_img_binary(params)
        os.environ["QEMU_IO_PROG"] = utils_misc.get_qemu_io_binary(params)
        os.environ["QEMU_NBD_PROG"] = utils_misc.get_binary('qemu-nbd', params)
        os.chdir(os.path.join(qemu_src_dir, iotests_root))
        cmd = './check'
        if extra_options:
            cmd += " %s" % extra_options
        cmd += " -%s" % image_format
        output = process.system_output(cmd, ignore_status=True, shell=True)
        match = re.search(result_pattern, output, re.I | re.M)
        if match:
            iotests_log_file = "qemu_iotests_%s.log" % image_format
            iotests_log_file = utils_misc.get_path(test.debugdir, iotests_log_file)
            with open(iotests_log_file, 'w+') as log:
                log.write(output)
                log.flush()
            msg = "Total test %s cases, %s failed"
            raise exceptions.TestFail(msg % (match.group(2), match.group(1)))

    build_root = params.get("build_root", "/root/rpmbuild")
    rpmbuild_clean_cmd = params["rpmbuild_clean_cmd"]
    cmd = "%s -version" % utils_misc.get_qemu_binary(params)
    output = process.system_output(cmd, shell=True)
    cwd = os.getcwd()
    (qemu_src_dir, spec) = install_test(build_root)
    try:
        if "qemu-kvm-rhev" in output:
            config_test(qemu_src_dir)
        run_test(qemu_src_dir)
    finally:
        try:
            os.chdir(cwd)
            process.system(rpmbuild_clean_cmd % spec, shell=True)
        except Exception:
            logging.warn("Fail to clean test environment")
Beispiel #44
0
def run(test, params, env):
    """
    Test qmp event notification, this case will:
    1) Start VM with qmp enable.
    2) Connect to qmp port then run qmp_capabilities command.
    3) Initiate the qmp command defined in config (qmp_cmd)
    4) Verify that qmp command works as designed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """
    def check_list(qmp_o, key, val=None, check_item_in_pair=True):
        """
        Check if the expect key, val are contained in QMP output qmp_o.

        :param qmp_o: output of QMP command
        :type qmp_o: list
        :param key: expect result
        :type key: str
        :param val: expect result
        :type val: str or None(if check_item_in_pair=False)
        :param check_item_in_pair: If expect result is dict (True) or str (False)
        :type check_item_in_pair: bool.

        :return check result
        :rtype: bool
        """
        for element in qmp_o:
            if isinstance(element, dict):
                if _check_dict(element, key, val, check_item_in_pair):
                    return True
            elif isinstance(element, list):
                if check_list(element, key, val, check_item_in_pair):
                    return True
            elif element != '' and not check_item_in_pair:
                if strict_match:
                    if operator.eq(key, element):
                        return True
                else:
                    if key in str(element):
                        return True
        return False

    def _check_dict(dic, key, val, check_item_in_pair=True):
        """
        Check if the expect key, val are contained in QMP output dic.

        :param dic: content of QMP command return value
        :type dic: dict
        :param key: expect result
        :type key: str
        :param val: expect result
        :type val: str or None(if check_item_in_pair=False)
        :param check_item_in_pair: If expect result is dict or str
        :type check_item_in_pair: bool. Means expect result is dict or str.

        :return check result
        :rtype: bool
        """
        if key in dic and not check_item_in_pair:
            return True
        elif key in dic and val == dic[key]:
            return True
        else:
            for value in dic.values():
                if isinstance(value, dict):
                    if _check_dict(value, key, val, check_item_in_pair):
                        return True
                elif isinstance(value, list):
                    if check_list(value, key, val, check_item_in_pair):
                        return True
                elif value != '' and not check_item_in_pair:
                    if strict_match:
                        if operator.eq(key, value):
                            return True
                    else:
                        if key in str(value):
                            return True
            return False

    def check_result(qmp_o, expect_o=None):
        """
        Check test result with difference way according to result_check.
        result_check = equal, expect_o should equal to qmp_o.
        result_check = contain, expect_o should be contained in qmp_o
        result_check = not_contain, expect_o should not be contained in qmp_o.

        :param qmp_o: output from pre_cmd, qmp_cmd or post_cmd.
        :type qmp_o: list
        :param expect_o: the expect result.
        :type expect_o: list
        """
        logging.info("Expect result is %s", expect_o)
        logging.info("Actual result that get from qmp_cmd/post_cmd is %s",
                     qmp_o)
        if result_check == "equal":
            if not operator.eq(qmp_o, expect_o):
                test.fail("QMP output does not equal to the expect result.\n "
                          "Expect result: '%s'\n"
                          "Actual result: '%s'" % (expect_o, qmp_o))
        elif result_check == "contain":
            for o in expect_o:
                if isinstance(o, dict):
                    for key, val in o.items():
                        result = check_list(qmp_o, key, val)
                        if not result:
                            break
                elif isinstance(o, str):
                    result = check_list(qmp_o, o, check_item_in_pair=False)

                if result:
                    logging.info("QMP output contain the expect value %s", o)
                else:
                    test.fail("QMP output does not contain the expect value.\n"
                              "Missed expect value: '%s'\n"
                              "Actual result: '%s'\n" % (o, qmp_o))
        elif result_check == "not_contain":
            for o in expect_o:
                if isinstance(o, dict):
                    for key, val in o.items():
                        result = check_list(qmp_o, key, val)
                        if result:
                            break
                elif isinstance(o, str):
                    result = check_list(qmp_o, o, check_item_in_pair=False)

                if result:
                    test.fail("QMP output contain the unexpect result.\n"
                              "Unexpect result: '%s'\n"
                              "Actual result: '%s'" % (o, qmp_o))

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        test.cancel("Host qemu does not support qmp.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    module = params.get("modprobe_module")
    if module:
        logging.info("modprobe the module %s", module)
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
        test.error("Incorrect configuration, no QMP monitor found.")
    callback = {
        "host_cmd":
        lambda cmd: process.system_output(cmd, shell=True).decode(),
        "guest_cmd": session.cmd_output,
        "qmp_cmd": qmp_port.send_args_cmd
    }

    def send_cmd(cmd):
        """ Helper to execute command on host/ssh guest/qmp monitor """
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            test.error("cmd_type is not supported")

    pre_cmd = params.get("pre_cmd")
    qmp_cmd = params.get("qmp_cmd")
    post_cmd = params.get("post_cmd")
    cmd_type = params.get("event_cmd_type")
    result_check = params.get("cmd_result_check")
    strict_match = params.get("strict_match", "yes") == 'yes'
    expect_o = eval(params.get("cmd_return_value", "[]"))

    # Pre command
    if pre_cmd is not None:
        logging.info("Run prepare command '%s'.", pre_cmd)
        pre_o = send_cmd(pre_cmd)
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)

    # qmp command
    try:
        # Testing command
        logging.info("Run qmp command '%s'.", qmp_cmd)
        qmp_o = qmp_port.send_args_cmd(qmp_cmd)
        if not isinstance(qmp_o, list):
            qmp_o = [qmp_o]
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, qmp_o)
    except qemu_monitor.QMPCmdError as err:
        if params.get("negative_test") == 'yes':
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
                    test.fail("'%s' not in exception '%s'" %
                              (check_pattern, err))
        else:
            test.fail(err)
    except qemu_monitor.MonitorProtocolError as err:
        test.fail(err)
    except Exception as err:
        test.fail(err)

    # sleep 10s to make netdev_del take effect
    if 'netdev_del' in qmp_cmd:
        time.sleep(10)

    # Post command
    if post_cmd is not None:
        logging.info("Run post command '%s'.", post_cmd)
        post_o = send_cmd(post_cmd)
        if not isinstance(post_o, list):
            post_o = [post_o]
        logging.debug("Post-command: '%s'\n Output: '%s'", post_cmd, post_o)

    if result_check == "equal" or result_check == "contain":
        logging.info("Verify qmp command '%s' works as designed.", qmp_cmd)
        if qmp_cmd == "query-name":
            vm_name = params["main_vm"]
            expect_o = [{'name': vm_name}]
        elif qmp_cmd == "query-uuid":
            uuid_input = params["uuid"]
            expect_o = [{'UUID': uuid_input}]
        elif qmp_cmd == "query-version":
            qemu_version_cmd = "rpm -qa | grep -E 'qemu-kvm(-(rhev|ma))?-[0-9]' | head -n 1"
            host_arch = platform.machine()
            qemu_version = callback["host_cmd"](qemu_version_cmd).replace(
                '.%s' % host_arch, '')
            expect_o = [str(qemu_version)]
        elif qmp_cmd == "query-block":
            images = params['images'].split()
            image_info = {}
            for image in images:
                image_params = params.object_params(image)
                image_format = image_params['image_format']
                image_drive = "drive_%s" % image
                if vm.check_capability(Flags.BLOCKDEV):
                    image_info['node-name'] = image_drive
                else:
                    image_info['device'] = image_drive
                image_info['qdev'] = image
                image_info['format'] = image_format
                expect_o.append(image_info)
        elif qmp_cmd == "query-target":
            host_arch = platform.machine()
            if host_arch == "ppc64le":
                host_arch = host_arch[:5]
            expect_o = [{"arch": host_arch}]
        elif qmp_cmd == "query-machines":
            # Remove avocado machine type
            vm_machines = params["machine_type"].split(':', 1)[-1]
            expect_o = [{'alias': vm_machines}]
        check_result(qmp_o, expect_o)
    elif result_check.startswith("post_"):
        logging.info("Verify post qmp command '%s' works as designed.",
                     post_cmd)
        result_check = result_check.split('_', 1)[1]
        check_result(post_o, expect_o)
    session.close()
Beispiel #45
0
def run(test, params, env):
    """
    Boot guest with different cpu flags and check if guest works correctly.

    :param test: kvm test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    cpu.Flag.aliases = cpu.kvm_map_flags_aliases
    qemu_binary = utils_misc.get_qemu_binary(params)

    cpuflags_src = os.path.join(data_dir.get_deps_dir("cpu_flags"), "src")
    cpuflags_def = os.path.join(data_dir.get_deps_dir("cpu_flags"),
                                "cpu_map.xml")
    smp = int(params.get("smp", 1))

    all_host_supported_flags = params.get("all_host_supported_flags", "no")

    mig_timeout = float(params.get("mig_timeout", "3600"))
    mig_protocol = params.get("migration_protocol", "tcp")
    mig_speed = params.get("mig_speed", "1G")

    cpu_model_black_list = params.get("cpu_model_blacklist", "").split(" ")

    multi_host_migration = params.get("multi_host_migration", "no")

    class HgFlags(object):

        def __init__(self, cpu_model, extra_flags=set([])):
            virtual_flags = set(map(cpu.Flag,
                                    params.get("guest_spec_flags", "").split()))
            self.hw_flags = set(map(utils_misc.Flag,
                                    params.get("host_spec_flags", "").split()))
            self.qemu_support_flags = get_all_qemu_flags()
            self.host_support_flags = set(map(cpu.Flag,
                                              cpu.get_cpu_flags()))
            self.quest_cpu_model_flags = (get_guest_host_cpuflags(cpu_model) -
                                          virtual_flags)

            self.supported_flags = (self.qemu_support_flags &
                                    self.host_support_flags)
            self.cpumodel_unsupport_flags = (self.supported_flags -
                                             self.quest_cpu_model_flags)

            self.host_unsupported_flags = (self.quest_cpu_model_flags -
                                           self.host_support_flags)

            self.all_possible_guest_flags = (self.quest_cpu_model_flags -
                                             self.host_unsupported_flags)
            self.all_possible_guest_flags |= self.cpumodel_unsupport_flags

            self.guest_flags = (self.quest_cpu_model_flags -
                                self.host_unsupported_flags)
            self.guest_flags |= extra_flags

            self.host_all_unsupported_flags = set([])
            self.host_all_unsupported_flags |= self.qemu_support_flags
            self.host_all_unsupported_flags -= (self.host_support_flags |
                                                virtual_flags)

    def start_guest_with_cpuflags(cpuflags, smp=None, migration=False,
                                  wait=True):
        """
        Try to boot guest with special cpu flags and try login in to them.
        """
        params_b = params.copy()
        params_b["cpu_model"] = cpuflags
        if smp is not None:
            params_b["smp"] = smp

        vm_name = "vm1-cpuflags"
        vm = qemu_vm.VM(vm_name, params_b, test.bindir, env['address_cache'])
        env.register_vm(vm_name, vm)
        if (migration is True):
            vm.create(migration_mode=mig_protocol)
        else:
            vm.create()

        session = None
        try:
            vm.verify_alive()

            if wait:
                session = vm.wait_for_login()
        except qemu_vm.ImageUnbootableError:
            vm.destroy(gracefully=False)
            raise

        return (vm, session)

    def get_guest_system_cpuflags(vm_session):
        """
        Get guest system cpuflags.

        :param vm_session: session to checked vm.
        :return: [corespond flags]
        """
        flags_re = re.compile(r'^flags\s*:(.*)$', re.MULTILINE)
        out = vm_session.cmd_output("cat /proc/cpuinfo")

        flags = flags_re.search(out).groups()[0].split()
        return set(map(cpu.Flag, flags))

    def get_guest_host_cpuflags_legacy(cpumodel):
        """
        Get cpu flags correspond with cpumodel parameters.

        :param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
        :return: [corespond flags]
        """
        cmd = qemu_binary + " -cpu ?dump"
        output = process.run(cmd).stdout
        re.escape(cpumodel)
        pattern = (r".+%s.*\n.*\n +feature_edx .+ \((.*)\)\n +feature_"
                   r"ecx .+ \((.*)\)\n +extfeature_edx .+ \((.*)\)\n +"
                   r"extfeature_ecx .+ \((.*)\)\n" % (cpumodel))
        flags = []
        model = re.search(pattern, output)
        if model is None:
            test.fail("Cannot find %s cpu model." % (cpumodel))
        for flag_group in model.groups():
            flags += flag_group.split()
        return set(map(cpu.Flag, flags))

    class ParseCpuFlags(object):

        def __init__(self, encoding=None):
            self.cpus = {}
            self.parser = expat.ParserCreate(encoding)
            self.parser.StartElementHandler = self.start_element
            self.parser.EndElementHandler = self.end_element
            self.last_arch = None
            self.last_model = None
            self.sub_model = False
            self.all_flags = []

        def start_element(self, name, attrs):
            if name == "cpus":
                self.cpus = {}
            elif name == "arch":
                self.last_arch = self.cpus[attrs['name']] = {}
            elif name == "model":
                if self.last_model is None:
                    self.last_model = self.last_arch[attrs['name']] = []
                else:
                    self.last_model += self.last_arch[attrs['name']]
                    self.sub_model = True
            elif name == "feature":
                if self.last_model is not None:
                    self.last_model.append(attrs['name'])
                else:
                    self.all_flags.append(attrs['name'])

        def end_element(self, name):
            if name == "arch":
                self.last_arch = None
            elif name == "model":
                if self.sub_model is False:
                    self.last_model = None
                else:
                    self.sub_model = False

        def parse_file(self, file_path):
            self.parser.ParseFile(open(file_path, 'r'))
            return self.cpus

    def get_guest_host_cpuflags_1350(cpumodel):
        """
        Get cpu flags correspond with cpumodel parameters.

        :param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
        :return: [corespond flags]
        """
        p = ParseCpuFlags()
        cpus = p.parse_file(cpuflags_def)
        flags = []
        for arch in cpus.values():
            if cpumodel in arch.keys():
                flags = arch[cpumodel]
        return set(map(cpu.Flag, flags))

    get_guest_host_cpuflags_BAD = get_guest_host_cpuflags_1350

    def get_all_qemu_flags_legacy():
        cmd = qemu_binary + " -cpu ?cpuid"
        output = process.run(cmd).stdout

        flags_re = re.compile(r".*\n.*f_edx:(.*)\n.*f_ecx:(.*)\n"
                              ".*extf_edx:(.*)\n.*extf_ecx:(.*)")
        m = flags_re.search(output)
        flags = []
        for a in m.groups():
            flags += a.split()

        return set(map(cpu.Flag, flags))

    def get_all_qemu_flags_1350():
        cmd = qemu_binary + " -cpu ?"
        output = process.run(cmd).stdout

        flags_re = re.compile(r".*Recognized CPUID flags:\n(.*)", re.DOTALL)
        m = flags_re.search(output)
        flags = []
        for a in m.groups():
            flags += a.split()

        return set(map(cpu.Flag, flags))

    def get_all_qemu_flags_BAD():
        """
        Get cpu flags correspond with cpumodel parameters.

        :param cpumodel: Cpumodel parameter sended to <qemu-kvm-cmd>.
        :return: [corespond flags]
        """
        p = ParseCpuFlags()
        p.parse_file(cpuflags_def)
        return set(map(cpu.Flag, p.all_flags))

    def get_cpu_models_legacy():
        """
        Get all cpu models from qemu.

        :return: cpu models.
        """
        cmd = qemu_binary + " -cpu ?"
        output = process.run(cmd).stdout

        cpu_re = re.compile(r"\w+\s+\[?(\w+)\]?")
        return cpu_re.findall(output)

    def get_cpu_models_1350():
        """
        Get all cpu models from qemu.

        :return: cpu models.
        """
        cmd = qemu_binary + " -cpu ?"
        output = process.run(cmd).stdout

        cpu_re = re.compile(r"x86\s+\[?(\w+)\]?")
        return cpu_re.findall(output)

    get_cpu_models_BAD = get_cpu_models_1350

    def get_qemu_cpu_cmd_version():
        cmd = qemu_binary + " -cpu ?cpuid"
        try:
            process.run(cmd).stdout
            return "legacy"
        except:
            cmd = qemu_binary + " -cpu ?"
            output = process.run(cmd).stdout
            if "CPUID" in output:
                return "1350"
            else:
                return "BAD"

    qcver = get_qemu_cpu_cmd_version()

    get_guest_host_cpuflags = locals()["get_guest_host_cpuflags_%s" % qcver]
    get_all_qemu_flags = locals()["get_all_qemu_flags_%s" % qcver]
    get_cpu_models = locals()["get_cpu_models_%s" % qcver]

    def get_flags_full_name(cpu_flag):
        """
        Get all name of Flag.

        :param cpu_flag: Flag
        :return: all name of Flag.
        """
        cpu_flag = cpu.Flag(cpu_flag)
        for f in get_all_qemu_flags():
            if f == cpu_flag:
                return cpu.Flag(f)
        return []

    def parse_qemu_cpucommand(cpumodel):
        """
        Parse qemu cpu params.

        :param cpumodel: Cpu model command.
        :return: All flags which guest must have.
        """
        flags = cpumodel.split(",")
        cpumodel = flags[0]

        qemu_model_flag = get_guest_host_cpuflags(cpumodel)
        host_support_flag = set(map(cpu.Flag,
                                    cpu.get_cpu_flags()))
        real_flags = qemu_model_flag & host_support_flag

        for f in flags[1:]:
            if f[0].startswith("+"):
                real_flags |= set([get_flags_full_name(f[1:])])
            if f[0].startswith("-"):
                real_flags -= set([get_flags_full_name(f[1:])])

        return real_flags

    def check_cpuflags(cpumodel, vm_session):
        """
        Check if vm flags are same like flags select by cpumodel.

        :param cpumodel: params for -cpu param in qemu-kvm
        :param vm_session: session to vm to check flags.

        :return: ([excess], [missing]) flags
        """
        gf = get_guest_system_cpuflags(vm_session)
        rf = parse_qemu_cpucommand(cpumodel)

        logging.debug("Guest flags: %s", gf)
        logging.debug("Host flags: %s", rf)
        logging.debug("Flags on guest not defined by host: %s", (gf - rf))
        return rf - gf

    def get_cpu_models_supported_by_host():
        """
        Get all cpumodels which set of flags is subset of hosts flags.

        :return: [cpumodels]
        """
        cpumodels = []
        for cpumodel in get_cpu_models():
            flags = HgFlags(cpumodel)
            if flags.host_unsupported_flags == set([]):
                cpumodels.append(cpumodel)
        return cpumodels

    def disable_cpu(vm_session, cpu, disable=True):
        """
        Disable cpu in guest system.

        :param cpu: CPU id to disable.
        :param disable: if True disable cpu else enable cpu.
        """
        system_cpu_dir = "/sys/devices/system/cpu/"
        cpu_online = system_cpu_dir + "cpu%d/online" % (cpu)
        cpu_state = vm_session.cmd_output("cat %s" % cpu_online).strip()
        if disable and cpu_state == "1":
            vm_session.cmd("echo 0 > %s" % cpu_online)
            logging.debug("Guest cpu %d is disabled.", cpu)
        elif cpu_state == "0":
            vm_session.cmd("echo 1 > %s" % cpu_online)
            logging.debug("Guest cpu %d is enabled.", cpu)

    def check_online_cpus(vm_session, smp, disabled_cpu):
        """
        Disable cpu in guest system.

        :param smp: Count of cpu core in system.
        :param disable_cpu: List of disabled cpu.

        :return: List of CPUs that are still enabled after disable procedure.
        """
        online = [0]
        for cpuid in range(1, smp):
            system_cpu_dir = "/sys/devices/system/cpu/"
            cpu_online = system_cpu_dir + "cpu%d/online" % (cpuid)
            cpu_state = vm_session.cmd_output("cat %s" % cpu_online).strip()
            if cpu_state == "1":
                online.append(cpuid)
        cpu_proc = vm_session.cmd_output("cat /proc/cpuinfo")
        cpu_state_proc = map(lambda x: int(x),
                             re.findall(r"processor\s+:\s*(\d+)\n", cpu_proc))
        if set(online) != set(cpu_state_proc):
            test.error("Some cpus are disabled but %s are still "
                       "visible like online in /proc/cpuinfo." %
                       (set(cpu_state_proc) - set(online)))

        return set(online) - set(disabled_cpu)

    def install_cpuflags_test_on_vm(vm, dst_dir):
        """
        Install stress to vm.

        :param vm: virtual machine.
        :param dst_dir: Installation path.
        """
        session = vm.wait_for_login()
        vm.copy_files_to(cpuflags_src, dst_dir)
        session.cmd("sync")
        session.cmd("cd %s; make EXTRA_FLAGS='';" %
                    os.path.join(dst_dir, "src"))
        session.cmd("sync")
        session.close()

    def check_cpuflags_work(vm, path, flags):
        """
        Check which flags work.

        :param vm: Virtual machine.
        :param path: Path of cpuflags_test
        :param flags: Flags to test.
        :return: Tuple (Working, not working, not tested) flags.
        """
        pass_Flags = []
        not_tested = []
        not_working = []
        session = vm.wait_for_login()
        for f in flags:
            try:
                for tc in cpu.kvm_map_flags_to_test[f]:
                    session.cmd("%s/cpuflags-test --%s" %
                                (os.path.join(path, "src"), tc))
                pass_Flags.append(f)
            except aexpect.ShellCmdError:
                not_working.append(f)
            except KeyError:
                not_tested.append(f)
        return (set(map(cpu.Flag, pass_Flags)),
                set(map(cpu.Flag, not_working)),
                set(map(cpu.Flag, not_tested)))

    def run_stress(vm, timeout, guest_flags):
        """
        Run stress on vm for timeout time.
        """
        ret = False
        install_path = "/tmp"
        install_cpuflags_test_on_vm(vm, install_path)
        flags = check_cpuflags_work(vm, install_path, guest_flags)
        dd_session = vm.wait_for_login()
        stress_session = vm.wait_for_login()
        dd_session.sendline("dd if=/dev/[svh]da of=/tmp/stressblock"
                            " bs=10MB count=100 &")
        try:
            stress_session.cmd("%s/cpuflags-test --stress %s%s" %
                               (os.path.join(install_path, "src"), smp,
                                cpu.kvm_flags_to_stresstests(flags[0])),
                               timeout=timeout)
        except aexpect.ShellTimeoutError:
            ret = True
        stress_session.close()
        dd_session.close()
        return ret

    def separe_cpu_model(cpu_model):
        try:
            (cpu_model, _) = cpu_model.split(":")
        except ValueError:
            cpu_model = cpu_model
        return cpu_model

    def parse_cpu_model():
        """
        Parse cpu_models from config file.

        :return: [(cpumodel, extra_flags)]
        """
        cpu_model = params.get("cpu_model", "")
        logging.debug("CPU model found: %s", str(cpu_model))

        try:
            (cpu_model, extra_flags) = cpu_model.split(":")
            extra_flags = set(map(cpu.Flag, extra_flags.split(",")))
        except ValueError:
            cpu_model = cpu_model
            extra_flags = set([])
        return (cpu_model, extra_flags)

    class MiniSubtest(object):

        def __new__(cls, *args, **kargs):
            self = super(MiniSubtest, cls).__new__(cls)
            ret = None
            if args is None:
                args = []
            try:
                ret = self.test(*args, **kargs)
            finally:
                if hasattr(self, "clean"):
                    self.clean()
            return ret

    def print_exception(called_object):
        exc_type, exc_value, exc_traceback = sys.exc_info()
        logging.error("In function (%s):", called_object.__name__)
        logging.error("Call from:\n%s",
                      traceback.format_stack()[-2][:-1])
        logging.error("Exception from:\n%s",
                      "".join(traceback.format_exception(
                              exc_type, exc_value,
                              exc_traceback.tb_next)))

    class Test_temp(MiniSubtest):

        def clean(self):
            logging.info("cleanup")
            vm = getattr(self, "vm", None)
            if vm:
                vm.destroy(gracefully=False)
            clone = getattr(self, "clone", None)
            if clone:
                clone.destroy(gracefully=False)

    # 1) <qemu-kvm-cmd> -cpu ?model
    class test_qemu_cpu_model(MiniSubtest):

        def test(self):
            if qcver == "legacy":
                cpu_models = params.get("cpu_models", "core2duo").split()
                cmd = qemu_binary + " -cpu ?model"
                result = process.run(cmd)
                missing = []
                cpu_models = map(separe_cpu_model, cpu_models)
                for cpu_model in cpu_models:
                    if cpu_model not in result.stdout:
                        missing.append(cpu_model)
                if missing:
                    test.fail("CPU models %s are not in output "
                              "'%s' of command \n%s" %
                              (missing, cmd, result.stdout))
            else:
                test.cancel("New qemu does not support -cpu "
                            "?model. (%s)" % qcver)

    # 2) <qemu-kvm-cmd> -cpu ?dump
    class test_qemu_dump(MiniSubtest):

        def test(self):
            if qcver == "legacy":
                cpu_models = params.get("cpu_models", "core2duo").split()
                cmd = qemu_binary + " -cpu ?dump"
                result = process.run(cmd)
                cpu_models = map(separe_cpu_model, cpu_models)
                missing = []
                for cpu_model in cpu_models:
                    if cpu_model not in result.stdout:
                        missing.append(cpu_model)
                if missing:
                    test.fail("CPU models %s are not in output "
                              "'%s' of command \n%s" %
                              (missing, cmd, result.stdout))
            else:
                test.cancel("New qemu does not support -cpu "
                            "?dump. (%s)" % qcver)

    # 3) <qemu-kvm-cmd> -cpu ?cpuid
    class test_qemu_cpuid(MiniSubtest):

        def test(self):
            if qcver == "legacy":
                cmd = qemu_binary + " -cpu ?cpuid"
                result = process.run(cmd)
                if result.stdout is "":
                    test.fail("There aren't any cpu Flag in output"
                              " '%s' of command \n%s" % (cmd, result.stdout))
            else:
                test.cancel("New qemu does not support -cpu "
                            "?cpuid. (%s)" % qcver)

    # 1) boot with cpu_model
    class test_boot_cpu_model(Test_temp):

        def test(self):
            cpu_model, _ = parse_cpu_model()
            logging.debug("Run tests with cpu model %s", cpu_model)
            flags = HgFlags(cpu_model)
            (self.vm, session) = start_guest_with_cpuflags(cpu_model)
            not_enable_flags = (check_cpuflags(cpu_model, session) -
                                flags.hw_flags)
            if not_enable_flags != set([]):
                test.fail("Flags defined on host but not found "
                          "on guest: %s" % (not_enable_flags))

    # 2) success boot with supported flags
    class test_boot_cpu_model_and_additional_flags(Test_temp):

        def test(self):
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            cpuf_model = cpu_model

            if all_host_supported_flags == "yes":
                for fadd in flags.cpumodel_unsupport_flags:
                    cpuf_model += ",+" + str(fadd)
            else:
                for fadd in extra_flags:
                    cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            if all_host_supported_flags == "yes":
                guest_flags = flags.all_possible_guest_flags
            else:
                guest_flags = flags.guest_flags

            (self.vm, session) = start_guest_with_cpuflags(cpuf_model)

            not_enable_flags = (check_cpuflags(cpuf_model, session) -
                                flags.hw_flags)
            if not_enable_flags != set([]):
                logging.info("Model unsupported flags: %s",
                             str(flags.cpumodel_unsupport_flags))
                logging.error("Flags defined on host but not on found "
                              "on guest: %s", str(not_enable_flags))
            logging.info("Check main instruction sets.")

            install_path = "/tmp"
            install_cpuflags_test_on_vm(self.vm, install_path)

            Flags = check_cpuflags_work(self.vm, install_path,
                                        flags.all_possible_guest_flags)
            logging.info("Woking CPU flags: %s", str(Flags[0]))
            logging.info("Not working CPU flags: %s", str(Flags[1]))
            logging.warning("Flags works even if not defined on guest cpu "
                            "flags: %s", str(Flags[0] - guest_flags))
            logging.warning("Not tested CPU flags: %s", str(Flags[2]))

            if Flags[1] & guest_flags:
                test.fail("Some flags do not work: %s" % (str(Flags[1])))

    # 3) fail boot unsupported flags
    class test_boot_warn_with_host_unsupported_flags(MiniSubtest):

        def test(self):
            # This is virtual cpu flags which are supported by
            # qemu but no with host cpu.
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Unsupported flags %s.",
                          str(flags.host_all_unsupported_flags))
            cpuf_model = cpu_model + ",check"

            # Add unsupported flags.
            for fadd in flags.host_all_unsupported_flags:
                cpuf_model += ",+" + str(fadd)

            vnc_port = utils_misc.find_free_port(5900, 6100) - 5900
            cmd = "%s -cpu %s -vnc :%d -enable-kvm" % (qemu_binary,
                                                       cpuf_model,
                                                       vnc_port)
            out = None

            try:
                try:
                    out = process.run(cmd, timeout=5, ignore_status=True).stderr
                    test.fail("Guest not boot with unsupported flags.")
                except process.CmdError as e:
                    out = e.result.stderr
            finally:
                uns_re = re.compile(r"^warning:.*flag '(.+)'", re.MULTILINE)
                nf_re = re.compile(
                    r"^CPU feature (.+) not found", re.MULTILINE)
                warn_flags = set([cpu.Flag(x)
                                  for x in uns_re.findall(out)])
                not_found = set([cpu.Flag(x)
                                 for x in nf_re.findall(out)])
                fwarn_flags = flags.host_all_unsupported_flags - warn_flags
                fwarn_flags -= not_found
                if fwarn_flags:
                    test.fail("Qemu did not warn the use of "
                              "flags %s" % str(fwarn_flags))

    # 3) fail boot unsupported flags
    class test_fail_boot_with_host_unsupported_flags(MiniSubtest):

        def test(self):
            # This is virtual cpu flags which are supported by
            # qemu but no with host cpu.
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)
            cpuf_model = cpu_model + ",enforce"

            logging.debug("Unsupported flags %s.",
                          str(flags.host_all_unsupported_flags))

            # Add unsupported flags.
            for fadd in flags.host_all_unsupported_flags:
                cpuf_model += ",+" + str(fadd)

            vnc_port = utils_misc.find_free_port(5900, 6100) - 5900
            cmd = "%s -cpu %s -vnc :%d -enable-kvm" % (qemu_binary,
                                                       cpuf_model,
                                                       vnc_port)
            out = None
            try:
                try:
                    out = process.run(cmd, timeout=5, ignore_status=True).stderr
                except process.CmdError:
                    logging.error("Host boot with unsupported flag")
            finally:
                uns_re = re.compile(r"^warning:.*flag '(.+)'", re.MULTILINE)
                nf_re = re.compile(
                    r"^CPU feature (.+) not found", re.MULTILINE)
                warn_flags = set([cpu.Flag(x)
                                  for x in uns_re.findall(out)])
                not_found = set([cpu.Flag(x)
                                 for x in nf_re.findall(out)])
                fwarn_flags = flags.host_all_unsupported_flags - warn_flags
                fwarn_flags -= not_found
                if fwarn_flags:
                    test.fail("Qemu did not warn the use of "
                              "flags %s" % str(fwarn_flags))

    # 4) check guest flags under load cpu, stress and system (dd)
    class test_boot_guest_and_try_flags_under_load(Test_temp):

        def test(self):
            logging.info("Check guest working cpuflags under load "
                         "cpu and stress and system (dd)")
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            cpuf_model = cpu_model

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))

            if all_host_supported_flags == "yes":
                logging.debug("Added flags %s.",
                              str(flags.cpumodel_unsupport_flags))

                # Add unsupported flags.
                for fadd in flags.cpumodel_unsupport_flags:
                    cpuf_model += ",+" + str(fadd)

                for fdel in flags.host_unsupported_flags:
                    cpuf_model += ",-" + str(fdel)

            (self.vm, _) = start_guest_with_cpuflags(cpuf_model, smp)

            if (not run_stress(self.vm, 60, flags.guest_flags)):
                test.fail("Stress test ended before end of test.")

    # 5) Online/offline CPU
    class test_online_offline_guest_CPUs(Test_temp):

        def test(self):
            cpu_model, extra_flags = parse_cpu_model()

            logging.debug("Run tests with cpu model %s.", (cpu_model))
            flags = HgFlags(cpu_model, extra_flags)

            (self.vm, session) = start_guest_with_cpuflags(cpu_model, smp)

            def encap(timeout):
                random.seed()
                begin = time.time()
                end = begin
                if smp > 1:
                    while end - begin < 60:
                        cpu = random.randint(1, smp - 1)
                        if random.randint(0, 1):
                            disable_cpu(session, cpu, True)
                        else:
                            disable_cpu(session, cpu, False)
                        end = time.time()
                    return True
                else:
                    logging.warning("For this test is necessary smp > 1.")
                    return False
            timeout = 60

            test_flags = flags.guest_flags
            if all_host_supported_flags == "yes":
                test_flags = flags.all_possible_guest_flags

            result = utils_misc.parallel([(encap, [timeout]),
                                          (run_stress, [self.vm, timeout,
                                                        test_flags])])
            if not (result[0] and result[1]):
                test.fail("Stress tests failed before end of testing.")

    # 6) migration test
    class test_migration_with_additional_flags(Test_temp):

        def test(self):
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            logging.debug("Added flags %s.",
                          str(flags.cpumodel_unsupport_flags))
            cpuf_model = cpu_model

            # Add unsupported flags.
            for fadd in flags.cpumodel_unsupport_flags:
                cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            (self.vm, _) = start_guest_with_cpuflags(cpuf_model, smp)

            install_path = "/tmp"
            install_cpuflags_test_on_vm(self.vm, install_path)
            flags = check_cpuflags_work(self.vm, install_path,
                                        flags.guest_flags)
            test.assertTrue(flags[0], "No cpuflags passed the check: %s"
                            % str(flags))
            test.assertFalse(flags[1], "Some cpuflags failed the check: %s"
                             % str(flags))
            dd_session = self.vm.wait_for_login()
            stress_session = self.vm.wait_for_login()

            dd_session.sendline("nohup dd if=$(echo /dev/[svh]da) of=/tmp/"
                                "stressblock bs=10MB count=100 &")
            cmd = ("nohup %s/cpuflags-test --stress  %s%s &" %
                   (os.path.join(install_path, "src"), smp,
                    cpu.kvm_flags_to_stresstests(flags[0])))
            stress_session.sendline(cmd)

            time.sleep(5)

            qemu_migration.set_speed(self.vm, mig_speed)
            self.clone = self.vm.migrate(
                mig_timeout, mig_protocol, offline=False,
                not_wait_for_migration=True)

            time.sleep(5)

            try:
                self.vm.wait_for_migration(10)
            except virt_vm.VMMigrateTimeoutError:
                qemu_migration.set_downtime(self.vm, 1)
                self.vm.wait_for_migration(mig_timeout)

            self.clone.resume()
            self.vm.destroy(gracefully=False)

            stress_session = self.clone.wait_for_login()

            # If cpuflags-test hang up during migration test raise exception
            try:
                stress_session.cmd('killall cpuflags-test')
            except aexpect.ShellCmdError:
                test.fail("Stress cpuflags-test should be still "
                          "running after migration.")
            try:
                stress_session.cmd("ls /tmp/stressblock && "
                                   "rm -f /tmp/stressblock")
            except aexpect.ShellCmdError:
                test.fail("Background 'dd' command failed to "
                          "produce output file.")

    def net_send_object(socket, obj):
        """
        Send python object over network.

        :param ip_addr: ipaddres of waiter for data.
        :param obj: object to send
        """
        data = pickle.dumps(obj, pickle.HIGHEST_PROTOCOL)
        socket.sendall("%6d" % len(data))
        socket.sendall(data)

    def net_recv_object(socket, timeout=60):
        """
        Receive python object over network.

        :param ip_addr: ipaddres of waiter for data.
        :param obj: object to send
        :return: object from network
        """
        try:
            time_start = time.time()
            data = ""
            d_len = int(socket.recv(6))

            while (len(data) < d_len and (time.time() - time_start) < timeout):
                data += socket.recv(d_len - len(data))

            data = pickle.loads(data)
            return data
        except:
            test.fail("Failed to receive python object over the network")

    class test_multi_host_migration(Test_temp):

        def test(self):
            """
            Test migration between multiple hosts.
            """
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            logging.debug("Added flags %s.",
                          str(flags.cpumodel_unsupport_flags))
            cpuf_model = cpu_model

            for fadd in extra_flags:
                cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            install_path = "/tmp"

            class testMultihostMigration(migration.MultihostMigration):

                def __init__(self, test, params, env):
                    migration.MultihostMigration.__init__(self, test, params,
                                                          env)

                def migration_scenario(self):
                    srchost = self.params.get("hosts")[0]
                    dsthost = self.params.get("hosts")[1]

                    def worker(mig_data):
                        vm = env.get_vm("vm1")
                        session = vm.wait_for_login(timeout=self.login_timeout)

                        install_cpuflags_test_on_vm(vm, install_path)

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s", str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))
                        session.sendline("nohup dd if=/dev/[svh]da of=/tmp/"
                                         "stressblock bs=10MB count=100 &")

                        cmd = ("nohup %s/cpuflags-test --stress  %s%s &" %
                               (os.path.join(install_path, "src"),
                                smp,
                                cpu.kvm_flags_to_stresstests(Flags[0] &
                                                             flags.guest_flags)))
                        logging.debug("Guest_flags: %s",
                                      str(flags.guest_flags))
                        logging.debug("Working_flags: %s", str(Flags[0]))
                        logging.debug("Start stress on guest: %s", cmd)
                        session.sendline(cmd)

                    def check_worker(mig_data):
                        vm = env.get_vm("vm1")

                        vm.verify_illegal_instruction()

                        session = vm.wait_for_login(timeout=self.login_timeout)

                        try:
                            session.cmd('killall cpuflags-test')
                        except aexpect.ShellCmdError:
                            test.fail("The cpuflags-test program"
                                      " should be active after"
                                      " migration and it's not.")

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s",
                                     str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))

                    self.migrate_wait(["vm1"], srchost, dsthost,
                                      worker, check_worker)

            params_b = params.copy()
            params_b["cpu_model"] = cpu_model
            mig = testMultihostMigration(test, params_b, env)
            mig.run()

    class test_multi_host_migration_onoff_cpu(Test_temp):

        def test(self):
            """
            Test migration between multiple hosts.
            """
            cpu_model, extra_flags = parse_cpu_model()

            flags = HgFlags(cpu_model, extra_flags)

            logging.debug("Cpu mode flags %s.",
                          str(flags.quest_cpu_model_flags))
            logging.debug("Added flags %s.",
                          str(flags.cpumodel_unsupport_flags))
            cpuf_model = cpu_model

            for fadd in extra_flags:
                cpuf_model += ",+" + str(fadd)

            for fdel in flags.host_unsupported_flags:
                cpuf_model += ",-" + str(fdel)

            smp = int(params["smp"])
            disable_cpus = list(map(lambda cpu: int(cpu),
                                    params.get("disable_cpus", "").split()))

            install_path = "/tmp"

            class testMultihostMigration(migration.MultihostMigration):

                def __init__(self, test, params, env):
                    migration.MultihostMigration.__init__(self, test, params,
                                                          env)
                    self.srchost = self.params.get("hosts")[0]
                    self.dsthost = self.params.get("hosts")[1]
                    self.id = {'src': self.srchost,
                               'dst': self.dsthost,
                               "type": "disable_cpu"}
                    self.migrate_count = int(self.params.get('migrate_count',
                                                             '2'))

                def ping_pong_migrate(self, sync, worker, check_worker):
                    for _ in range(self.migrate_count):
                        logging.info("File transfer not ended, starting"
                                     " a round of migration...")
                        sync.sync(True, timeout=mig_timeout)
                        if self.hostid == self.srchost:
                            self.migrate_wait(["vm1"],
                                              self.srchost,
                                              self.dsthost,
                                              start_work=worker)
                        elif self.hostid == self.dsthost:
                            self.migrate_wait(["vm1"],
                                              self.srchost,
                                              self.dsthost,
                                              check_work=check_worker)
                        tmp = self.dsthost
                        self.dsthost = self.srchost
                        self.srchost = tmp

                def migration_scenario(self):
                    from autotest.client.shared.syncdata import SyncData

                    sync = SyncData(self.master_id(), self.hostid, self.hosts,
                                    self.id, self.sync_server)

                    def worker(mig_data):
                        vm = env.get_vm("vm1")
                        session = vm.wait_for_login(timeout=self.login_timeout)

                        install_cpuflags_test_on_vm(vm, install_path)

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s", str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))
                        for cpu in disable_cpus:
                            if cpu < smp:
                                disable_cpu(session, cpu, True)
                            else:
                                logging.warning("There is no enouth cpu"
                                                " in Guest. It is trying to"
                                                "remove cpu:%s from guest with"
                                                " smp:%s.", cpu, smp)
                        logging.debug("Guest_flags: %s",
                                      str(flags.guest_flags))
                        logging.debug("Working_flags: %s", str(Flags[0]))

                    def check_worker(mig_data):
                        vm = env.get_vm("vm1")

                        vm.verify_illegal_instruction()

                        session = vm.wait_for_login(timeout=self.login_timeout)

                        really_disabled = check_online_cpus(session, smp,
                                                            disable_cpus)

                        not_disabled = set(really_disabled) & set(disable_cpus)
                        if not_disabled:
                            test.fail("Some of disabled cpus are "
                                      "online. This shouldn't "
                                      "happen. Cpus disabled on "
                                      "srchost:%s, Cpus not "
                                      "disabled on dsthost:%s" %
                                      (disable_cpus, not_disabled))

                        Flags = check_cpuflags_work(vm, install_path,
                                                    flags.all_possible_guest_flags)
                        logging.info("Woking CPU flags: %s",
                                     str(Flags[0]))
                        logging.info("Not working CPU flags: %s",
                                     str(Flags[1]))
                        logging.warning("Flags works even if not defined on"
                                        " guest cpu flags: %s",
                                        str(Flags[0] - flags.guest_flags))
                        logging.warning("Not tested CPU flags: %s",
                                        str(Flags[2]))

                    self.ping_pong_migrate(sync, worker, check_worker)

            params_b = params.copy()
            params_b["cpu_model"] = cpu_model
            mig = testMultihostMigration(test, params_b, env)
            mig.run()

    test_type = params.get("test_type")
    if (test_type in locals()):
        tests_group = locals()[test_type]
        if params.get("cpu_model"):
            tests_group()
        else:
            cpu_models = (set(get_cpu_models_supported_by_host()) -
                          set(cpu_model_black_list))
            if not cpu_models:
                test.cancel("No cpu_models detected, nothing to test.")
            logging.info("Start test with cpu models %s", str(cpu_models))
            failed = []
            for cpumodel in cpu_models:
                params["cpu_model"] = cpumodel
                try:
                    tests_group()
                except:
                    print_exception(tests_group)
                    failed.append(cpumodel)
            if failed != []:
                test.fail("Test of cpu models %s failed." % (str(failed)))
    else:
        test.fail("Test group '%s' is not defined in"
                  " cpuflags test" % test_type)
Beispiel #46
0
def run_cpuid(test, params, env):
    """
    Boot guest with different cpu_models and cpu flags and check if guest works correctly.

    @param test: kvm test object.
    @param params: Dictionary with the test parameters.
    @param env: Dictionary with test environment.
    """
    qemu_binary = utils_misc.get_qemu_binary(params)

    cpu_model = params.get("cpu_model", "qemu64")

    xfail = False
    if (params.get("xfail") is not None) and (params.get("xfail") == "yes"):
        xfail = True

    class MiniSubtest(test_module.Subtest):
        """
        subtest base class for actual tests
        """
        def __new__(cls, *args, **kargs):
            self = test.__new__(cls)
            ret = None
            if args is None:
                args = []
            try:
                ret = self.test(*args, **kargs)
            finally:
                if hasattr(self, "clean"):
                    self.clean()
            return ret

        def clean(self):
            """
            cleans up running VM instance
            """
            if (hasattr(self, "vm")):
                vm = getattr(self, "vm")
                if vm.is_alive():
                    vm.pause()
                    vm.destroy(gracefully=False)

        def test(self):
            """
            stub for actual test code
            """
            raise error.TestFail("test() must be redifined in subtest")

    def print_exception(called_object):
        """
        print error including stack trace
        """
        exc_type, exc_value, exc_traceback = sys.exc_info()
        logging.error("In function (" + called_object.__name__ + "):")
        logging.error("Call from:\n" +
                      traceback.format_stack()[-2][:-1])
        logging.error("Exception from:\n" +
                      "".join(traceback.format_exception(
                                              exc_type, exc_value,
                                              exc_traceback.tb_next)))

    def cpu_models_to_test():
        """Return the list of CPU models to be tested, based on the
        cpu_models and cpu_model config options.

        Config option "cpu_model" may be used to ask a single CPU model
        to be tested. Config option "cpu_models" may be used to ask
        multiple CPU models to be tested.

        If cpu_models is "*", all CPU models reported by QEMU will be tested.
        """
        models_opt = params.get("cpu_models")
        model_opt = params.get("cpu_model")

        if (models_opt is None and model_opt is None):
            raise error.TestError("No cpu_models or cpu_model option is set")

        cpu_models = set()

        if models_opt == '*':
            cpu_models.update(utils_misc.get_qemu_cpu_models(qemu_binary))
        elif models_opt:
            cpu_models.update(models_opt.split())

        if model_opt:
            cpu_models.add(model_opt)

        return cpu_models

    class test_qemu_cpu_models_list(MiniSubtest):
        """
        check CPU models returned by <qemu> -cpu '?' are what is expected
        """
        def test(self):
            """
            test method
            """
            cpu_models = cpu_models_to_test()
            qemu_models = utils_misc.get_qemu_cpu_models(qemu_binary)
            missing = set(cpu_models) - set(qemu_models)
            if missing:
                raise error.TestFail("Some CPU models not in QEMU CPU model list: %s")
            added = set(qemu_models) - set(cpu_models)
            if added:
                logging.info("Extra CPU models in QEMU CPU listing: %s", added)

    def get_guest_cpuid(self, cpu_model, feature=None):
        test_kernel_dir = os.path.join(test.virtdir, "deps",
                                       "cpuid_test_kernel")
        os.chdir(test_kernel_dir)
        utils.make("cpuid_dump_kernel.bin")

        vm_name = params['main_vm']
        params_b = params.copy()
        params_b["kernel"] = os.path.join(test_kernel_dir, "cpuid_dump_kernel.bin")
        params_b["cpu_model"] = cpu_model
        params_b["cpu_model_flags"] = feature
        del params_b["images"]
        del params_b["nics"]
        env_process.preprocess_vm(self, params_b, env, vm_name)
        vm = env.get_vm(vm_name)
        vm.create()
        self.vm = vm
        vm.resume()

        timeout = float(params.get("login_timeout", 240))
        f = lambda: re.search("==END TEST==", vm.serial_console.get_output())
        if not utils_misc.wait_for(f, timeout, 1):
            raise error.TestFail("Could not get test complete message.")

        test_sig = re.compile("==START TEST==\n((?:.*\n)*)\n*==END TEST==")
        test_output = test_sig.search(vm.serial_console.get_output())
        if test_output == None:
            raise error.TestFail("Test output signature not found in "
                                 "output:\n %s", vm.serial_console.get_output())
        self.clean()
        return test_output.group(1)

    def cpuid_regs_to_dic(level_count, cpuid_dump):
        """
            @param level_count: is CPUID level and count string in format
                                'LEVEL COUNT', where:
                                      LEVEL - CPUID level in hex format
                                            8 chracters width
                                      COUNT - input ECX value of cpuid in
                                            hex format 2 charaters width
                                example: '0x00000001 0x00'
            @cpuid_dump: string: output of 'cpuid' utility or provided with
                                 this test simple kernel that dumps cpuid
                                 in a similar format.
            @return: dictionary of register values indexed by register name
        """
        grp = '\w*=(\w*)\s*'
        regs = re.search('\s+%s:.*%s%s%s%s' % (level_count, grp, grp, grp, grp),
                         cpuid_dump)
        if regs == None:
            raise error.TestFail("Could not find %s in cpuid output:\n%s",
                                 level_count, cpuid_dump)
        return {'eax': int(regs.group(1), 16), 'ebx': int(regs.group(2), 16),
                'ecx': int(regs.group(3), 16), 'edx': int(regs.group(4), 16) }

    def cpuid_to_vendor(cpuid_dump, idx):
        r = cpuid_regs_to_dic(idx + ' 0x00', cpuid_dump)
        dst =  []
        map(lambda i:
            dst.append((chr(r['ebx'] >> (8 * i) & 0xff))), range(0, 4))
        map(lambda i:
            dst.append((chr(r['edx'] >> (8 * i) & 0xff))), range(0, 4))
        map(lambda i:
            dst.append((chr(r['ecx'] >> (8 * i) & 0xff))), range(0, 4))
        return ''.join(dst)

    class default_vendor(MiniSubtest):
        """
        Boot qemu with specified cpu models and
        verify that CPU vendor matches requested
        """
        def test(self):
            cpu_models = cpu_models_to_test()

            vendor = params.get("vendor")
            if vendor is None or vendor == "host":
                cmd = "grep 'vendor_id' /proc/cpuinfo | head -n1 | awk '{print $3}'"
                cmd_result = utils.run(cmd, ignore_status=True)
                vendor = cmd_result.stdout.strip()

            ignore_cpus = set(params.get("ignore_cpu_models","").split(' '))
            cpu_models = cpu_models - ignore_cpus

            for cpu_model in cpu_models:
                out = get_guest_cpuid(self, cpu_model)
                guest_vendor = cpuid_to_vendor(out, '0x00000000')
                logging.debug("Guest's vendor: " + guest_vendor)
                if guest_vendor != vendor:
                    raise error.TestFail("Guest vendor [%s], doesn't match "
                                         "required vendor [%s] for CPU [%s]" %
                                         (guest_vendor, vendor, cpu_model))

    class custom_vendor(MiniSubtest):
        """
        Boot qemu with specified vendor
        """
        def test(self):
            has_error = False
            vendor = params["vendor"]

            try:
                out = get_guest_cpuid(self, cpu_model, "vendor=" + vendor)
                guest_vendor0 = cpuid_to_vendor(out, '0x00000000')
                guest_vendor80000000 = cpuid_to_vendor(out, '0x80000000')
                logging.debug("Guest's vendor[0]: " + guest_vendor0)
                logging.debug("Guest's vendor[0x80000000]: " +
                              guest_vendor80000000)
                if guest_vendor0 != vendor:
                    raise error.TestFail("Guest vendor[0] [%s], doesn't match "
                                         "required vendor [%s] for CPU [%s]" %
                                         (guest_vendor0, vendor, cpu_model))
                if guest_vendor80000000 != vendor:
                    raise error.TestFail("Guest vendor[0x80000000] [%s], "
                                         "doesn't match required vendor "
                                         "[%s] for CPU [%s]" %
                                         (guest_vendor80000000, vendor,
                                          cpu_model))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_level(cpuid_dump):
        r = cpuid_regs_to_dic('0x00000000 0x00', cpuid_dump)
        return r['eax']

    class custom_level(MiniSubtest):
        """
        Boot qemu with specified level
        """
        def test(self):
            has_error = False
            level = params["level"]
            try:
                out = get_guest_cpuid(self, cpu_model, "level=" + level)
                guest_level = str(cpuid_to_level(out))
                if guest_level != level:
                    raise error.TestFail("Guest's level [%s], doesn't match "
                                         "required level [%s]" %
                                         (guest_level, level))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_family(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_regs_to_dic('0x00000001 0x00', cpuid_dump)['eax']
        family = (eax >> 8) & 0xf
        if family  == 0xf:
            # extract extendend family
            return family + ((eax >> 20) & 0xff)
        return family

    class custom_family(MiniSubtest):
        """
        Boot qemu with specified family
        """
        def test(self):
            has_error = False
            family = params["family"]
            try:
                out = get_guest_cpuid(self, cpu_model, "family=" + family)
                guest_family = str(cpuid_to_family(out))
                if guest_family != family:
                    raise error.TestFail("Guest's family [%s], doesn't match "
                                         "required family [%s]" %
                                         (guest_family, family))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_model(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_regs_to_dic('0x00000001 0x00', cpuid_dump)['eax']
        model = (eax >> 4) & 0xf
        # extended model
        model |= (eax >> 12) & 0xf0
        return model

    class custom_model(MiniSubtest):
        """
        Boot qemu with specified model
        """
        def test(self):
            has_error = False
            model = params["model"]
            try:
                out = get_guest_cpuid(self, cpu_model, "model=" + model)
                guest_model = str(cpuid_to_model(out))
                if guest_model != model:
                    raise error.TestFail("Guest's model [%s], doesn't match "
                                         "required model [%s]" %
                                         (guest_model, model))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_stepping(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_regs_to_dic('0x00000001 0x00', cpuid_dump)['eax']
        stepping = eax & 0xf
        return stepping

    class custom_stepping(MiniSubtest):
        """
        Boot qemu with specified stepping
        """
        def test(self):
            has_error = False
            stepping = params["stepping"]
            try:
                out = get_guest_cpuid(self, cpu_model, "stepping=" + stepping)
                guest_stepping = str(cpuid_to_stepping(out))
                if guest_stepping != stepping:
                    raise error.TestFail("Guest's stepping [%s], doesn't match "
                                         "required stepping [%s]" %
                                         (guest_stepping, stepping))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_xlevel(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.2.1 Largest Extendend Function # (Function 80000000h)
        return cpuid_regs_to_dic('0x80000000 0x00', cpuid_dump)['eax']

    class custom_xlevel(MiniSubtest):
        """
        Boot qemu with specified xlevel
        """
        def test(self):
            has_error = False
            xlevel = params["xlevel"]
            if params.get("expect_xlevel") is not None:
                xlevel = params.get("expect_xlevel")

            try:
                out = get_guest_cpuid(self, cpu_model, "xlevel=" +
                                      params.get("xlevel"))
                guest_xlevel = str(cpuid_to_xlevel(out))
                if guest_xlevel != xlevel:
                    raise error.TestFail("Guest's xlevel [%s], doesn't match "
                                         "required xlevel [%s]" %
                                         (guest_xlevel, xlevel))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_model_id(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.2.3 Processor Brand String (Functions 80000002h, 80000003h,
        # 80000004h)
        m_id = ""
        for idx in ('0x80000002', '0x80000003', '0x80000004'):
            regs = cpuid_regs_to_dic('%s 0x00' % idx, cpuid_dump)
            for name in ('eax', 'ebx', 'ecx', 'edx'):
                for shift in range(4):
                    c = ((regs[name] >> (shift * 8)) & 0xff)
                    if c == 0: # drop trailing \0-s
                        break
                    m_id += chr(c)
        return m_id

    class custom_model_id(MiniSubtest):
        """
        Boot qemu with specified model_id
        """
        def test(self):
            has_error = False
            model_id = params["model_id"]

            try:
                out = get_guest_cpuid(self, cpu_model, "model_id='%s'" %
                                      model_id)
                guest_model_id = cpuid_to_model_id(out)
                if guest_model_id != model_id:
                    raise error.TestFail("Guest's model_id [%s], doesn't match "
                                         "required model_id [%s]" %
                                         (guest_model_id, model_id))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_regs_to_string(cpuid_dump, leaf, idx, regs):
        r = cpuid_regs_to_dic('%s %s' % (leaf, idx), cpuid_dump)
        signature = ""
        for i in regs:
            for shift in range(0, 4):
                c = chr((r[i] >> (shift * 8)) & 0xFF)
                if c in string.printable:
                    signature = signature + c
                else:
                    signature = "%s\\x%02x" % (signature, ord(c))
        logging.debug("(%s.%s:%s: signature: %s" % (leaf, idx, str(regs),
                                                    signature))
        return signature

    class cpuid_signature(MiniSubtest):
        """
        test signature in specified leaf:index:regs
        """
        def test(self):
            has_error = False
            flags = params.get("flags","")
            leaf = params.get("leaf","0x40000000")
            idx = params.get("index","0x00")
            regs = params.get("regs","ebx ecx edx").split()
            signature = params["signature"]
            try:
                out = get_guest_cpuid(self, cpu_model, flags)
                _signature = cpuid_regs_to_string(out, leaf, idx, regs)
                if _signature != signature:
                    raise error.TestFail("Guest's signature [%s], doesn't"
                                         "match required signature [%s]" %
                                         (_signature, signature))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    class cpuid_bit_test(MiniSubtest):
        """
        test bits in specified leaf:func:reg
        """
        def test(self):
            has_error = False
            flags = params.get("flags","")
            leaf = params.get("leaf","0x40000000")
            idx = params.get("index","0x00")
            reg = params.get("reg","eax")
            bits = params["bits"].split()
            try:
                out = get_guest_cpuid(self, cpu_model, flags)
                r = cpuid_regs_to_dic('%s %s' % (leaf, idx), out)[reg]
                logging.debug("CPUID(%s.%s).%s=0x%08x" % (leaf, idx, reg, r))
                for i in bits:
                    if (r & (1 << int(i))) == 0:
                        raise error.TestFail("CPUID(%s.%s).%s[%s] is not set" %
                                             (leaf, idx, reg, i))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")

    class cpuid_reg_test(MiniSubtest):
        """
        test register value in specified leaf:index:reg
        """
        def test(self):
            has_error = False
            flags = params.get("flags","")
            leaf = params.get("leaf")
            idx = params.get("index","0x00")
            reg = params.get("reg","eax")
            val = int(params["value"])
            try:
                out = get_guest_cpuid(self, cpu_model, flags)
                r = cpuid_regs_to_dic('%s %s' % (leaf, idx), out)[reg]
                logging.debug("CPUID(%s.%s).%s=0x%08x" % (leaf, idx, reg, r))
                if r != val:
                    raise error.TestFail("CPUID(%s.%s).%s is not 0x%08x" %
                                         (leaf, idx, reg, val))
            except:
                has_error = True
                if xfail is False:
                    raise
            if (has_error is False) and (xfail is True):
                raise error.TestFail("Test was expected to fail, but it didn't")


    # subtests runner
    test_type = params["test_type"]
    failed = []
    if test_type in locals():
        tests_group = locals()[test_type]
        try:
            tests_group()
        except:
            print_exception(tests_group)
            failed.append(test_type)
    else:
        raise error.TestError("Test group '%s' is not defined in"
                              " test" % test_type)

    if failed != []:
        raise error.TestFail("Test of cpu models %s failed." %
                              (str(failed)))
Beispiel #47
0
def run(test, params, env):
    """
    Boot guest with different cpu_models and cpu flags and check if guest works correctly.

    :param test: kvm test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    qemu_binary = utils_misc.get_qemu_binary(params)

    cpu_model = params.get("cpu_model", "qemu64")

    xfail = False
    if (params.get("xfail") is not None) and (params.get("xfail") == "yes"):
        xfail = True

    def cpu_models_to_test():
        """Return the list of CPU models to be tested, based on the
        cpu_models and cpu_model config options.

        Config option "cpu_model" may be used to ask a single CPU model
        to be tested. Config option "cpu_models" may be used to ask
        multiple CPU models to be tested.

        If cpu_models is "*", all CPU models reported by QEMU will be tested.
        """
        models_opt = params.get("cpu_models")
        model_opt = params.get("cpu_model")

        if (models_opt is None and model_opt is None):
            raise error.TestError("No cpu_models or cpu_model option is set")

        cpu_models = set()

        if models_opt == '*':
            cpu_models.update(utils_misc.get_qemu_cpu_models(qemu_binary))
        elif models_opt:
            cpu_models.update(models_opt.split())

        if model_opt:
            cpu_models.add(model_opt)

        return cpu_models

    def test_qemu_cpu_models_list(self):
        """
        check CPU models returned by <qemu> -cpu '?' are what is expected
        """
        """
        test method
        """
        cpu_models = cpu_models_to_test()
        qemu_models = utils_misc.get_qemu_cpu_models(qemu_binary)
        missing = set(cpu_models) - set(qemu_models)
        if missing:
            raise error.TestFail(
                "Some CPU models not in QEMU CPU model list: %r" % (missing))
        added = set(qemu_models) - set(cpu_models)
        if added:
            logging.info("Extra CPU models in QEMU CPU listing: %s", added)

    def compare_cpuid_output(a, b):
        """
        Generates a list of (bit, va, vb) tuples for
        each bit that is different between a and b.
        """
        for bit in range(32):
            ba = (a & (1 << bit)) >> bit
            if b is not None:
                bb = (b & (1 << bit)) >> bit
            else:
                bb = None
            if ba != bb:
                yield (bit, ba, bb)

    def parse_cpuid_dump(output):
        dbg("parsing cpuid dump: %r", output)
        cpuid_re = re.compile(
            "^ *(0x[0-9a-f]+) +0x([0-9a-f]+): +eax=0x([0-9a-f]+) ebx=0x([0-9a-f]+) ecx=0x([0-9a-f]+) edx=0x([0-9a-f]+)$")
        output_match = re.search('(==START TEST==.*==END TEST==)', output, re.M | re.DOTALL)
        if output_match is None:
            dbg("cpuid dump doesn't follow expected pattern")
            return None
        output = output_match.group(1)
        out_lines = output.splitlines()
        if out_lines[0] != '==START TEST==' or out_lines[-1] != '==END TEST==':
            dbg("cpuid dump doesn't have expected delimiters")
            return None
        if out_lines[1] != 'CPU:':
            dbg("cpuid dump doesn't start with 'CPU:' line")
            return None
        result = {}
        for l in out_lines[2:-1]:
            m = cpuid_re.match(l)
            if m is None:
                dbg("invalid cpuid dump line: %r", l)
                return None
            in_eax = int(m.group(1), 16)
            in_ecx = int(m.group(2), 16)
            result[in_eax, in_ecx, 'eax'] = int(m.group(3), 16)
            result[in_eax, in_ecx, 'ebx'] = int(m.group(4), 16)
            result[in_eax, in_ecx, 'ecx'] = int(m.group(5), 16)
            result[in_eax, in_ecx, 'edx'] = int(m.group(6), 16)
        return result

    def get_test_kernel_cpuid(self, vm):
        vm.resume()

        timeout = float(params.get("login_timeout", 240))
        logging.debug("Will wait for CPUID serial output at %r",
                      vm.serial_console)
        if not utils_misc.wait_for(lambda:
                                   re.search("==END TEST==",
                                             vm.serial_console.get_output()),
                                   timeout, 1):
            raise error.TestFail("Could not get test complete message.")

        test_output = parse_cpuid_dump(vm.serial_console.get_output())
        logging.debug("Got CPUID serial output: %r", test_output)
        if test_output is None:
            raise error.TestFail("Test output signature not found in "
                                 "output:\n %s", vm.serial_console.get_output())
        vm.destroy(gracefully=False)
        return test_output

    def find_cpu_obj(vm):
        """Find path of a valid VCPU object"""
        roots = ['/machine/icc-bridge/icc', '/machine/unattached/device']
        for root in roots:
            for child in vm.monitor.cmd('qom-list', dict(path=root)):
                logging.debug('child: %r', child)
                if child['type'].rstrip('>').endswith('-cpu'):
                    return root + '/' + child['name']

    def get_qom_cpuid(self, vm):
        assert vm.monitor.protocol == "qmp"
        cpu_path = find_cpu_obj(vm)
        logging.debug('cpu path: %r', cpu_path)
        r = {}
        for prop in 'feature-words', 'filtered-features':
            words = vm.monitor.cmd('qom-get', dict(path=cpu_path, property=prop))
            logging.debug('%s property: %r', prop, words)
            for w in words:
                reg = w['cpuid-register'].lower()
                key = (w['cpuid-input-eax'], w.get('cpuid-input-ecx', 0), reg)
                r.setdefault(key, 0)
                r[key] |= w['features']
        return r

    def get_guest_cpuid(self, cpu_model, feature=None, extra_params=None, qom_mode=False):
        if not qom_mode:
            test_kernel_dir = os.path.join(data_dir.get_deps_dir(), "cpuid", "src")
            os.chdir(test_kernel_dir)
            utils.make("cpuid_dump_kernel.bin")

        vm_name = params['main_vm']
        params_b = params.copy()
        if not qom_mode:
            params_b["kernel"] = os.path.join(
                test_kernel_dir, "cpuid_dump_kernel.bin")
        params_b["cpu_model"] = cpu_model
        params_b["cpu_model_flags"] = feature
        del params_b["images"]
        del params_b["nics"]
        if extra_params:
            params_b.update(extra_params)
        env_process.preprocess_vm(self, params_b, env, vm_name)
        vm = env.get_vm(vm_name)
        dbg('is dead: %r', vm.is_dead())
        vm.create()
        self.vm = vm
        if qom_mode:
            return get_qom_cpuid(self, vm)
        else:
            return get_test_kernel_cpuid(self, vm)

    def cpuid_to_vendor(cpuid_dump, idx):
        dst = []
        map(lambda i:
            dst.append((chr(cpuid_dump[idx, 0, 'ebx'] >> (8 * i) & 0xff))),
            range(0, 4))
        map(lambda i:
            dst.append((chr(cpuid_dump[idx, 0, 'edx'] >> (8 * i) & 0xff))),
            range(0, 4))
        map(lambda i:
            dst.append((chr(cpuid_dump[idx, 0, 'ecx'] >> (8 * i) & 0xff))),
            range(0, 4))
        return ''.join(dst)

    def default_vendor(self):
        """
        Boot qemu with specified cpu models and
        verify that CPU vendor matches requested
        """
        cpu_models = cpu_models_to_test()

        vendor = params.get("vendor")
        if vendor is None or vendor == "host":
            cmd = "grep 'vendor_id' /proc/cpuinfo | head -n1 | awk '{print $3}'"
            cmd_result = utils.run(cmd, ignore_status=True)
            vendor = cmd_result.stdout.strip()

        ignore_cpus = set(params.get("ignore_cpu_models", "").split(' '))
        cpu_models = cpu_models - ignore_cpus

        for cpu_model in cpu_models:
            out = get_guest_cpuid(self, cpu_model)
            guest_vendor = cpuid_to_vendor(out, 0x00000000)
            logging.debug("Guest's vendor: " + guest_vendor)
            if guest_vendor != vendor:
                raise error.TestFail("Guest vendor [%s], doesn't match "
                                     "required vendor [%s] for CPU [%s]" %
                                     (guest_vendor, vendor, cpu_model))

    def custom_vendor(self):
        """
        Boot qemu with specified vendor
        """
        has_error = False
        vendor = params["vendor"]

        try:
            out = get_guest_cpuid(self, cpu_model, "vendor=" + vendor)
            guest_vendor0 = cpuid_to_vendor(out, 0x00000000)
            guest_vendor80000000 = cpuid_to_vendor(out, 0x80000000)
            logging.debug("Guest's vendor[0]: " + guest_vendor0)
            logging.debug("Guest's vendor[0x80000000]: " +
                          guest_vendor80000000)
            if guest_vendor0 != vendor:
                raise error.TestFail("Guest vendor[0] [%s], doesn't match "
                                     "required vendor [%s] for CPU [%s]" %
                                     (guest_vendor0, vendor, cpu_model))
            if guest_vendor80000000 != vendor:
                raise error.TestFail("Guest vendor[0x80000000] [%s], "
                                     "doesn't match required vendor "
                                     "[%s] for CPU [%s]" %
                                     (guest_vendor80000000, vendor,
                                      cpu_model))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_level(cpuid_dump):
        r = cpuid_dump[0, 0]
        return r['eax']

    def custom_level(self):
        """
        Boot qemu with specified level
        """
        has_error = False
        level = params["level"]
        try:
            out = get_guest_cpuid(self, cpu_model, "level=" + level)
            guest_level = str(cpuid_to_level(out))
            if guest_level != level:
                raise error.TestFail("Guest's level [%s], doesn't match "
                                     "required level [%s]" %
                                     (guest_level, level))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_family(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_dump[1, 0]['eax']
        family = (eax >> 8) & 0xf
        if family == 0xf:
            # extract extendend family
            return family + ((eax >> 20) & 0xff)
        return family

    def custom_family(self):
        """
        Boot qemu with specified family
        """
        has_error = False
        family = params["family"]
        try:
            out = get_guest_cpuid(self, cpu_model, "family=" + family)
            guest_family = str(cpuid_to_family(out))
            if guest_family != family:
                raise error.TestFail("Guest's family [%s], doesn't match "
                                     "required family [%s]" %
                                     (guest_family, family))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_model(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_dump[1, 0]['eax']
        model = (eax >> 4) & 0xf
        # extended model
        model |= (eax >> 12) & 0xf0
        return model

    def custom_model(self):
        """
        Boot qemu with specified model
        """
        has_error = False
        model = params["model"]
        try:
            out = get_guest_cpuid(self, cpu_model, "model=" + model)
            guest_model = str(cpuid_to_model(out))
            if guest_model != model:
                raise error.TestFail("Guest's model [%s], doesn't match "
                                     "required model [%s]" %
                                     (guest_model, model))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_stepping(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.1.2 Feature Information (Function 01h)
        eax = cpuid_dump[1, 0]['eax']
        stepping = eax & 0xf
        return stepping

    def custom_stepping(self):
        """
        Boot qemu with specified stepping
        """
        has_error = False
        stepping = params["stepping"]
        try:
            out = get_guest_cpuid(self, cpu_model, "stepping=" + stepping)
            guest_stepping = str(cpuid_to_stepping(out))
            if guest_stepping != stepping:
                raise error.TestFail("Guest's stepping [%s], doesn't match "
                                     "required stepping [%s]" %
                                     (guest_stepping, stepping))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_xlevel(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.2.1 Largest Extendend Function # (Function 80000000h)
        return cpuid_dump[0x80000000, 0x00]['eax']

    def custom_xlevel(self):
        """
        Boot qemu with specified xlevel
        """
        has_error = False
        xlevel = params["xlevel"]
        if params.get("expect_xlevel") is not None:
            xlevel = params.get("expect_xlevel")

        try:
            out = get_guest_cpuid(self, cpu_model, "xlevel=" +
                                  params.get("xlevel"))
            guest_xlevel = str(cpuid_to_xlevel(out))
            if guest_xlevel != xlevel:
                raise error.TestFail("Guest's xlevel [%s], doesn't match "
                                     "required xlevel [%s]" %
                                     (guest_xlevel, xlevel))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_to_model_id(cpuid_dump):
        # Intel Processor Identification and the CPUID Instruction
        # http://www.intel.com/Assets/PDF/appnote/241618.pdf
        # 5.2.3 Processor Brand String (Functions 80000002h, 80000003h,
        # 80000004h)
        m_id = ""
        for idx in (0x80000002, 0x80000003, 0x80000004):
            regs = cpuid_dump[idx, 0]
            for name in ('eax', 'ebx', 'ecx', 'edx'):
                for shift in range(4):
                    c = ((regs[name] >> (shift * 8)) & 0xff)
                    if c == 0:  # drop trailing \0-s
                        break
                    m_id += chr(c)
        return m_id

    def custom_model_id(self):
        """
        Boot qemu with specified model_id
        """
        has_error = False
        model_id = params["model_id"]

        try:
            out = get_guest_cpuid(self, cpu_model, "model_id='%s'" %
                                  model_id)
            guest_model_id = cpuid_to_model_id(out)
            if guest_model_id != model_id:
                raise error.TestFail("Guest's model_id [%s], doesn't match "
                                     "required model_id [%s]" %
                                     (guest_model_id, model_id))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_regs_to_string(cpuid_dump, leaf, idx, regs):
        r = cpuid_dump[leaf, idx]
        signature = ""
        for i in regs:
            for shift in range(0, 4):
                c = chr((r[i] >> (shift * 8)) & 0xFF)
                if c in string.printable:
                    signature = signature + c
                else:
                    signature = "%s\\x%02x" % (signature, ord(c))
        logging.debug("(%s.%s:%s: signature: %s" % (leaf, idx, str(regs),
                                                    signature))
        return signature

    def cpuid_signature(self):
        """
        test signature in specified leaf:index:regs
        """
        has_error = False
        flags = params.get("flags", "")
        leaf = int(params.get("leaf", "0x40000000"), 0)
        idx = int(params.get("index", "0x00"), 0)
        regs = params.get("regs", "ebx ecx edx").split()
        signature = params["signature"]
        try:
            out = get_guest_cpuid(self, cpu_model, flags)
            _signature = cpuid_regs_to_string(out, leaf, idx, regs)
            if _signature != signature:
                raise error.TestFail("Guest's signature [%s], doesn't"
                                     "match required signature [%s]" %
                                     (_signature, signature))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_bit_test(self):
        """
        test bits in specified leaf:func:reg
        """
        has_error = False
        flags = params.get("flags", "")
        leaf = int(params.get("leaf", "0x40000000"), 0)
        idx = int(params.get("index", "0x00"), 0)
        reg = params.get("reg", "eax")
        bits = params["bits"].split()
        try:
            out = get_guest_cpuid(self, cpu_model, flags)
            r = out[leaf, idx][reg]
            logging.debug("CPUID(%s.%s).%s=0x%08x" % (leaf, idx, reg, r))
            for i in bits:
                if (r & (1 << int(i))) == 0:
                    raise error.TestFail("CPUID(%s.%s).%s[%s] is not set" %
                                         (leaf, idx, reg, i))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def cpuid_reg_test(self):
        """
        test register value in specified leaf:index:reg
        """
        has_error = False
        flags = params.get("flags", "")
        leaf = int(params.get("leaf", "0x00"), 0)
        idx = int(params.get("index", "0x00"), 0)
        reg = params.get("reg", "eax")
        val = int(params["value"], 0)
        try:
            out = get_guest_cpuid(self, cpu_model, flags)
            r = out[leaf, idx][reg]
            logging.debug("CPUID(%s.%s).%s=0x%08x" % (leaf, idx, reg, r))
            if r != val:
                raise error.TestFail("CPUID(%s.%s).%s is not 0x%08x" %
                                     (leaf, idx, reg, val))
        except:
            has_error = True
            if xfail is False:
                raise
        if (has_error is False) and (xfail is True):
            raise error.TestFail("Test was expected to fail, but it didn't")

    def check_cpuid_dump(self):
        """
        Compare full CPUID dump data
        """
        machine_type = params.get("machine_type_to_check", "")
        kvm_enabled = params.get("enable_kvm", "yes") == "yes"

        ignore_cpuid_leaves = params.get("ignore_cpuid_leaves", "")
        ignore_cpuid_leaves = ignore_cpuid_leaves.split()
        whitelist = []
        for leaf in ignore_cpuid_leaves:
            leaf = leaf.split(',')
            # syntax of ignore_cpuid_leaves:
            # <in_eax>[,<in_ecx>[,<register>[ ,<bit>]]] ...
            for i in 0, 1, 3:  # integer fields:
                if len(leaf) > i:
                    leaf[i] = int(leaf[i], 0)
            whitelist.append(tuple(leaf))

        if not machine_type:
            raise error.TestNAError("No machine_type_to_check defined")
        cpu_model_flags = params.get('cpu_model_flags', '')
        full_cpu_model_name = cpu_model
        if cpu_model_flags:
            full_cpu_model_name += ','
            full_cpu_model_name += cpu_model_flags.lstrip(',')
        ref_file = os.path.join(data_dir.get_deps_dir(), 'cpuid',
                                "cpuid_dumps",
                                kvm_enabled and "kvm" or "nokvm",
                                machine_type, '%s-dump.txt' % (full_cpu_model_name))
        if not os.path.exists(ref_file):
            raise error.TestNAError("no cpuid dump file: %s" % (ref_file))
        reference = open(ref_file, 'r').read()
        if not reference:
            raise error.TestNAError(
                "no cpuid dump data on file: %s" % (ref_file))
        reference = parse_cpuid_dump(reference)
        if reference is None:
            raise error.TestNAError(
                "couldn't parse reference cpuid dump from file; %s" % (ref_file))
        qom_mode = params.get('qom_mode', "no").lower() == 'yes'
        if not qom_mode:
            cpu_model_flags += ',enforce'
        try:

            out = get_guest_cpuid(
                self, cpu_model, cpu_model_flags,
                extra_params=dict(machine_type=machine_type, smp=1),
                qom_mode=qom_mode)
        except (virt_vm.VMStartError, virt_vm.VMCreateError) as e:
            output = getattr(e, 'reason', getattr(e, 'output', ''))
            if "host doesn't support requested feature:" in output \
                or ("host cpuid" in output and
                    ("lacks requested flag" in output or
                     "flag restricted to guest" in output)) \
                    or ("Unable to find CPU definition:" in output):
                raise error.TestNAError(
                    "Can't run CPU model %s on this host" % (full_cpu_model_name))
            else:
                raise
        dbg('ref_file: %r', ref_file)
        dbg('ref: %r', reference)
        dbg('out: %r', out)
        ok = True
        for k in reference.keys():
            in_eax, in_ecx, reg = k
            diffs = compare_cpuid_output(reference[k], out.get(k))
            for d in diffs:
                bit, vreference, vout = d
                whitelisted = (in_eax,) in whitelist \
                    or (in_eax, in_ecx) in whitelist \
                    or (in_eax, in_ecx, reg) in whitelist \
                    or (in_eax, in_ecx, reg, bit) in whitelist
                silent = False

                if vout is None and params.get('ok_missing', 'no') == 'yes':
                    whitelisted = True
                    silent = True

                if not silent:
                    info(
                        "Non-matching bit: CPUID[0x%x,0x%x].%s[%d]: found %s instead of %s%s",
                        in_eax, in_ecx, reg, bit, vout, vreference,
                        whitelisted and " (whitelisted)" or "")

                if not whitelisted:
                    ok = False
        if not ok:
            raise error.TestFail("Unexpected CPUID data")

    # subtests runner
    test_type = params["test_type"]
    if test_type not in locals():
        raise error.TestError("Test function '%s' is not defined in"
                              " test" % test_type)

    test_func = locals()[test_type]
    return test_func(test)
Beispiel #48
0
def run(test, params, env):
    """
    slof_device_tree test:
    steps:
    1. Boot up a guest.
    2. Check the guest device tree information
    3. Compare the value with expected result.
    :param test: Kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """

    def get_info(vm_session, guest_info):
        """
        Check the corresponding information from vm.

        :param vm_session: session to checked vm.
        :return: corresponding prompt
        """
        (status, output) = vm_session.cmd_status_output("echo `cat /proc/device-tree/%s`" % guest_info)
        if status != 0:
            raise exceptions.TestFail("Failed to get %s" % guest_info)
        return output.strip()

    def check_nonexist_aliases(vm_session, devices):
        """
        Check a nonexist device aliases.

        :param vm_session: session to checked vm.
        :return: corresponding prompt
        """

        status = vm_session.cmd_status("test -f /proc/device-tree/aliases/cdrom")
        error_context.context("Checking whether aliases file is indeed nonexisting", logging.info)
        if status == 0:
            raise exceptions.TestFail("Nonexist cdrom aliases check failed.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 600))

    session = vm.wait_for_login(timeout=timeout)

    try:
        guest_system_id = get_info(session, "system-id")
        if guest_system_id != vm.get_uuid():
            raise exceptions.TestFail("Guest system id does not match to uuid")

        guest_uuid = get_info(session, "vm,uuid")
        if guest_uuid != vm.get_uuid():
            raise exceptions.TestFail("Guest uuid does not match to expected id.")

        host_system_id = process.system_output("echo `cat /proc/device-tree/system-id`", shell=True).strip()
        host_system_id_in_guest = get_info(session, "host-serial")
        if host_system_id != host_system_id_in_guest:
            raise exceptions.TestFail("Host system id does not match to value in guest.")

        guest_partition_name = get_info(session, "ibm,partition-name")
        if guest_partition_name != params.get("main_vm"):
            raise exceptions.TestFail("Guest partition name is wrong.")

        qemu_binary = utils_misc.get_qemu_binary(params)
        devices = qcontainer.DevContainer(qemu_binary, vm, strict_mode="no")
        check_nonexist_aliases(session, devices)

    finally:
        session.close()
def run(test, params, env):
    """
    Test qmp event notification function:
    1) Boot up guest with qmp and macvtap.
    2) In guest, change network interface to promisc state.
    3) Try to catch qmp event notification in qmp monitor.
    4) Execute query-rx-filter in host qmp session.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        error.TestNAError("This test case requires a host QEMU with QMP "
                          "monitor support")
    if params.get("nettype", "macvtap") != "macvtap":
        error.TestNAError("This test case test macvtap.")

    params["start_vm"] = "yes"
    vm_name = params.get("main_vm", "vm1")
    env_process.preprocess_vm(test, params, env, vm_name)

    vm = env.get_vm(vm_name)
    vm.verify_alive()

    event_cmd = params.get("event_cmd")
    event_cmd_type = params.get("event_cmd_type")
    event_check = params.get("event_check")
    timeout = int(params.get("check_timeout", 360))
    pre_cmd = params.get("pre_cmd")
    post_cmd = params.get("post_cmd")
    post_cmd_type = params.get("post_cmd_type")

    session = vm.wait_for_serial_login(timeout=int(params.get("login_timeout",
                                                              360)))

    callback = {"host_cmd": utils.system_output,
                "guest_cmd": session.get_command_output,
                "qmp_cmd": vm.get_monitors_by_type("qmp")[0].send_args_cmd}

    def send_cmd(cmd, cmd_type):
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            raise error.TestError("cmd_type is not supported")

    if pre_cmd:
        error.context("Run pre_cmd '%s'", logging.info)
        pre_cmd_type = params.get("pre_cmd_type", event_cmd_type)
        send_cmd(pre_cmd, pre_cmd_type)

    mac = vm.get_mac_address()
    interface_name = utils_net.get_linux_ifname(session, mac)

    error.context("In guest, change network interface to promisc state.",
                  logging.info)
    event_cmd = params.get("event_cmd") % interface_name
    send_cmd(event_cmd, event_cmd_type)

    error.context("Try to get qmp events in %s seconds!" % timeout,
                  logging.info)
    end_time = time.time() + timeout
    qmp_monitors = vm.get_monitors_by_type("qmp")
    qmp_num = len(qmp_monitors)
    while time.time() < end_time:
        for monitor in qmp_monitors:
            event = monitor.get_event(event_check)
            if event:
                txt = "Monitr %s " % monitor.name
                txt += "receive qmp %s event notification" % event_check
                logging.info(txt)
                qmp_num -= 1
                qmp_monitors.remove(monitor)
        time.sleep(5)
        if qmp_num <= 0:
            break
    if qmp_num > 0:
        output = session.cmd("ip link show")
        err = "Monitor(s) "
        for monitor in qmp_monitors:
            err += "%s " % monitor.name
        err += " did not receive qmp %s event notification." % event_check
        err += " ip link show command output in guest: %s" % output
        raise error.TestFail(err)

    if post_cmd:
        for nic in vm.virtnet:
            post_cmd = post_cmd % nic.device_id
            error.context("Run post_cmd '%s'" % post_cmd, logging.info)
            post_cmd_type = params.get("post_cmd_type", event_cmd_type)
            output = send_cmd(post_cmd, post_cmd_type)
            post_cmd_check = params.get("post_cmd_check")
            if post_cmd_check:
                if post_cmd_check not in str(output):
                    err = "Did not find '%s' in " % post_cmd_check
                    err += "'%s' command's output: %s" % (post_cmd, output)
                    raise error.TestFail(err)

    if session:
        session.close()
Beispiel #50
0
def run_qmp_command(test, params, env):
    """
    Test qmp event notification, this case will:
    1) Start VM with qmp enable.
    2) Connect to qmp port then run qmp_capabilities command.
    3) Initiate the qmp command defined in config (qmp_cmd)
    4) Verify that qmp command works as designed.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """
    def check_result(qmp_o, output=None):
        """
        Check test result with difference way accoriding to
        result_check.
        result_check = equal, will compare cmd_return_value with qmp
                       command output.
        result_check = contain, will try to find cmd_return_value in qmp
                       command output.
        result_check = m_equal_q, will compare key value in monitor command
                       output and qmp command output.
        result_check = m_in_q, will try to find monitor command output's key
                       value in qmp command output.
        result_check = m_format_q, will try to match the output's format with
                       check pattern.

        :param qmp_o: output from pre_cmd, qmp_cmd or post_cmd.
        :param o: output from pre_cmd, qmp_cmd or post_cmd or an execpt
        result set in config file.
        """
        if result_check == "equal":
            value = output
            if value != str(qmp_o):
                raise error.TestFail("QMP command return value does not match "
                                     "the expect result. Expect result: '%s'\n"
                                     "Actual result: '%s'" % (value, qmp_o))
        elif result_check == "contain":
            values = output.split(';')
            for value in values:
                if value.strip() not in str(qmp_o):
                    raise error.TestFail("QMP command output does not contain "
                                         "expect result. Expect result: '%s'\n"
                                         "Actual result: '%s'"
                                         % (value, qmp_o))
        elif result_check == "not_contain":
            values = output.split(';')
            for value in values:
                if value in str(qmp_o):
                    raise error.TestFail("QMP command output contains unexpect"
                                         " result. Unexpect result: '%s'\n"
                                         "Actual result: '%s'"
                                         % (value, qmp_o))
        elif result_check == "m_equal_q":
            msg = "QMP command ouput is not equal to in human monitor command."
            msg += "\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman command output: '%s'" % output
            res = output.splitlines(True)
            if type(qmp_o) != type(res):
                len_o = 1
            else:
                len_o = len(qmp_o)
            if len(res) != len_o:
                raise error.TestFail(msg)
            re_str = r'([^ \t\n\r\f\v=]*)=([^ \t\n\r\f\v=]*)'
            for i in range(len(res)):
                if qmp_cmd == "query-version":
                    version = qmp_o['qemu']
                    version = "%s.%s.%s" % (version['major'], version['minor'],
                                            version['micro'])
                    package = qmp_o['package']
                    re_str = r"([0-9]+\.[0-9]+\.[0-9]+)\s*(\(\S*\))?"
                    hmp_version, hmp_package = re.findall(re_str, res[i])[0]
                    if not hmp_package:
                        hmp_package = package
                    if version != hmp_version or package != hmp_package:
                        raise error.TestFail(msg)
                else:
                    matches = re.findall(re_str, res[i])
                    for key, val in matches:
                        if '0x' in val:
                            val = long(val, 16)
                            if val != qmp_o[i][key]:
                                msg += "\nValue in human monitor: '%s'" % val
                                msg += "\nValue in qmp: '%s'" % qmp_o[i][key]
                                raise error.TestFail(msg)
                        elif qmp_cmd == "query-block":
                            cmp_str = "u'%s': u'%s'" % (key, val)
                            cmp_s = "u'%s': %s" % (key, val)
                            if '0' == val:
                                cmp_str_b = "u'%s': False" % key
                            elif '1' == val:
                                cmp_str_b = "u'%s': True" % key
                            else:
                                cmp_str_b = cmp_str
                            if (cmp_str not in str(qmp_o[i]) and
                               cmp_str_b not in str(qmp_o[i]) and
                               cmp_s not in str(qmp_o[i])):
                                msg += ("\nCan not find '%s', '%s' or '%s' in "
                                        " QMP command output."
                                        % (cmp_s, cmp_str_b, cmp_str))
                                raise error.TestFail(msg)
                        elif qmp_cmd == "query-balloon":
                            if (int(val) * 1024 * 1024 != qmp_o[key] and
                               val not in str(qmp_o[key])):
                                msg += ("\n'%s' is not in QMP command output"
                                        % val)
                                raise error.TestFail(msg)
                        else:
                            if (val not in str(qmp_o[i][key]) and
                               str(bool(int(val))) not in str(qmp_o[i][key])):
                                msg += ("\n'%s' is not in QMP command output"
                                        % val)
                                raise error.TestFail(msg)
        elif result_check == "m_in_q":
            res = output.splitlines(True)
            msg = "Key value from human monitor command is not in"
            msg += "QMP command output.\nQMP command output: '%s'" % qmp_o
            msg += "\nHuman monitor command output '%s'" % output
            for i in range(len(res)):
                params = res[i].rstrip().split()
                for param in params:
                    try:
                        str_o = str(qmp_o.values())
                    except AttributeError:
                        str_o = qmp_o
                    if param.rstrip() not in str(str_o):
                        msg += "\nKey value is '%s'" % param.rstrip()
                        raise error.TestFail(msg)
        elif result_check == "m_format_q":
            match_flag = True
            for i in qmp_o:
                if output is None:
                    raise error.TestError("QMP output pattern is missing")
                if re.match(output.strip(), str(i)) is None:
                    match_flag = False
            if not match_flag:
                msg = "Output does not match the pattern: '%s'" % output
                raise error.TestFail(msg)

    def qmp_cpu_check(output):
        """ qmp_cpu test check """
        last_cpu = int(params['smp']) - 1
        for out in output:
            cpu = out.get('CPU')
            if cpu is None:
                raise error.TestFail("'CPU' index is missing in QMP output "
                                     "'%s'" % out)
            else:
                current = out.get('current')
                if current is None:
                    raise error.TestFail("'current' key is missing in QMP "
                                         "output '%s'" % out)
                elif cpu < last_cpu:
                    if current is False:
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
                                             "'False', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
                elif cpu == last_cpu:
                    if current is True:
                        pass
                    else:
                        raise error.TestFail("Attribute 'current' should be "
                                             "'True', but is '%s' instead.\n"
                                             "'%s'" % (current, out))
                elif cpu <= last_cpu:
                    continue
                else:
                    raise error.TestFail("Incorrect CPU index '%s' (corrupted "
                                         "or higher than no_cpus).\n%s"
                                         % (cpu, out))

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        raise error.TestNAError("Host qemu does not support qmp.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))

    module = params.get("modprobe_module")
    if module:
        error.context("modprobe the module %s" % module, logging.info)
        session.cmd("modprobe %s" % module)

    qmp_ports = vm.get_monitors_by_type('qmp')
    if qmp_ports:
        qmp_port = qmp_ports[0]
    else:
        raise error.TestError("Incorrect configuration, no QMP monitor found.")
    hmp_ports = vm.get_monitors_by_type('human')
    if hmp_ports:
        hmp_port = hmp_ports[0]
    else:
        raise error.TestError("Incorrect configuration, no QMP monitor found.")
    callback = {"host_cmd": utils.system_output,
                "guest_cmd": session.get_command_output,
                "monitor_cmd": hmp_port.send_args_cmd,
                "qmp_cmd": qmp_port.send_args_cmd}

    def send_cmd(cmd):
        """ Helper to execute command on ssh/host/monitor """
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd)
        else:
            raise error.TestError("cmd_type is not supported")

    pre_cmd = params.get("pre_cmd")
    qmp_cmd = params.get("qmp_cmd")
    cmd_type = params.get("event_cmd_type")
    post_cmd = params.get("post_cmd")
    result_check = params.get("cmd_result_check")
    cmd_return_value = params.get("cmd_return_value")

    # HOOKs
    if result_check == 'qmp_cpu':
        pre_cmd = "cpu index=%d" % (int(params['smp']) - 1)

    # Pre command
    if pre_cmd is not None:
        error.context("Run prepare command '%s'." % pre_cmd, logging.info)
        pre_o = send_cmd(pre_cmd)
        logging.debug("Pre-command: '%s'\n Output: '%s'", pre_cmd, pre_o)
    try:
        # Testing command
        error.context("Run qmp command '%s'." % qmp_cmd, logging.info)
        output = qmp_port.send_args_cmd(qmp_cmd)
        logging.debug("QMP command: '%s' \n Output: '%s'", qmp_cmd, output)
    except qemu_monitor.QMPCmdError, err:
        if params.get("negative_test") == 'yes':
            logging.debug("Negative QMP command: '%s'\n output:'%s'", qmp_cmd,
                          err)
            if params.get("negative_check_pattern"):
                check_pattern = params.get("negative_check_pattern")
                if check_pattern not in str(err):
                    raise error.TestFail("'%s' not in exception '%s'"
                                         % (check_pattern, err))
        else:
            raise error.TestFail(err)
Beispiel #51
0
def run(test, params, env):
    """
    Test hotplug of PCI devices and check the status in guest.
    1 Boot up a guest
    2 Hotplug virtio disk to the guest. Record the id and partition name of
      the disk in a list.
    3 Random choice a disk in the list. Unplug the disk and check the
      partition status.
    4 Hotpulg the disk back to guest with the same monitor cmdline and same
      id which is record in step 2.
    5 Check the partition status in guest. And confirm the disk with dd cmd
    6 Repeat step 3 to 5 for N times

    :param test:   KVM test object.
    :param params: Dictionary with the test parameters.
    :param env:    Dictionary with test environment.
    """
    def prepare_image_params(params):
        pci_num = int(params['pci_num'])
        for i in xrange(pci_num):
            image_name = '%s_%s' % ('stg', i)
            params['images'] = ' '.join([params['images'], image_name])
            image_image_name = '%s_%s' % ('image_name', image_name)
            params[image_image_name] = '%s_%s' % ('storage', i)
            image_image_format = '%s_%s' % ('image_format', image_name)
            params[image_image_format] = params.get('image_format_extra',
                                                    'qcow2')
            image_image_size = '%s_%s' % ('image_size', image_name)
            params[image_image_size] = params.get('image_size_extra', '128K')
        return params

    def find_new_device(check_cmd, device_string, chk_timeout=5.0):
        end_time = time.time() + chk_timeout
        idx = ("wmic" in check_cmd and [0] or [-1])[0]
        while time.time() < end_time:
            new_line = session.cmd_output(check_cmd)
            for line in re.split("\n+", new_line.strip()):
                dev_name = re.split("\s+", line.strip())[idx]
                if dev_name not in device_string:
                    return dev_name
            time.sleep(0.1)
        return None

    def find_del_device(check_cmd, device_string, chk_timeout=5.0):
        end_time = time.time() + chk_timeout
        idx = ("wmic" in check_cmd and [0] or [-1])[0]
        while time.time() < end_time:
            new_line = session.cmd_output(check_cmd)
            for line in re.split("\n+", device_string.strip()):
                dev_name = re.split("\s+", line.strip())[idx]
                if dev_name not in new_line:
                    return dev_name
            time.sleep(0.1)
        return None

    # Select an image file
    def find_image(pci_num):
        image_params = params.object_params("%s" % img_list[pci_num + 1])
        o = storage.get_image_filename(image_params, data_dir.get_data_dir())
        return o

    def pci_add_block(pci_num, queues, pci_id):
        image_filename = find_image(pci_num)
        pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
                       (image_filename, pci_model))
        return pci_add(pci_add_cmd)

    def pci_add(pci_add_cmd):
        guest_devices = session.cmd_output(chk_cmd)
        error.context("Adding pci device with command 'pci_add'")
        add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        guest_device = find_new_device(chk_cmd, guest_devices)
        pci_info.append(['', '', add_output, pci_model, guest_device])
        if "OK domain" not in add_output:
            raise error.TestFail("Add PCI device failed. "
                                 "Monitor command is: %s, Output: %r" %
                                 (pci_add_cmd, add_output))
        return vm.monitor.info("pci")

    def is_supported_device(dev):
        # Probe qemu to verify what is the supported syntax for PCI hotplug
        cmd_output = vm.monitor.human_monitor_cmd("?")
        if len(re.findall("\ndevice_add", cmd_output)) > 0:
            cmd_type = "device_add"
        elif len(re.findall("\npci_add", cmd_output)) > 0:
            cmd_type = "pci_add"
        else:
            raise error.TestError("Unknown version of qemu")

        # Probe qemu for a list of supported devices
        probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type)
        devices_supported = [
            j.strip('"') for j in re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"',
                                             probe_output, re.MULTILINE)
        ]
        logging.debug(
            "QEMU reported the following supported devices for "
            "PCI hotplug: %s", devices_supported)
        return (dev in devices_supported)

    def verify_supported_device(dev):
        if not is_supported_device(dev):
            raise error.TestError("%s doesn't support device: %s" %
                                  (cmd_type, dev))

    def device_add_block(pci_num, queues=1, pci_id=None):
        if pci_id is not None:
            device_id = pci_type + "-" + pci_id
        else:
            device_id = pci_type + "-" + utils_misc.generate_random_id()
            pci_info.append([device_id, device_id])

        image_format = params.get("image_format_%s" % img_list[pci_num + 1])
        if not image_format:
            image_format = params.get("image_format", "qcow2")
        image_filename = find_image(pci_num)

        pci_model = params.get("pci_model")
        controller_model = None
        if pci_model == "virtio":
            pci_model = "virtio-blk-pci"

        if pci_model == "scsi":
            pci_model = "scsi-disk"
            if arch.ARCH in ('ppc64', 'ppc64le'):
                controller_model = "spapr-vscsi"
            else:
                controller_model = "lsi53c895a"
            verify_supported_device(controller_model)
            controller_id = "controller-" + device_id
            controller_add_cmd = ("device_add %s,id=%s" %
                                  (controller_model, controller_id))
            error.context("Adding SCSI controller.")
            vm.monitor.send_args_cmd(controller_add_cmd)

        verify_supported_device(pci_model)
        if drive_cmd_type == "drive_add":
            driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        elif drive_cmd_type == "__com.redhat_drive_add":
            driver_add_cmd = ("%s file=%s,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        # add driver.
        error.context("Adding driver.")
        vm.monitor.send_args_cmd(driver_add_cmd, convert=False)

        pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" %
                       (pci_info[pci_num][1], pci_model, pci_info[pci_num][0]))
        return device_add(pci_num, pci_add_cmd, pci_id=pci_id)

    def device_add(pci_num, pci_add_cmd, pci_id=None):
        error.context("Adding pci device with command 'device_add'")
        guest_devices = session.cmd_output(chk_cmd)
        if vm.monitor.protocol == 'qmp':
            add_output = vm.monitor.send_args_cmd(pci_add_cmd)
        else:
            add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        guest_device = find_new_device(chk_cmd, guest_devices)
        if pci_id is None:
            pci_info[pci_num].append(add_output)
            pci_info[pci_num].append(pci_model)
            pci_info[pci_num].append(guest_device)

        after_add = vm.monitor.info("pci")
        if pci_info[pci_num][1] not in str(after_add):
            logging.error("Could not find matched id in monitor:"
                          " %s" % pci_info[pci_num][1])
            raise error.TestFail("Add device failed. Monitor command is: %s"
                                 ". Output: %r" % (pci_add_cmd, add_output))
        return after_add

    # Hot add a pci device
    def add_device(pci_num, queues=1, pci_id=None):
        info_pci_ref = vm.monitor.info("pci")
        reference = session.cmd_output(reference_cmd)

        try:
            # get function for adding device.
            add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)]
        except Exception:
            raise error.TestError("No function for adding " +
                                  "'%s' dev " % pci_type +
                                  "with '%s'" % cmd_type)
        after_add = None
        if add_fuction:
            # Do add pci device.
            after_add = add_fuction(pci_num, queues, pci_id)

        try:
            # Define a helper function to compare the output
            def _new_shown():
                o = session.cmd_output(reference_cmd)
                return o != reference

            # Define a helper function to catch PCI device string
            def _find_pci():
                output = session.cmd_output(params.get("find_pci_cmd"))
                output = map(string.strip, output.splitlines())
                ref = map(string.strip, reference.splitlines())
                output = [_ for _ in output if _ not in ref]
                output = "\n".join(output)
                if re.search(params.get("match_string"), output, re.I):
                    return True
                return False

            error.context("Start checking new added device")
            # Compare the output of 'info pci'
            if after_add == info_pci_ref:
                raise error.TestFail("No new PCI device shown after "
                                     "executing monitor command: 'info pci'")

            secs = int(params.get("wait_secs_for_hook_up"))
            if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3):
                raise error.TestFail("No new device shown in output of" +
                                     "command executed inside the " +
                                     "guest: %s" % reference_cmd)

            if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3):
                raise error.TestFail("PCI %s %s " % (pci_model, pci_type) +
                                     "device not found in guest. Command " +
                                     "was: %s" % params.get("find_pci_cmd"))

            # Test the newly added device
            try:
                session.cmd(params.get("pci_test_cmd") % (pci_num + 1))
            except aexpect.ShellError, e:
                raise error.TestFail("Check for %s device failed" % pci_type +
                                     "after PCI hotplug." +
                                     "Output: %r" % e.output)

        except Exception:
            pci_del(pci_num, ignore_failure=True)
            raise

    # Hot delete a pci device
    def pci_del(pci_num, ignore_failure=False):
        def _device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != before_del

        before_del = vm.monitor.info("pci")
        if cmd_type == "pci_add":
            slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1])
            cmd = "pci_del pci_addr=%s" % hex(slot_id)
            vm.monitor.send_args_cmd(cmd, convert=False)
        elif cmd_type == "device_add":
            cmd = "device_del id=%s" % pci_info[pci_num][1]
            vm.monitor.send_args_cmd(cmd)

        if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1)
                and not ignore_failure):
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" %
                                 (pci_info[pci_num][3], cmd))

    params = prepare_image_params(params)
    env_process.process_images(env_process.preprocess_image, test, params)
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=timeout)

    test_timeout = int(params.get("hotplug_timeout", 360))
    reference_cmd = params["reference_cmd"]
    # Test if it is nic or block
    pci_type = params["pci_type"]
    pci_model = params["pci_model"]

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
        session.cmd("modprobe %s" % module)

    # check monitor type
    qemu_binary = utils_misc.get_qemu_binary(params)
    # Probe qemu to verify what is the supported syntax for PCI hotplug
    if vm.monitor.protocol == 'qmp':
        cmd_output = vm.monitor.info("commands")
    else:
        cmd_output = vm.monitor.human_monitor_cmd("help", debug=False)

    cmd_type = utils_misc.find_substring(str(cmd_output), "device_add",
                                         "pci_add")
    if not cmd_type:
        raise error.TestError("Could find a suitable method for hotplugging"
                              " device in this version of qemu")

    # Determine syntax of drive hotplug
    # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6
    # drive_add == qemu-kvm-0.13 onwards
    drive_cmd_type = utils_misc.find_substring(str(cmd_output),
                                               "__com.redhat_drive_add",
                                               "drive_add")
    if not drive_cmd_type:
        raise error.TestError("Unknown version of qemu")

    local_functions = locals()

    pci_num_range = int(params.get("pci_num"))
    rp_times = int(params.get("repeat_times"))
    img_list = params.get("images").split()
    chk_cmd = params.get("guest_check_cmd")
    mark_cmd = params.get("mark_cmd")
    offset = params.get("offset")
    confirm_cmd = params.get("confirm_cmd")

    pci_info = []
    # Add block device into guest
    for pci_num in xrange(pci_num_range):
        error.context("Prepare the %d removable pci device" % pci_num,
                      logging.info)
        add_device(pci_num)
        if pci_info[pci_num][4] is not None:
            partition = pci_info[pci_num][4]
            cmd = mark_cmd % (partition, partition, offset)
            session.cmd(cmd)
        else:
            raise error.TestError("Device not init in guest")

    for j in range(rp_times):
        # pci_info is a list of list.
        # each element 'i' has 4 members:
        # pci_info[i][0] == device drive id, only used for device_add
        # pci_info[i][1] == device id, only used for device_add
        # pci_info[i][2] == output of device add command
        # pci_info[i][3] == device module name.
        # pci_info[i][4] == partition id in guest
        pci_num = random.randint(0, len(pci_info) - 1)
        error.context("start unplug pci device, repeat %d" % j, logging.info)
        guest_devices = session.cmd_output(chk_cmd)
        pci_del(pci_num)
        device_del = find_del_device(chk_cmd, guest_devices)
        if device_del != pci_info[pci_num][4]:
            raise error.TestFail("Device is not deleted in guest.")
        error.context("Start plug pci device, repeat %d" % j, logging.info)
        guest_devices = session.cmd_output(chk_cmd)
        add_device(pci_num, pci_id=pci_info[pci_num][0])
        device_del = find_new_device(chk_cmd, guest_devices)
        if device_del != pci_info[pci_num][4]:
            raise error.TestFail("Device partition changed from %s to %s" %
                                 (pci_info[pci_num][4], device_del))
        cmd = confirm_cmd % (pci_info[pci_num][4], offset)
        confirm_info = session.cmd_output(cmd)
        if device_del not in confirm_info:
            raise error.TestFail("Can not find partition tag in Guest: %s" %
                                 confirm_info)
Beispiel #52
0
def run_smbios_table(test, params, env):
    """
    Check smbios table :
    1) Get the smbios table from config file,if there is no config option in
       config file, the script will generate the config parameters automately.
    2) Boot a guest with smbios options and/or -M option
    3) Verify if bios options have been emulated correctly.

    :param test: QEMU test object.
    :param params: Dictionary with the test parameters.
    :param env: Dictionary with test environment.
    """
    smbios_type = params.get("smbios_type")
    notset_output = params.get("notset_output")
    dmidecode_exp = params.get("dmidecode_exp")
    login_timeout = float(params.get("login_timeout", 360))

    smbios = ""
    if params.get("smbios_type_disable", "no") == "no":
        # Set the smbios parameter, if you have set it in the config file,
        # it'll be honored, else, one will be generated.
        for sm_type in smbios_type.split():
            if sm_type == "Bios":
                smbios_type_number = 0
            elif sm_type == "System":
                smbios_type_number = 1
            smbios += " -smbios type=%s" % smbios_type_number
            dmidecode_key = params.object_params(sm_type).get("dmikeyword")
            dmidecode_key = dmidecode_key.split()
            for key in dmidecode_key:
                cmd = dmidecode_exp % (smbios_type_number, key)
                default_key_para = utils.system_output(cmd).strip()
                smbios_key_para_set = params.object_params(sm_type).get(key, default_key_para)
                smbios += ",%s='%s'" % (key.lower(), smbios_key_para_set)

        if params.get("extra_params"):
            params["extra_params"] += smbios
        else:
            params["extra_params"] = smbios

    support_machine_types = []
    if params.get("traversal_machine_emulated", "no") == "no":
        support_machine_types.append(params.get("machine_type"))
    else:
        qemu_binary = utils_misc.get_qemu_binary(params)
        tmp = utils_misc.get_support_machine_type(qemu_binary)
        (support_machine_types, expect_system_versions) = tmp

    failures = []
    for m_type in support_machine_types:
        params["machine_type"] = m_type
        params["start_vm"] = "yes"

        error.context("Boot the vm using -M option:'-M %s',smbios para:'%s' " % (m_type, smbios), logging.info)
        env_process.preprocess_vm(test, params, env, params.get("main_vm"))
        vm1 = env.get_vm(params["main_vm"])
        session = vm1.wait_for_login(timeout=login_timeout)

        error.context("Check smbios info on guest is setted as expected")

        for sm_type in smbios_type.split():
            if sm_type == "Bios":
                smbios_type_number = 0
            elif sm_type == "System":
                smbios_type_number = 1
            dmidecode_key = params.object_params(sm_type).get("dmikeyword")
            dmidecode_key = dmidecode_key.split()
            for key in dmidecode_key:
                cmd = dmidecode_exp % (smbios_type_number, key)
                smbios_get_para = session.cmd(cmd).strip()
                if params.get("smbios_type_disable", "no") == "no":
                    default_key_para = utils.system_output(cmd).strip()
                    smbios_set_para = params.object_params(sm_type).get(key, default_key_para)
                else:
                    key_index = support_machine_types.index(m_type)
                    smbios_set_para = expect_system_versions[key_index]

                if smbios_get_para == notset_output:
                    smbios_get_para = ""

                if smbios_get_para != smbios_set_para:
                    e_msg = "%s.%s mismatch, Set '%s' but guest is : '%s'" % (
                        sm_type,
                        key,
                        smbios_set_para,
                        smbios_get_para,
                    )
                    failures.append(e_msg)

        session.close()
        if params.get("traversal_machine_emulated", "no") == "yes":
            vm1.destroy(gracefully=False)

    error.context("")
    if failures:
        raise error.TestFail("smbios table test reported %s failures:\n%s" % (len(failures), "\n".join(failures)))
Beispiel #53
0
def run(test, params, env):
    """
    Test hotplug of PCI devices and check the status in guest.
    1 Boot up a guest
    2 Hotplug virtio disk to the guest. Record the id and partition name of
      the disk in a list.
    3 Random choice a disk in the list. Unplug the disk and check the
      partition status.
    4 Hotpulg the disk back to guest with the same monitor cmdline and same
      id which is record in step 2.
    5 Check the partition status in guest. And confirm the disk with dd cmd
    6 Repeat step 3 to 5 for N times

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

    def prepare_image_params(params):
        pci_num = int(params['pci_num'])
        for i in xrange(pci_num):
            image_name = '%s_%s' % ('stg', i)
            params['images'] = ' '.join([params['images'], image_name])
            image_image_name = '%s_%s' % ('image_name', image_name)
            params[image_image_name] = '%s_%s' % ('storage', i)
            image_image_format = '%s_%s' % ('image_format', image_name)
            params[image_image_format] = params.get('image_format_extra', 'qcow2')
            image_image_size = '%s_%s' % ('image_size', image_name)
            params[image_image_size] = params.get('image_size_extra', '128K')
        return params

    def find_new_device(check_cmd, device_string, chk_timeout=5.0):
        end_time = time.time() + chk_timeout
        idx = ("wmic" in check_cmd and [0] or [-1])[0]
        while time.time() < end_time:
            new_line = session.cmd_output(check_cmd)
            for line in re.split("\n+", new_line.strip()):
                dev_name = re.split("\s+", line.strip())[idx]
                if dev_name not in device_string:
                    return dev_name
            time.sleep(0.1)
        return None

    def find_del_device(check_cmd, device_string, chk_timeout=5.0):
        end_time = time.time() + chk_timeout
        idx = ("wmic" in check_cmd and [0] or [-1])[0]
        while time.time() < end_time:
            new_line = session.cmd_output(check_cmd)
            for line in re.split("\n+", device_string.strip()):
                dev_name = re.split("\s+", line.strip())[idx]
                if dev_name not in new_line:
                    return dev_name
            time.sleep(0.1)
        return None

    # Select an image file
    def find_image(pci_num):
        image_params = params.object_params("%s" % img_list[pci_num + 1])
        o = storage.get_image_filename(image_params, data_dir.get_data_dir())
        return o

    def pci_add_block(pci_num, queues, pci_id):
        image_filename = find_image(pci_num)
        pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" %
                       (image_filename, pci_model))
        return pci_add(pci_add_cmd)

    def pci_add(pci_add_cmd):
        guest_devices = session.cmd_output(chk_cmd)
        error.context("Adding pci device with command 'pci_add'")
        add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        guest_device = find_new_device(chk_cmd, guest_devices)
        pci_info.append(['', '', add_output, pci_model, guest_device])
        if "OK domain" not in add_output:
            raise error.TestFail("Add PCI device failed. "
                                 "Monitor command is: %s, Output: %r" %
                                 (pci_add_cmd, add_output))
        return vm.monitor.info("pci")

    def is_supported_device(dev):
        # Probe qemu to verify what is the supported syntax for PCI hotplug
        cmd_output = vm.monitor.human_monitor_cmd("?")
        if len(re.findall("\ndevice_add", cmd_output)) > 0:
            cmd_type = "device_add"
        elif len(re.findall("\npci_add", cmd_output)) > 0:
            cmd_type = "pci_add"
        else:
            raise error.TestError("Unknown version of qemu")

        # Probe qemu for a list of supported devices
        probe_output = vm.monitor.human_monitor_cmd("%s ?" % cmd_type)
        devices_supported = [j.strip('"') for j in
                             re.findall('\"[a-z|0-9|\-|\_|\,|\.]*\"',
                                        probe_output, re.MULTILINE)]
        logging.debug("QEMU reported the following supported devices for "
                      "PCI hotplug: %s", devices_supported)
        return (dev in devices_supported)

    def verify_supported_device(dev):
        if not is_supported_device(dev):
            raise error.TestError("%s doesn't support device: %s" %
                                  (cmd_type, dev))

    def device_add_block(pci_num, queues=1, pci_id=None):
        if pci_id is not None:
            device_id = pci_type + "-" + pci_id
        else:
            device_id = pci_type + "-" + utils_misc.generate_random_id()
            pci_info.append([device_id, device_id])

        image_format = params.get("image_format_%s" % img_list[pci_num + 1])
        if not image_format:
            image_format = params.get("image_format", "qcow2")
        image_filename = find_image(pci_num)

        pci_model = params.get("pci_model")
        controller_model = None
        if pci_model == "virtio":
            pci_model = "virtio-blk-pci"

        if pci_model == "scsi":
            pci_model = "scsi-disk"
            if arch.ARCH in ('ppc64', 'ppc64le'):
                controller_model = "spapr-vscsi"
            else:
                controller_model = "lsi53c895a"
            verify_supported_device(controller_model)
            controller_id = "controller-" + device_id
            controller_add_cmd = ("device_add %s,id=%s" %
                                  (controller_model, controller_id))
            error.context("Adding SCSI controller.")
            vm.monitor.send_args_cmd(controller_add_cmd)

        verify_supported_device(pci_model)
        if drive_cmd_type == "drive_add":
            driver_add_cmd = ("%s auto file=%s,if=none,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        elif drive_cmd_type == "__com.redhat_drive_add":
            driver_add_cmd = ("%s file=%s,format=%s,id=%s" %
                              (drive_cmd_type, image_filename, image_format,
                               pci_info[pci_num][0]))
        # add driver.
        error.context("Adding driver.")
        vm.monitor.send_args_cmd(driver_add_cmd, convert=False)

        pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" %
                       (pci_info[pci_num][1],
                        pci_model,
                        pci_info[pci_num][0])
                       )
        return device_add(pci_num, pci_add_cmd, pci_id=pci_id)

    def device_add(pci_num, pci_add_cmd, pci_id=None):
        error.context("Adding pci device with command 'device_add'")
        guest_devices = session.cmd_output(chk_cmd)
        if vm.monitor.protocol == 'qmp':
            add_output = vm.monitor.send_args_cmd(pci_add_cmd)
        else:
            add_output = vm.monitor.send_args_cmd(pci_add_cmd, convert=False)
        guest_device = find_new_device(chk_cmd, guest_devices)
        if pci_id is None:
            pci_info[pci_num].append(add_output)
            pci_info[pci_num].append(pci_model)
            pci_info[pci_num].append(guest_device)

        after_add = vm.monitor.info("pci")
        if pci_info[pci_num][1] not in str(after_add):
            logging.error("Could not find matched id in monitor:"
                          " %s" % pci_info[pci_num][1])
            raise error.TestFail("Add device failed. Monitor command is: %s"
                                 ". Output: %r" % (pci_add_cmd, add_output))
        return after_add

    # Hot add a pci device
    def add_device(pci_num, queues=1, pci_id=None):
        info_pci_ref = vm.monitor.info("pci")
        reference = session.cmd_output(reference_cmd)

        try:
            # get function for adding device.
            add_fuction = local_functions["%s_%s" % (cmd_type, pci_type)]
        except Exception:
            raise error.TestError("No function for adding " +
                                  "'%s' dev " % pci_type +
                                  "with '%s'" % cmd_type)
        after_add = None
        if add_fuction:
            # Do add pci device.
            after_add = add_fuction(pci_num, queues, pci_id)

        try:
            # Define a helper function to compare the output
            def _new_shown():
                o = session.cmd_output(reference_cmd)
                return o != reference

            # Define a helper function to catch PCI device string
            def _find_pci():
                output = session.cmd_output(params.get("find_pci_cmd"))
                output = map(string.strip, output.splitlines())
                ref = map(string.strip, reference.splitlines())
                output = [_ for _ in output if _ not in ref]
                output = "\n".join(output)
                if re.search(params.get("match_string"), output, re.I):
                    return True
                return False

            error.context("Start checking new added device")
            # Compare the output of 'info pci'
            if after_add == info_pci_ref:
                raise error.TestFail("No new PCI device shown after "
                                     "executing monitor command: 'info pci'")

            secs = int(params.get("wait_secs_for_hook_up", 3))
            if not utils_misc.wait_for(_new_shown, test_timeout, secs, 3):
                raise error.TestFail("No new device shown in output of" +
                                     "command executed inside the " +
                                     "guest: %s" % reference_cmd)

            if not utils_misc.wait_for(_find_pci, test_timeout, 3, 3):
                raise error.TestFail("PCI %s %s " % (pci_model, pci_type) +
                                     "device not found in guest. Command " +
                                     "was: %s" % params.get("find_pci_cmd"))

            # Test the newly added device
            try:
                session.cmd(params.get("pci_test_cmd") % (pci_num + 1))
            except aexpect.ShellError, e:
                raise error.TestFail("Check for %s device failed" % pci_type +
                                     "after PCI hotplug." +
                                     "Output: %r" % e.output)

        except Exception:
            pci_del(pci_num, ignore_failure=True)
            raise

    # Hot delete a pci device
    def pci_del(pci_num, ignore_failure=False):
        def _device_removed():
            after_del = vm.monitor.info("pci")
            return after_del != before_del

        before_del = vm.monitor.info("pci")
        if cmd_type == "pci_add":
            slot_id = int(pci_info[pci_num][2].split(",")[2].split()[1])
            cmd = "pci_del pci_addr=%s" % hex(slot_id)
            vm.monitor.send_args_cmd(cmd, convert=False)
        elif cmd_type == "device_add":
            cmd = "device_del id=%s" % pci_info[pci_num][1]
            vm.monitor.send_args_cmd(cmd)

        if (not utils_misc.wait_for(_device_removed, test_timeout, 0, 1) and
                not ignore_failure):
            raise error.TestFail("Failed to hot remove PCI device: %s. "
                                 "Monitor command: %s" %
                                 (pci_info[pci_num][3], cmd))

    params = prepare_image_params(params)
    env_process.process_images(env_process.preprocess_image, test, params)
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 360))
    session = vm.wait_for_login(timeout=timeout)

    test_timeout = int(params.get("hotplug_timeout", 360))
    reference_cmd = params["reference_cmd"]
    # Test if it is nic or block
    pci_type = params["pci_type"]
    pci_model = params["pci_model"]

    # Modprobe the module if specified in config file
    module = params.get("modprobe_module")
    if module:
        session.cmd("modprobe %s" % module)

    # check monitor type
    qemu_binary = utils_misc.get_qemu_binary(params)
    # Probe qemu to verify what is the supported syntax for PCI hotplug
    if vm.monitor.protocol == 'qmp':
        cmd_output = vm.monitor.info("commands")
    else:
        cmd_output = vm.monitor.human_monitor_cmd("help", debug=False)

    cmd_type = utils_misc.find_substring(str(cmd_output), "device_add",
                                         "pci_add")
    if not cmd_type:
        raise error.TestError("Could find a suitable method for hotplugging"
                              " device in this version of qemu")

    # Determine syntax of drive hotplug
    # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6
    # drive_add == qemu-kvm-0.13 onwards
    drive_cmd_type = utils_misc.find_substring(str(cmd_output),
                                               "__com.redhat_drive_add",
                                               "drive_add")
    if not drive_cmd_type:
        raise error.TestError("Unknown version of qemu")

    local_functions = locals()

    pci_num_range = int(params.get("pci_num"))
    rp_times = int(params.get("repeat_times"))
    img_list = params.get("images").split()
    chk_cmd = params.get("guest_check_cmd")
    mark_cmd = params.get("mark_cmd")
    offset = params.get("offset")
    confirm_cmd = params.get("confirm_cmd")

    pci_info = []
    # Add block device into guest
    for pci_num in xrange(pci_num_range):
        error.context("Prepare the %d removable pci device" % pci_num,
                      logging.info)
        add_device(pci_num)
        if pci_info[pci_num][4] is not None:
            partition = pci_info[pci_num][4]
            cmd = mark_cmd % (partition, partition, offset)
            session.cmd(cmd)
        else:
            raise error.TestError("Device not init in guest")

    for j in range(rp_times):
        # pci_info is a list of list.
        # each element 'i' has 4 members:
        # pci_info[i][0] == device drive id, only used for device_add
        # pci_info[i][1] == device id, only used for device_add
        # pci_info[i][2] == output of device add command
        # pci_info[i][3] == device module name.
        # pci_info[i][4] == partition id in guest
        pci_num = random.randint(0, len(pci_info) - 1)
        error.context("start unplug pci device, repeat %d" % j, logging.info)
        guest_devices = session.cmd_output(chk_cmd)
        pci_del(pci_num)
        device_del = find_del_device(chk_cmd, guest_devices)
        if device_del != pci_info[pci_num][4]:
            raise error.TestFail("Device is not deleted in guest.")
        error.context("Start plug pci device, repeat %d" % j, logging.info)
        guest_devices = session.cmd_output(chk_cmd)
        add_device(pci_num, pci_id=pci_info[pci_num][0])
        device_del = find_new_device(chk_cmd, guest_devices)
        if device_del != pci_info[pci_num][4]:
            raise error.TestFail("Device partition changed from %s to %s" %
                                 (pci_info[pci_num][4], device_del))
        cmd = confirm_cmd % (pci_info[pci_num][4], offset)
        confirm_info = session.cmd_output(cmd)
        if device_del not in confirm_info:
            raise error.TestFail("Can not find partition tag in Guest: %s" %
                                 confirm_info)
Beispiel #54
0
def run(test, params, env):
    """
    slof_device_tree test:
    steps:
    1. Boot up a guest.
    2. Check the guest device tree information
    3. Compare the value with expected result.
    :param test: Kvm test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environment.
    """
    def get_info(vm_session, guest_info):
        """
        Check the corresponding information from vm.

        :param vm_session: session to checked vm.
        :return: corresponding prompt
        """
        (status, output) = vm_session.cmd_status_output(
            "echo `cat /proc/device-tree/%s`" % guest_info)
        if status != 0:
            raise exceptions.TestFail("Failed to get %s" % guest_info)
        return output.strip()

    def check_nonexist_aliases(vm_session, devices):
        """
        Check a nonexist device aliases.

        :param vm_session: session to checked vm.
        :return: corresponding prompt
        """

        status = vm_session.cmd_status(
            "test -f /proc/device-tree/aliases/cdrom")
        error_context.context(
            "Checking whether aliases file is indeed nonexisting",
            logging.info)
        if status == 0:
            raise exceptions.TestFail("Nonexist cdrom aliases check failed.")

    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()
    timeout = int(params.get("login_timeout", 600))

    session = vm.wait_for_login(timeout=timeout)

    try:
        guest_system_id = get_info(session, "system-id")
        if guest_system_id != vm.get_uuid():
            raise exceptions.TestFail("Guest system id does not match to uuid")

        guest_uuid = get_info(session, "vm,uuid")
        if guest_uuid != vm.get_uuid():
            raise exceptions.TestFail(
                "Guest uuid does not match to expected id.")

        host_system_id = process.system_output(
            "echo `cat /proc/device-tree/system-id`", shell=True).strip()
        host_system_id_in_guest = get_info(session, "host-serial")
        if host_system_id != host_system_id_in_guest:
            raise exceptions.TestFail(
                "Host system id does not match to value in guest.")

        guest_partition_name = get_info(session, "ibm,partition-name")
        if guest_partition_name != params.get("main_vm"):
            raise exceptions.TestFail("Guest partition name is wrong.")

        qemu_binary = utils_misc.get_qemu_binary(params)
        devices = qcontainer.DevContainer(qemu_binary, vm, strict_mode="no")
        check_nonexist_aliases(session, devices)

    finally:
        session.close()
def run(test, params, env):
    """
    Test qmp event notification function:
    1) Boot up guest with qmp.
    2) Trigger qmp event in guest.
    3) Try to catch qmp event notification in qmp monitor.

    :param test: QEMU test object
    :param params: Dictionary with the test parameters
    :param env: Dictionary with test environmen.
    """

    qemu_binary = utils_misc.get_qemu_binary(params)
    if not utils_misc.qemu_has_option("qmp", qemu_binary):
        error.TestNAError("This test case requires a host QEMU with QMP "
                          "monitor support")
    vm = env.get_vm(params["main_vm"])
    vm.verify_alive()

    session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360)))
    qmp_monitor = filter(lambda x: x.protocol == "qmp", vm.monitors)[0]
    humam_monitor = filter(lambda x: x.protocol == "human", vm.monitors)[0]
    callback = {"host_cmd": commands.getoutput,
                "guest_cmd": session.cmd,
                "monitor_cmd": humam_monitor.send_args_cmd,
                "qmp_cmd": qmp_monitor.send_args_cmd}

    def send_cmd(cmd, options={}):
        if cmd_type in callback.keys():
            return callback[cmd_type](cmd, **options)
        else:
            raise error.TestError("cmd_type is not supported")

    pre_event_cmd = params.get("pre_event_cmd", "")
    pre_event_cmd_options = eval(
        "dict({0})".format(params.get("pre_event_cmd_options", "")))
    event_cmd = params.get("event_cmd")
    event_cmd_options = eval(
        "dict({0})".format(params.get("event_cmd_options", "")))
    post_event_cmd = params.get("post_event_cmd", "")
    post_event_cmd_options = eval(
        "dict({0})".format(params.get("post_event_cmd_options", "")))
    cmd_type = params.get("event_cmd_type")
    event_check = params.get("event_check")
    timeout = int(params.get("check_timeout", 360))
    action_check = params.get("action_check")

    if pre_event_cmd:
        send_cmd(pre_event_cmd, pre_event_cmd_options)

    send_cmd(event_cmd, event_cmd_options)

    end_time = time.time() + timeout
    qmp_monitors = vm.get_monitors_by_type("qmp")
    qmp_num = len(qmp_monitors)
    logging.info("Try to get qmp events in %s seconds!", timeout)
    while time.time() < end_time:
        for monitor in qmp_monitors:
            event = monitor.get_event(event_check)
            if event_check == "WATCHDOG":
                if event and event['data']['action'] == action_check:
                    logging.info("Receive watchdog %s event notification",
                                 action_check)
                    qmp_num -= 1
                    qmp_monitors.remove(monitor)
            else:
                if event:
                    logging.info("Receive qmp %s event notification",
                                 event_check)
                    qmp_num -= 1
                    qmp_monitors.remove(monitor)
        time.sleep(5)
        if qmp_num <= 0:
            break

    if qmp_num > 0:
        raise error.TestFail("Did not receive qmp %s event notification"
                             % event_check)

    if post_event_cmd:
        send_cmd(post_event_cmd, post_event_cmd_options)
    if session:
        session.close()