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))
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!")
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!")
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)
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)))
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))
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()
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()
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)
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)
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)
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()
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))
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.')
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)
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
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)
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")
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)
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)
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)
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)
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()
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))
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()
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
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)))
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)
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()
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()
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()
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)
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)
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)))
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")
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()
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)
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)))
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)
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()
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)
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)
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)))
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)
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()