def rebase_test(cmd): """ Subcommand 'qemu-img rebase' test Change the backing file of a snapshot image in "unsafe mode": Assume the previous backing file had missed and we just have to change reference of snapshot to new one. After change the backing file of a snapshot image in unsafe mode, the snapshot should work still. @param cmd: qemu-img base command. """ if not 'rebase' in utils.system_output(cmd + ' --help', ignore_status=True): raise error.TestNAError("Current kvm user space version does not" " support 'rebase' subcommand") sn_fmt = params.get("snapshot_format", "qcow2") sn1 = params.get("image_name_snapshot1") sn1 = kvm_utils.get_path(test.bindir, sn1) + ".%s" % sn_fmt base_img = kvm_vm.get_image_filename(params, test.bindir) _create(cmd, sn1, sn_fmt, base_img=base_img, base_img_fmt=image_format) # Create snapshot2 based on snapshot1 sn2 = params.get("image_name_snapshot2") sn2 = kvm_utils.get_path(test.bindir, sn2) + ".%s" % sn_fmt _create(cmd, sn2, sn_fmt, base_img=sn1, base_img_fmt=sn_fmt) rebase_mode = params.get("rebase_mode") if rebase_mode == "unsafe": os.remove(sn1) _rebase(cmd, sn2, base_img, image_format, mode=rebase_mode) # Check sn2's format and backing_file actual_base_img = _info(cmd, sn2, "backing file") base_img_name = os.path.basename(params.get("image_name")) if not base_img_name in actual_base_img: raise error.TestFail("After rebase the backing_file of 'sn2' is " "'%s' which is not expected as '%s'" % (actual_base_img, base_img_name)) s, o = _check(cmd, sn2) if not s: raise error.TestFail("Check image '%s' failed after rebase;" "got error: %s" % (sn2, o)) try: os.remove(sn2) os.remove(sn1) except: pass
def check_test(cmd): """ Subcommand 'qemu-img check' test. This tests will 'dd' to create a specified size file, and check it. Then convert it to supported image_format in each loop and check again. @param cmd: qemu-img base command. """ test_image = kvm_utils.get_path(test.bindir, params.get("image_name_dd")) print "test_image = %s" % test_image create_image_cmd = params.get("create_image_cmd") create_image_cmd = create_image_cmd % test_image print "create_image_cmd = %s" % create_image_cmd utils.system(create_image_cmd) s, o = _check(cmd, test_image) if not s: raise error.TestFail("Check image '%s' failed with error: %s" % (test_image, o)) for fmt in params.get("supported_image_formats").split(): output_image = test_image + ".%s" % fmt _convert(cmd, fmt, test_image, output_image) s, o = _check(cmd, output_image) if not s: raise error.TestFail("Check image '%s' got error: %s" % (output_image, o)) os.remove(output_image) os.remove(test_image)
def run_qemu_img(test, params, env): """ 'qemu-img' functions test: 1) Judge what subcommand is going to be tested 2) Run subcommand test @param test: kvm test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ cmd = kvm_utils.get_path(test.bindir, params.get("qemu_img_binary")) if not os.path.exists(cmd): raise error.TestError("Binary of 'qemu-img' not found") image_format = params.get("image_format") image_size = params.get("image_size", "10G") image_name = kvm_vm.get_image_filename(params, test.bindir) def _check(cmd, img): """ Simple 'qemu-img check' function implementation. @param cmd: qemu-img base command. @param img: image to be checked """ cmd += " check %s" % img logging.info("Checking image '%s'...", img) try: output = utils.system_output(cmd) except error.CmdError, e: if "does not support checks" in str(e): return (True, "") else: return (False, str(e)) return (True, output)
def create_image(params, root_dir): """ Create an image using qemu_image. @param params: Dictionary containing the test parameters. @param root_dir: Base directory for relative filenames. @note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) image_size -- the requested size of the image (a string qemu-img can understand, such as '10G') """ qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary", "qemu-img")) qemu_img_cmd += " create" format = params.get("image_format", "qcow2") qemu_img_cmd += " -f %s" % format image_filename = get_image_filename(params, root_dir) qemu_img_cmd += " %s" % image_filename size = params.get("image_size", "10G") qemu_img_cmd += " %s" % size try: utils.system(qemu_img_cmd) except error.CmdError, e: logging.error("Could not create image; qemu-img command failed:\n%s", str(e)) return None
def _take_screendumps(test, params, env): global _screendump_thread_termination_event temp_dir = test.debugdir if params.get("screendump_temp_dir"): temp_dir = kvm_utils.get_path(test.bindir, params.get("screendump_temp_dir")) try: os.makedirs(temp_dir) except OSError: pass temp_filename = os.path.join(temp_dir, "scrdump-%s.ppm" % kvm_utils.generate_random_string(6)) delay = float(params.get("screendump_delay", 5)) quality = int(params.get("screendump_quality", 30)) cache = {} while True: for vm in env.get_all_vms(): if not vm.is_alive(): continue try: vm.monitor.screendump(temp_filename) except kvm_monitor.MonitorError, e: logging.warn(e) continue if not os.path.exists(temp_filename): logging.warn("VM '%s' failed to produce a screendump", vm.name) continue if not ppm_utils.image_verify_ppm_file(temp_filename): logging.warn("VM '%s' produced an invalid screendump", vm.name) os.unlink(temp_filename) continue screendump_dir = os.path.join(test.debugdir, "screendumps_%s" % vm.name) try: os.makedirs(screendump_dir) except OSError: pass screendump_filename = os.path.join(screendump_dir, "%s_%s.jpg" % (vm.name, time.strftime("%Y-%m-%d_%H-%M-%S"))) hash = utils.hash_file(temp_filename) if hash in cache: try: os.link(cache[hash], screendump_filename) except OSError: pass else: try: image = PIL.Image.open(temp_filename) image.save(screendump_filename, format="JPEG", quality=quality) cache[hash] = screendump_filename except NameError: pass os.unlink(temp_filename) if _screendump_thread_termination_event.isSet(): _screendump_thread_termination_event = None break _screendump_thread_termination_event.wait(delay)
def run_autoit(test, params, env): """ A wrapper for AutoIt scripts. 1) Log into a guest. 2) Run AutoIt script. 3) Wait for script execution to complete. 4) Pass/fail according to exit status of script. @param test: KVM test object. @param params: Dictionary with test parameters. @param env: Dictionary with the test environment. """ vm = kvm_test_utils.get_living_vm(env, params.get("main_vm")) session = kvm_test_utils.wait_for_login(vm) try: logging.info("Starting script...") # Collect test parameters binary = params.get("autoit_binary") script = params.get("autoit_script") script_params = params.get("autoit_script_params", "") timeout = float(params.get("autoit_script_timeout", 600)) # Send AutoIt script to guest (this code will be replaced once we # support sending files to Windows guests) session.sendline("del script.au3") file = open(kvm_utils.get_path(test.bindir, script)) for line in file.readlines(): # Insert a '^' before each character line = "".join("^" + c for c in line.rstrip()) if line: # Append line to the file session.sendline("echo %s>>script.au3" % line) file.close() session.read_up_to_prompt() command = "cmd /c %s script.au3 %s" % (binary, script_params) logging.info("---------------- Script output ----------------") status = session.get_command_status(command, print_func=logging.info, timeout=timeout) logging.info("---------------- End of script output ----------------") if status is None: raise error.TestFail("Timeout expired before script execution " "completed (or something weird happened)") if status != 0: raise error.TestFail("Script execution failed") finally: session.close()
def create_test(cmd): """ Subcommand 'qemu-img create' test. @param cmd: qemu-img base command. """ image_large = params.get("image_name_large") img = kvm_utils.get_path(test.bindir, image_large) img += '.' + image_format _create(cmd, img_name=img, fmt=image_format, img_size=params.get("image_size_large")) os.remove(img)
def run_nic_bonding(test, params, env): """ Nic bonding test in guest. 1) Start guest with four nic models. 2) Setup bond0 in guest by script nic_bonding_guest.py. 3) Execute file transfer test between guest and host. 4) Repeatedly put down/up interfaces by set_link 5) Execute file transfer test between guest and host. @param test: Kvm test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ def control_link_loop(vm, termination_event): logging.info("Repeatedly put down/up interfaces by set_link") while True: for i in range(len(params.get("nics").split())): linkname = "%s.%s" % (params.get("nic_model"), i) cmd = "set_link %s down" % linkname vm.monitor.cmd(cmd) time.sleep(1) cmd = "set_link %s up" % linkname vm.monitor.cmd(cmd) if termination_event.isSet(): break timeout = int(params.get("login_timeout", 1200)) vm = env.get_vm(params["main_vm"]) vm.verify_alive() session_serial = vm.wait_for_serial_login(timeout=timeout) script_path = kvm_utils.get_path(test.bindir, "scripts/nic_bonding_guest.py") vm.copy_files_to(script_path, "/tmp/nic_bonding_guest.py") cmd = "python /tmp/nic_bonding_guest.py %s" % vm.get_mac_address() session_serial.cmd(cmd) termination_event = threading.Event() t = threading.Thread(target=control_link_loop, args=(vm, termination_event)) try: logging.info("Do some basic test before testing high availability") file_transfer.run_file_transfer(test, params, env) t.start() logging.info("Do file transfer testing") file_transfer.run_file_transfer(test, params, env) finally: termination_event.set() t.join(10) session_serial.close()
def get_image_filename(params, root_dir): """ Generate an image path from params and root_dir. @param params: Dictionary containing the test parameters. @param root_dir: Base directory for relative filenames. @note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) """ image_name = params.get("image_name", "image") image_format = params.get("image_format", "qcow2") image_filename = "%s.%s" % (image_name, image_format) image_filename = kvm_utils.get_path(root_dir, image_filename) return image_filename
def netdev_add(vm): netdev_id = kvm_utils.generate_random_id() attach_cmd = ("netdev_add tap,id=%s,script=%s" % (netdev_id, kvm_utils.get_path(vm.root_dir, params.get("nic_script")))) netdev_extra_params = params.get("netdev_extra_params") if netdev_extra_params: attach_cmd += ",%s" % netdev_extra_params logging.info("Adding netdev through %s", attach_cmd) vm.monitor.cmd(attach_cmd) network = vm.monitor.info("network") if netdev_id not in network: logging.error(network) raise error.TestError("Fail to add netdev: %s" % netdev_id) else: return netdev_id
def run_stepmaker(test, params, env): vm = env.get_vm(params.get("main_vm")) if not vm: raise error.TestError("VM object not found in environment") if not vm.is_alive(): raise error.TestError("VM seems to be dead; Step Maker requires a" " living VM") steps_filename = params.get("steps") if not steps_filename: raise error.TestError("Steps filename not specified") steps_filename = kvm_utils.get_path(test.bindir, steps_filename) if os.path.exists(steps_filename): raise error.TestError("Steps file %s already exists" % steps_filename) StepMaker(vm, steps_filename, test.debugdir, params) gtk.main()
def create_image(params, root_dir): """ Create an image using qemu_image. @param params: Dictionary containing the test parameters. @param root_dir: Base directory for relative filenames. @note: params should contain: image_name -- the name of the image file, without extension image_format -- the format of the image (qcow2, raw etc) image_size -- the requested size of the image (a string qemu-img can understand, such as '10G') """ qemu_img_cmd = kvm_utils.get_path(root_dir, params.get("qemu_img_binary", "qemu-img")) qemu_img_cmd += " create" format = params.get("image_format", "qcow2") qemu_img_cmd += " -f %s" % format image_filename = get_image_filename(params, root_dir) qemu_img_cmd += " %s" % image_filename size = params.get("image_size", "10G") qemu_img_cmd += " %s" % size logging.debug("Running qemu-img command:\n%s" % qemu_img_cmd) (status, output) = kvm_subprocess.run_fg(qemu_img_cmd, logging.debug, "(qemu-img) ", timeout=30) if status is None: logging.error("Timeout elapsed while waiting for qemu-img command " "to complete:\n%s" % qemu_img_cmd) return None elif status != 0: logging.error("Could not create image; " "qemu-img command failed:\n%s" % qemu_img_cmd) logging.error("Status: %s" % status) logging.error("Output:" + kvm_utils.format_str_for_message(output)) return None if not os.path.exists(image_filename): logging.error("Image could not be created for some reason; " "qemu-img command:\n%s" % qemu_img_cmd) return None logging.info("Image created in %s" % image_filename) return image_filename
def create(self, name=None, params=None, root_dir=None, for_migration=False, timeout=5.0): """ Start the VM by running a qemu command. All parameters are optional. The following applies to all parameters but for_migration: If a parameter is not supplied, the corresponding value stored in the class attributes is used, and if it is supplied, it is stored for later use. @param name: The name of the object @param params: A dict containing VM params @param root_dir: Base directory for relative filenames @param for_migration: If True, start the VM with the -incoming option """ self.destroy() if name != None: self.name = name if params != None: self.params = params if root_dir != None: self.root_dir = root_dir name = self.name params = self.params root_dir = self.root_dir # Verify the md5sum of the ISO image iso = params.get("cdrom") if iso: iso = kvm_utils.get_path(root_dir, iso) if not os.path.exists(iso): logging.error("ISO file not found: %s" % iso) return False compare = False if params.get("md5sum_1m"): logging.debug("Comparing expected MD5 sum with MD5 sum of " "first MB of ISO file...") actual_md5sum = kvm_utils.md5sum_file(iso, 1048576) expected_md5sum = params.get("md5sum_1m") compare = True elif params.get("md5sum"): logging.debug("Comparing expected MD5 sum with MD5 sum of ISO " "file...") actual_md5sum = kvm_utils.md5sum_file(iso) expected_md5sum = params.get("md5sum") compare = True if compare: if actual_md5sum == expected_md5sum: logging.debug("MD5 sums match") else: logging.error("Actual MD5 sum differs from expected one") return False # Make sure the following code is not executed by more than one thread # at the same time lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+") fcntl.lockf(lockfile, fcntl.LOCK_EX) try: # Handle port redirections redir_names = kvm_utils.get_sub_dict_names(params, "redirs") host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) self.redirs = {} for i in range(len(redir_names)): redir_params = kvm_utils.get_sub_dict(params, redir_names[i]) guest_port = int(redir_params.get("guest_port")) self.redirs[guest_port] = host_ports[i] # Find available VNC port, if needed if params.get("display") == "vnc": self.vnc_port = kvm_utils.find_free_port(5900, 6000) # Find random UUID if specified 'uuid = random' in config file if params.get("uuid") == "random": f = open("/proc/sys/kernel/random/uuid") self.uuid = f.read().strip() f.close() # Make qemu command qemu_command = self.make_qemu_command() # Is this VM supposed to accept incoming migrations? if for_migration: # Find available migration port self.migration_port = kvm_utils.find_free_port(5200, 6000) # Add -incoming option to the qemu command qemu_command += " -incoming tcp:0:%d" % self.migration_port logging.debug("Running qemu command:\n%s", qemu_command) self.process = kvm_subprocess.run_bg(qemu_command, None, logging.debug, "(qemu) ") if not self.process.is_alive(): logging.error("VM could not be created; " "qemu command failed:\n%s" % qemu_command) logging.error("Status: %s" % self.process.get_status()) logging.error("Output:" + kvm_utils.format_str_for_message(self.process.get_output())) self.destroy() return False if not kvm_utils.wait_for(self.is_alive, timeout, 0, 1): logging.error("VM is not alive for some reason; " "qemu command:\n%s" % qemu_command) self.destroy() return False # Get the output so far, to see if we have any problems with # hugepage setup. output = self.process.get_output() if "alloc_mem_area" in output: logging.error("Could not allocate hugepage memory; " "qemu command:\n%s" % qemu_command) logging.error("Output:" + kvm_utils.format_str_for_message(self.process.get_output())) return False logging.debug("VM appears to be alive with PID %d", self.process.get_pid()) return True finally: fcntl.lockf(lockfile, fcntl.LOCK_UN) lockfile.close()
def make_qemu_command(self, name=None, params=None, root_dir=None): """ Generate a qemu command line. All parameters are optional. If a parameter is not supplied, the corresponding value stored in the class attributes is used. @param name: The name of the object @param params: A dict containing VM params @param root_dir: Base directory for relative filenames @note: The params dict should contain: mem -- memory size in MBs cdrom -- ISO filename to use with the qemu -cdrom parameter extra_params -- a string to append to the qemu command shell_port -- port of the remote shell daemon on the guest (SSH, Telnet or the home-made Remote Shell Server) shell_client -- client program to use for connecting to the remote shell daemon on the guest (ssh, telnet or nc) x11_display -- if specified, the DISPLAY environment variable will be be set to this value for the qemu process (useful for SDL rendering) images -- a list of image object names, separated by spaces nics -- a list of NIC object names, separated by spaces For each image in images: drive_format -- string to pass as 'if' parameter for this image (e.g. ide, scsi) image_snapshot -- if yes, pass 'snapshot=on' to qemu for this image image_boot -- if yes, pass 'boot=on' to qemu for this image In addition, all parameters required by get_image_filename. For each NIC in nics: nic_model -- string to pass as 'model' parameter for this NIC (e.g. e1000) """ if name == None: name = self.name if params == None: params = self.params if root_dir == None: root_dir = self.root_dir # Start constructing the qemu command qemu_cmd = "" # Set the X11 display parameter if requested if params.get("x11_display"): qemu_cmd += "DISPLAY=%s " % params.get("x11_display") # Add the qemu binary qemu_cmd += kvm_utils.get_path(root_dir, params.get("qemu_binary", "qemu")) # Add the VM's name qemu_cmd += " -name '%s'" % name # Add the monitor socket parameter qemu_cmd += " -monitor unix:%s,server,nowait" % self.monitor_file_name for image_name in kvm_utils.get_sub_dict_names(params, "images"): image_params = kvm_utils.get_sub_dict(params, image_name) if image_params.get("boot_drive") == "no": continue qemu_cmd += " -drive file=%s" % get_image_filename(image_params, root_dir) if image_params.get("drive_format"): qemu_cmd += ",if=%s" % image_params.get("drive_format") if image_params.get("drive_cache"): qemu_cmd += ",cache=%s" % image_params.get("drive_cache") if image_params.get("drive_serial"): qemu_cmd += ",serial=%s" % image_params.get("drive_serial") if image_params.get("image_snapshot") == "yes": qemu_cmd += ",snapshot=on" if image_params.get("image_boot") == "yes": qemu_cmd += ",boot=on" vlan = 0 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"): nic_params = kvm_utils.get_sub_dict(params, nic_name) # Handle the '-net nic' part qemu_cmd += " -net nic,vlan=%d" % vlan if nic_params.get("nic_model"): qemu_cmd += ",model=%s" % nic_params.get("nic_model") if nic_params.has_key("address_index"): mac, ip = kvm_utils.get_mac_ip_pair_from_dict(nic_params) if mac: qemu_cmd += ",macaddr=%s" % mac # Handle the '-net tap' or '-net user' part mode = nic_params.get("nic_mode", "user") qemu_cmd += " -net %s,vlan=%d" % (mode, vlan) if mode == "tap": if nic_params.get("nic_ifname"): qemu_cmd += ",ifname=%s" % nic_params.get("nic_ifname") script_path = nic_params.get("nic_script") if script_path: script_path = kvm_utils.get_path(root_dir, script_path) qemu_cmd += ",script=%s" % script_path script_path = nic_params.get("nic_downscript") if script_path: script_path = kvm_utils.get_path(root_dir, script_path) qemu_cmd += ",downscript=%s" % script_path # Proceed to next NIC vlan += 1 mem = params.get("mem") if mem: qemu_cmd += " -m %s" % mem iso = params.get("cdrom") if iso: iso = kvm_utils.get_path(root_dir, iso) qemu_cmd += " -cdrom %s" % iso extra_params = params.get("extra_params") if extra_params: qemu_cmd += " %s" % extra_params for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"): redir_params = kvm_utils.get_sub_dict(params, redir_name) guest_port = int(redir_params.get("guest_port")) host_port = self.redirs.get(guest_port) qemu_cmd += " -redir tcp:%s::%s" % (host_port, guest_port) if params.get("display") == "vnc": qemu_cmd += " -vnc :%d" % (self.vnc_port - 5900) elif params.get("display") == "sdl": qemu_cmd += " -sdl" elif params.get("display") == "nographic": qemu_cmd += " -nographic" if params.get("uuid") == "random": qemu_cmd += " -uuid %s" % self.uuid elif params.get("uuid"): qemu_cmd += " -uuid %s" % params.get("uuid") return qemu_cmd
def create(self, name=None, params=None, root_dir=None, timeout=5.0, migration_mode=None, mac_source=None): """ Start the VM by running a qemu command. All parameters are optional. If name, params or root_dir are not supplied, the respective values stored as class attributes are used. @param name: The name of the object @param params: A dict containing VM params @param root_dir: Base directory for relative filenames @param migration_mode: If supplied, start VM for incoming migration using this protocol (either 'tcp', 'unix' or 'exec') @param migration_exec_cmd: Command to embed in '-incoming "exec: ..."' (e.g. 'gzip -c -d filename') if migration_mode is 'exec' @param mac_source: A VM object from which to copy MAC addresses. If not specified, new addresses will be generated. """ self.destroy() if name is not None: self.name = name if params is not None: self.params = params if root_dir is not None: self.root_dir = root_dir name = self.name params = self.params root_dir = self.root_dir # Verify the md5sum of the ISO image iso = params.get("cdrom") if iso: iso = kvm_utils.get_path(root_dir, iso) if not os.path.exists(iso): logging.error("ISO file not found: %s" % iso) return False compare = False if params.get("md5sum_1m"): logging.debug("Comparing expected MD5 sum with MD5 sum of " "first MB of ISO file...") actual_hash = utils.hash_file(iso, 1048576, method="md5") expected_hash = params.get("md5sum_1m") compare = True elif params.get("md5sum"): logging.debug("Comparing expected MD5 sum with MD5 sum of ISO " "file...") actual_hash = utils.hash_file(iso, method="md5") expected_hash = params.get("md5sum") compare = True elif params.get("sha1sum"): logging.debug("Comparing expected SHA1 sum with SHA1 sum of " "ISO file...") actual_hash = utils.hash_file(iso, method="sha1") expected_hash = params.get("sha1sum") compare = True if compare: if actual_hash == expected_hash: logging.debug("Hashes match") else: logging.error("Actual hash differs from expected one") return False # Make sure the following code is not executed by more than one thread # at the same time lockfile = open("/tmp/kvm-autotest-vm-create.lock", "w+") fcntl.lockf(lockfile, fcntl.LOCK_EX) try: # Handle port redirections redir_names = kvm_utils.get_sub_dict_names(params, "redirs") host_ports = kvm_utils.find_free_ports(5000, 6000, len(redir_names)) self.redirs = {} for i in range(len(redir_names)): redir_params = kvm_utils.get_sub_dict(params, redir_names[i]) guest_port = int(redir_params.get("guest_port")) self.redirs[guest_port] = host_ports[i] # Generate netdev IDs for all NICs self.netdev_id = [] for nic in kvm_utils.get_sub_dict_names(params, "nics"): self.netdev_id.append(kvm_utils.generate_random_id()) # Find available VNC port, if needed if params.get("display") == "vnc": self.vnc_port = kvm_utils.find_free_port(5900, 6100) # Find random UUID if specified 'uuid = random' in config file if params.get("uuid") == "random": f = open("/proc/sys/kernel/random/uuid") self.uuid = f.read().strip() f.close() # Generate or copy MAC addresses for all NICs num_nics = len(kvm_utils.get_sub_dict_names(params, "nics")) for vlan in range(num_nics): nic_name = kvm_utils.get_sub_dict_names(params, "nics")[vlan] nic_params = kvm_utils.get_sub_dict(params, nic_name) if nic_params.get("nic_mac", None): mac = nic_params.get("nic_mac") kvm_utils.set_mac_address(self.instance, vlan, mac) else: mac = mac_source and mac_source.get_mac_address(vlan) if mac: kvm_utils.set_mac_address(self.instance, vlan, mac) else: kvm_utils.generate_mac_address(self.instance, vlan) # Assign a PCI assignable device self.pci_assignable = None pa_type = params.get("pci_assignable") if pa_type in ["vf", "pf", "mixed"]: pa_devices_requested = params.get("devices_requested") # Virtual Functions (VF) assignable devices if pa_type == "vf": self.pci_assignable = kvm_utils.PciAssignable( type=pa_type, driver=params.get("driver"), driver_option=params.get("driver_option"), devices_requested=pa_devices_requested) # Physical NIC (PF) assignable devices elif pa_type == "pf": self.pci_assignable = kvm_utils.PciAssignable( type=pa_type, names=params.get("device_names"), devices_requested=pa_devices_requested) # Working with both VF and PF elif pa_type == "mixed": self.pci_assignable = kvm_utils.PciAssignable( type=pa_type, driver=params.get("driver"), driver_option=params.get("driver_option"), names=params.get("device_names"), devices_requested=pa_devices_requested) self.pa_pci_ids = self.pci_assignable.request_devs() if self.pa_pci_ids: logging.debug("Successfuly assigned devices: %s", self.pa_pci_ids) else: logging.error("No PCI assignable devices were assigned " "and 'pci_assignable' is defined to %s " "on your config file. Aborting VM creation.", pa_type) return False elif pa_type and pa_type != "no": logging.warn("Unsupported pci_assignable type: %s", pa_type) # Make qemu command qemu_command = self.make_qemu_command() # Add migration parameters if required if migration_mode == "tcp": self.migration_port = kvm_utils.find_free_port(5200, 6000) qemu_command += " -incoming tcp:0:%d" % self.migration_port elif migration_mode == "unix": self.migration_file = "/tmp/migration-unix-%s" % self.instance qemu_command += " -incoming unix:%s" % self.migration_file elif migration_mode == "exec": self.migration_port = kvm_utils.find_free_port(5200, 6000) qemu_command += (' -incoming "exec:nc -l %s"' % self.migration_port) logging.debug("Running qemu command:\n%s", qemu_command) self.process = kvm_subprocess.run_bg(qemu_command, None, logging.debug, "(qemu) ") # Make sure the process was started successfully if not self.process.is_alive(): logging.error("VM could not be created; " "qemu command failed:\n%s" % qemu_command) logging.error("Status: %s" % self.process.get_status()) logging.error("Output:" + kvm_utils.format_str_for_message( self.process.get_output())) self.destroy() return False # Establish monitor connections self.monitors = [] for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"): monitor_params = kvm_utils.get_sub_dict(params, monitor_name) # Wait for monitor connection to succeed end_time = time.time() + timeout while time.time() < end_time: try: if monitor_params.get("monitor_type") == "qmp": # Add a QMP monitor monitor = kvm_monitor.QMPMonitor( monitor_name, self.get_monitor_filename(monitor_name)) else: # Add a "human" monitor monitor = kvm_monitor.HumanMonitor( monitor_name, self.get_monitor_filename(monitor_name)) except kvm_monitor.MonitorError, e: logging.warn(e) else: if monitor.is_responsive(): break time.sleep(1) else: logging.error("Could not connect to monitor '%s'" % monitor_name) self.destroy() return False # Add this monitor to the list self.monitors += [monitor] # Get the output so far, to see if we have any problems with # KVM modules or with hugepage setup. output = self.process.get_output() if re.search("Could not initialize KVM", output, re.IGNORECASE): logging.error("Could not initialize KVM; " "qemu command:\n%s" % qemu_command) logging.error("Output:" + kvm_utils.format_str_for_message( self.process.get_output())) self.destroy() return False if "alloc_mem_area" in output: logging.error("Could not allocate hugepage memory; " "qemu command:\n%s" % qemu_command) logging.error("Output:" + kvm_utils.format_str_for_message( self.process.get_output())) self.destroy() return False logging.debug("VM appears to be alive with PID %s", self.get_pid()) # Establish a session with the serial console -- requires a version # of netcat that supports -U self.serial_console = kvm_subprocess.ShellSession( "nc -U %s" % self.get_serial_console_filename(), auto_close=False, output_func=kvm_utils.log_line, output_params=("serial-%s.log" % name,)) return True
def run_guest_test(test, params, env): """ A wrapper for running customized tests in guests. 1) Log into a guest. 2) Run script. 3) Wait for script execution to complete. 4) Pass/fail according to exit status of script. @param test: KVM test object. @param params: Dictionary with test parameters. @param env: Dictionary with the test environment. """ login_timeout = int(params.get("login_timeout", 360)) reboot = params.get("reboot", "no") vm = env.get_vm(params["main_vm"]) vm.verify_alive() if params.get("serial_login") == "yes": session = vm.wait_for_serial_login(timeout=login_timeout) else: session = vm.wait_for_login(timeout=login_timeout) if reboot == "yes": logging.debug("Rebooting guest before test ...") session = vm.reboot(session, timeout=login_timeout) try: logging.info("Starting script...") # Collect test parameters interpreter = params.get("interpreter") script = params.get("guest_script") dst_rsc_path = params.get("dst_rsc_path", "script.au3") script_params = params.get("script_params", "") test_timeout = float(params.get("test_timeout", 600)) logging.debug("Starting preparing resouce files...") # Download the script resource from a remote server, or # prepare the script using rss? if params.get("download") == "yes": download_cmd = params.get("download_cmd") rsc_server = params.get("rsc_server") rsc_dir = os.path.basename(rsc_server) dst_rsc_dir = params.get("dst_rsc_dir") # Change dir to dst_rsc_dir, and remove the guest script dir there rm_cmd = "cd %s && (rmdir /s /q %s || del /s /q %s)" % \ (dst_rsc_dir, rsc_dir, rsc_dir) session.cmd(rm_cmd, timeout=test_timeout) logging.debug("Clean directory succeeded.") # then download the resource. rsc_cmd = "cd %s && %s %s" % (dst_rsc_dir, download_cmd, rsc_server) session.cmd(rsc_cmd, timeout=test_timeout) logging.info("Download resource finished.") else: session.cmd_output("del %s" % dst_rsc_path, internal_timeout=0) script_path = kvm_utils.get_path(test.bindir, script) vm.copy_files_to(script_path, dst_rsc_path, timeout=60) cmd = "%s %s %s" % (interpreter, dst_rsc_path, script_params) try: logging.info("------------ Script output ------------") session.cmd(cmd, print_func=logging.info, timeout=test_timeout) finally: logging.info("------------ End of script output ------------") if reboot == "yes": logging.debug("Rebooting guest after test ...") session = vm.reboot(session, timeout=login_timeout) logging.debug("guest test PASSED.") finally: session.close()
def preprocess(test, params, env): """ Preprocess all VMs and images according to the instructions in params. Also, collect some host information, such as the KVM version. @param test: An Autotest test object. @param params: A dict containing all VM and image parameters. @param env: The environment (a dict-like object). """ error.context("preprocessing") # Start tcpdump if it isn't already running if "address_cache" not in env: env["address_cache"] = {} if "tcpdump" in env and not env["tcpdump"].is_alive(): env["tcpdump"].close() del env["tcpdump"] if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes": cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump") logging.debug("Starting tcpdump (%s)...", cmd) env["tcpdump"] = kvm_subprocess.Tail( command=cmd, output_func=_update_address_cache, output_params=(env["address_cache"], )) if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(), 0.1, 0.1, 1.0): logging.warn("Could not start tcpdump") logging.warn("Status: %s" % env["tcpdump"].get_status()) logging.warn( "Output:" + kvm_utils.format_str_for_message(env["tcpdump"].get_output())) # Destroy and remove VMs that are no longer needed in the environment requested_vms = params.objects("vms") for key in env.keys(): vm = env[key] if not kvm_utils.is_vm(vm): continue if not vm.name in requested_vms: logging.debug("VM '%s' found in environment but not required for " "test; removing it..." % vm.name) vm.destroy() del env[key] # Get the KVM kernel module version and write it as a keyval logging.debug("Fetching KVM module version...") if os.path.exists("/dev/kvm"): try: kvm_version = open("/sys/module/kvm/version").read().strip() except: kvm_version = os.uname()[2] else: kvm_version = "Unknown" logging.debug("KVM module not loaded") logging.debug("KVM version: %s" % kvm_version) test.write_test_keyval({"kvm_version": kvm_version}) # Get the KVM userspace version and write it as a keyval logging.debug("Fetching KVM userspace version...") qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary", "qemu")) version_line = commands.getoutput("%s -help | head -n 1" % qemu_path) matches = re.findall("[Vv]ersion .*?,", version_line) if matches: kvm_userspace_version = " ".join(matches[0].split()[1:]).strip(",") else: kvm_userspace_version = "Unknown" logging.debug("Could not fetch KVM userspace version") logging.debug("KVM userspace version: %s" % kvm_userspace_version) test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version}) if params.get("setup_hugepages") == "yes": h = test_setup.HugePageConfig(params) h.setup() if params.get("type") == "unattended_install": u = test_setup.UnattendedInstallConfig(test, params) u.setup() if params.get("type") == "enospc": e = test_setup.EnospcConfig(test, params) e.setup() # Execute any pre_commands if params.get("pre_command"): process_command(test, params, env, params.get("pre_command"), int(params.get("pre_command_timeout", "600")), params.get("pre_command_noncritical") == "yes") # Preprocess all VMs and images process(test, params, env, preprocess_image, preprocess_vm) # Start the screendump thread if params.get("take_regular_screendumps") == "yes": logging.debug("Starting screendump thread") global _screendump_thread, _screendump_thread_termination_event _screendump_thread_termination_event = threading.Event() _screendump_thread = threading.Thread(target=_take_screendumps, args=(test, params, env)) _screendump_thread.start()
def _take_screendumps(test, params, env): global _screendump_thread_termination_event temp_dir = test.debugdir if params.get("screendump_temp_dir"): temp_dir = kvm_utils.get_path(test.bindir, params.get("screendump_temp_dir")) try: os.makedirs(temp_dir) except OSError: pass temp_filename = os.path.join( temp_dir, "scrdump-%s.ppm" % kvm_utils.generate_random_string(6)) delay = float(params.get("screendump_delay", 5)) quality = int(params.get("screendump_quality", 30)) cache = {} while True: for vm in env.get_all_vms(): if not vm.is_alive(): continue try: vm.monitor.screendump(temp_filename) except kvm_monitor.MonitorError, e: logging.warn(e) continue if not os.path.exists(temp_filename): logging.warn("VM '%s' failed to produce a screendump", vm.name) continue if not ppm_utils.image_verify_ppm_file(temp_filename): logging.warn("VM '%s' produced an invalid screendump", vm.name) os.unlink(temp_filename) continue screendump_dir = os.path.join(test.debugdir, "screendumps_%s" % vm.name) try: os.makedirs(screendump_dir) except OSError: pass screendump_filename = os.path.join( screendump_dir, "%s_%s.jpg" % (vm.name, time.strftime("%Y-%m-%d_%H-%M-%S"))) hash = utils.hash_file(temp_filename) if hash in cache: try: os.link(cache[hash], screendump_filename) except OSError: pass else: try: image = PIL.Image.open(temp_filename) image.save(screendump_filename, format="JPEG", quality=quality) cache[hash] = screendump_filename except NameError: pass os.unlink(temp_filename) if _screendump_thread_termination_event.isSet(): _screendump_thread_termination_event = None break _screendump_thread_termination_event.wait(delay)
def run_whql_submission(test, params, env): """ WHQL submission test: 1) Log into the guest (the client machine) and into a DTM server machine 2) Copy the automation program binary (dsso_test_binary) to the server machine 3) Run the automation program 4) Pass the program all relevant parameters (e.g. device_data) 5) Wait for the program to terminate 6) Parse and report job results (logs and HTML reports are placed in test.bindir) @param test: kvm test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ vm = kvm_test_utils.get_living_vm(env, params.get("main_vm")) session = kvm_test_utils.wait_for_login(vm, 0, 240) # Collect parameters server_address = params.get("server_address") server_shell_port = int(params.get("server_shell_port")) server_file_transfer_port = int(params.get("server_file_transfer_port")) server_studio_path = params.get("server_studio_path", "%programfiles%\\ " "Microsoft Driver Test Manager\\Studio") dsso_test_binary = params.get("dsso_test_binary", "deps/whql_submission_15.exe") dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary) test_device = params.get("test_device") job_filter = params.get("job_filter", ".*") test_timeout = float(params.get("test_timeout", 600)) wtt_services = params.get("wtt_services") # Restart WTT service(s) on the client logging.info("Restarting WTT services on client") for svc in wtt_services.split(): kvm_test_utils.stop_windows_service(session, svc) for svc in wtt_services.split(): kvm_test_utils.start_windows_service(session, svc) # Copy dsso_test_binary to the server rss_file_transfer.upload( server_address, server_file_transfer_port, dsso_test_binary, server_studio_path, timeout=60 ) # Open a shell session with the server server_session = kvm_utils.remote_login( "nc", server_address, server_shell_port, "", "", session.prompt, session.linesep ) server_session.set_status_test_command(session.status_test_command) # Get the computer names of the server and client cmd = "echo %computername%" server_name = server_session.cmd_output(cmd).strip() client_name = session.cmd_output(cmd).strip() session.close() # Run the automation program on the server server_session.cmd("cd %s" % server_studio_path) cmd = "%s %s %s %s %s %s" % ( os.path.basename(dsso_test_binary), server_name, client_name, "%s_pool" % client_name, "%s_submission" % client_name, test_timeout, ) server_session.sendline(cmd) # Helper function: wait for a given prompt and raise an exception if an # error occurs def find_prompt(prompt): m, o = server_session.read_until_last_line_matches( [prompt, server_session.prompt], print_func=logging.info, timeout=600 ) if m != 0: errors = re.findall("^Error:.*$", o, re.I | re.M) if errors: raise error.TestError(errors[0]) else: raise error.TestError("Error running automation program: " "could not find '%s' prompt" % prompt) # Tell the automation program which device to test find_prompt("Device to test:") server_session.sendline(test_device) # Tell the automation program which jobs to run find_prompt("Jobs to run:") server_session.sendline(job_filter) # Give the automation program all the device data supplied by the user find_prompt("DeviceData name:") for dd in kvm_utils.get_sub_dict_names(params, "device_data"): dd_params = kvm_utils.get_sub_dict(params, dd) if dd_params.get("dd_name") and dd_params.get("dd_data"): server_session.sendline(dd_params.get("dd_name")) server_session.sendline(dd_params.get("dd_data")) server_session.sendline() # Give the automation program all the descriptor information supplied by # the user find_prompt("Descriptor path:") for desc in kvm_utils.get_sub_dict_names(params, "descriptors"): desc_params = kvm_utils.get_sub_dict(params, desc) if desc_params.get("desc_path"): server_session.sendline(desc_params.get("desc_path")) server_session.sendline() # Wait for the automation program to terminate try: o = server_session.read_up_to_prompt(print_func=logging.info, timeout=test_timeout + 300) # (test_timeout + 300 is used here because the automation program is # supposed to terminate cleanly on its own when test_timeout expires) done = True except kvm_subprocess.ExpectError, e: o = e.output done = False
def run_whql_client_install(test, params, env): """ WHQL DTM client installation: 1) Log into the guest (the client machine) and into a DTM server machine 2) Stop the DTM client service (wttsvc) on the client machine 3) Delete the client machine from the server's data store 4) Rename the client machine (give it a randomly generated name) 5) Move the client machine into the server's workgroup 6) Reboot the client machine 7) Install the DTM client software 8) Setup auto logon for the user created by the installation (normally DTMLLUAdminUser) 9) Reboot again @param test: kvm test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ vm = env.get_vm(params["main_vm"]) vm.verify_alive() session = vm.wait_for_login(timeout=int(params.get("login_timeout", 360))) # Collect test params server_address = params.get("server_address") server_shell_port = int(params.get("server_shell_port")) server_file_transfer_port = int(params.get("server_file_transfer_port")) server_studio_path = params.get("server_studio_path", "%programfiles%\\ " "Microsoft Driver Test Manager\\Studio") server_username = params.get("server_username") server_password = params.get("server_password") client_username = params.get("client_username") client_password = params.get("client_password") dsso_delete_machine_binary = params.get("dsso_delete_machine_binary", "deps/whql_delete_machine_15.exe") dsso_delete_machine_binary = kvm_utils.get_path(test.bindir, dsso_delete_machine_binary) install_timeout = float(params.get("install_timeout", 600)) install_cmd = params.get("install_cmd") wtt_services = params.get("wtt_services") # Stop WTT service(s) on client for svc in wtt_services.split(): kvm_test_utils.stop_windows_service(session, svc) # Copy dsso_delete_machine_binary to server rss_file_transfer.upload(server_address, server_file_transfer_port, dsso_delete_machine_binary, server_studio_path, timeout=60) # Open a shell session with server server_session = kvm_utils.remote_login("nc", server_address, server_shell_port, "", "", session.prompt, session.linesep) server_session.set_status_test_command(session.status_test_command) # Get server and client information cmd = "echo %computername%" server_name = server_session.cmd_output(cmd).strip() client_name = session.cmd_output(cmd).strip() cmd = "wmic computersystem get domain" server_workgroup = server_session.cmd_output(cmd).strip() server_workgroup = server_workgroup.splitlines()[-1] regkey = r"HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" cmd = "reg query %s /v Domain" % regkey o = server_session.cmd_output(cmd).strip().splitlines()[-1] try: server_dns_suffix = o.split(None, 2)[2] except IndexError: server_dns_suffix = "" # Delete the client machine from the server's data store (if it's there) server_session.cmd("cd %s" % server_studio_path) cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary), server_name, client_name) server_session.cmd(cmd, print_func=logging.info) server_session.close() # Rename the client machine client_name = "autotest_%s" % kvm_utils.generate_random_string(4) logging.info("Renaming client machine to '%s'", client_name) cmd = ('wmic computersystem where name="%%computername%%" rename name="%s"' % client_name) session.cmd(cmd, timeout=600) # Join the server's workgroup logging.info("Joining workgroup '%s'", server_workgroup) cmd = ('wmic computersystem where name="%%computername%%" call ' 'joindomainorworkgroup name="%s"' % server_workgroup) session.cmd(cmd, timeout=600) # Set the client machine's DNS suffix logging.info("Setting DNS suffix to '%s'", server_dns_suffix) cmd = 'reg add %s /v Domain /d "%s" /f' % (regkey, server_dns_suffix) session.cmd(cmd, timeout=300) # Reboot session = vm.reboot(session) # Access shared resources on the server machine logging.info("Attempting to access remote share on server") cmd = r"net use \\%s /user:%s %s" % (server_name, server_username, server_password) end_time = time.time() + 120 while time.time() < end_time: try: session.cmd(cmd) break except: pass time.sleep(5) else: raise error.TestError("Could not access server share from client " "machine") # Install logging.info("Installing DTM client (timeout=%ds)", install_timeout) install_cmd = r"cmd /c \\%s\%s" % (server_name, install_cmd.lstrip("\\")) session.cmd(install_cmd, timeout=install_timeout) # Setup auto logon logging.info("Setting up auto logon for user '%s'", client_username) cmd = ('reg add ' '"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon" ' '/v "%s" /d "%s" /t REG_SZ /f') session.cmd(cmd % ("AutoAdminLogon", "1")) session.cmd(cmd % ("DefaultUserName", client_username)) session.cmd(cmd % ("DefaultPassword", client_password)) # Reboot one more time session = vm.reboot(session) session.close()
def run_whql_submission(test, params, env): """ WHQL submission test: 1) Log into the client machines and into a DTM server machine 2) Copy the automation program binary (dsso_test_binary) to the server machine 3) Run the automation program 4) Pass the program all relevant parameters (e.g. device_data) 5) Wait for the program to terminate 6) Parse and report job results (logs and HTML reports are placed in test.debugdir) @param test: kvm test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ # Log into all client VMs login_timeout = int(params.get("login_timeout", 360)) vms = [] sessions = [] for vm_name in params.objects("vms"): vms.append(env.get_vm(vm_name)) vms[-1].verify_alive() sessions.append(vms[-1].wait_for_login(timeout=login_timeout)) # Make sure all NICs of all client VMs are up for vm in vms: nics = vm.params.objects("nics") for nic_index in range(len(nics)): s = vm.wait_for_login(nic_index, 600) s.close() # Collect parameters server_address = params.get("server_address") server_shell_port = int(params.get("server_shell_port")) server_file_transfer_port = int(params.get("server_file_transfer_port")) server_studio_path = params.get("server_studio_path", "%programfiles%\\ " "Microsoft Driver Test Manager\\Studio") dsso_test_binary = params.get("dsso_test_binary", "deps/whql_submission_15.exe") dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary) dsso_delete_machine_binary = params.get("dsso_delete_machine_binary", "deps/whql_delete_machine_15.exe") dsso_delete_machine_binary = kvm_utils.get_path(test.bindir, dsso_delete_machine_binary) test_timeout = float(params.get("test_timeout", 600)) # Copy dsso binaries to the server for filename in dsso_test_binary, dsso_delete_machine_binary: rss_file_transfer.upload(server_address, server_file_transfer_port, filename, server_studio_path, timeout=60) # Open a shell session with the server server_session = kvm_utils.remote_login("nc", server_address, server_shell_port, "", "", sessions[0].prompt, sessions[0].linesep) server_session.set_status_test_command(sessions[0].status_test_command) # Get the computer names of the server and clients cmd = "echo %computername%" server_name = server_session.cmd_output(cmd).strip() client_names = [session.cmd_output(cmd).strip() for session in sessions] # Delete all client machines from the server's data store server_session.cmd("cd %s" % server_studio_path) for client_name in client_names: cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary), server_name, client_name) server_session.cmd(cmd, print_func=logging.debug) # Reboot the client machines sessions = kvm_utils.parallel((vm.reboot, (session,)) for vm, session in zip(vms, sessions)) # Check the NICs again for vm in vms: nics = vm.params.objects("nics") for nic_index in range(len(nics)): s = vm.wait_for_login(nic_index, 600) s.close() # Run whql_pre_command and close the sessions if params.get("whql_pre_command"): for session in sessions: session.cmd(params.get("whql_pre_command"), int(params.get("whql_pre_command_timeout", 600))) session.close() # Run the automation program on the server pool_name = "%s_pool" % client_names[0] submission_name = "%s_%s" % (client_names[0], params.get("submission_name")) cmd = "%s %s %s %s %s %s" % (os.path.basename(dsso_test_binary), server_name, pool_name, submission_name, test_timeout, " ".join(client_names)) server_session.sendline(cmd) # Helper function: wait for a given prompt and raise an exception if an # error occurs def find_prompt(prompt): m, o = server_session.read_until_last_line_matches( [prompt, server_session.prompt], print_func=logging.info, timeout=600) if m != 0: errors = re.findall("^Error:.*$", o, re.I | re.M) if errors: raise error.TestError(errors[0]) else: raise error.TestError("Error running automation program: " "could not find '%s' prompt" % prompt) # Tell the automation program which device to test find_prompt("Device to test:") server_session.sendline(params.get("test_device")) # Tell the automation program which jobs to run find_prompt("Jobs to run:") server_session.sendline(params.get("job_filter", ".*")) # Set submission DeviceData find_prompt("DeviceData name:") for dd in params.objects("device_data"): dd_params = params.object_params(dd) if dd_params.get("dd_name") and dd_params.get("dd_data"): server_session.sendline(dd_params.get("dd_name")) server_session.sendline(dd_params.get("dd_data")) server_session.sendline() # Set submission descriptors find_prompt("Descriptor path:") for desc in params.objects("descriptors"): desc_params = params.object_params(desc) if desc_params.get("desc_path"): server_session.sendline(desc_params.get("desc_path")) server_session.sendline() # Set machine dimensions for each client machine for vm_name in params.objects("vms"): vm_params = params.object_params(vm_name) find_prompt(r"Dimension name\b.*:") for dp in vm_params.objects("dimensions"): dp_params = vm_params.object_params(dp) if dp_params.get("dim_name") and dp_params.get("dim_value"): server_session.sendline(dp_params.get("dim_name")) server_session.sendline(dp_params.get("dim_value")) server_session.sendline() # Set extra parameters for tests that require them (e.g. NDISTest) for vm_name in params.objects("vms"): vm_params = params.object_params(vm_name) find_prompt(r"Parameter name\b.*:") for dp in vm_params.objects("device_params"): dp_params = vm_params.object_params(dp) if dp_params.get("dp_name") and dp_params.get("dp_regex"): server_session.sendline(dp_params.get("dp_name")) server_session.sendline(dp_params.get("dp_regex")) # Make sure the prompt appears again (if the device isn't found # the automation program will terminate) find_prompt(r"Parameter name\b.*:") server_session.sendline() # Wait for the automation program to terminate try: o = server_session.read_up_to_prompt(print_func=logging.info, timeout=test_timeout + 300) # (test_timeout + 300 is used here because the automation program is # supposed to terminate cleanly on its own when test_timeout expires) done = True except kvm_subprocess.ExpectError, e: o = e.output done = False
def run_steps(test, params, env): vm = env.get_vm(params.get("main_vm")) if not vm: raise error.TestError("VM object not found in environment") if not vm.is_alive(): e_msg = "VM seems to be dead. Guestwizard requires a living VM" raise error.TestError(e_msg) steps_filename = params.get("steps") if not steps_filename: raise error.TestError("Steps filename not specified") steps_filename = kvm_utils.get_path(test.bindir, steps_filename) if not os.path.exists(steps_filename): raise error.TestError("Steps file not found: %s" % steps_filename) sf = open(steps_filename, "r") lines = sf.readlines() sf.close() vm.monitor.cmd("cont") current_step_num = 0 current_screendump = None skip_current_step = False # Iterate over the lines in the file for line in lines: line = line.strip() if not line: continue logging.info(line) if line.startswith("#"): continue words = line.split() if words[0] == "step": current_step_num += 1 current_screendump = None skip_current_step = False elif words[0] == "screendump": current_screendump = words[1] elif skip_current_step: continue elif words[0] == "sleep": timeout_multiplier = float(params.get("timeout_multiplier") or 1) time.sleep(float(words[1]) * timeout_multiplier) elif words[0] == "key": vm.send_key(words[1]) elif words[0] == "var": if not handle_var(vm, params, words[1]): logging.error("Variable not defined: %s", words[1]) elif words[0] == "barrier_2": if current_screendump: scrdump_filename = os.path.join( ppm_utils.get_data_dir(steps_filename), current_screendump) else: scrdump_filename = None if not barrier_2(vm, words, params, test.debugdir, scrdump_filename, current_step_num): skip_current_step = True else: vm.send_key(words[0])
def preprocess(test, params, env): """ Preprocess all VMs and images according to the instructions in params. Also, collect some host information, such as the KVM version. @param test: An Autotest test object. @param params: A dict containing all VM and image parameters. @param env: The environment (a dict-like object). """ error.context("preprocessing") # Start tcpdump if it isn't already running if "address_cache" not in env: env["address_cache"] = {} if "tcpdump" in env and not env["tcpdump"].is_alive(): env["tcpdump"].close() del env["tcpdump"] if "tcpdump" not in env and params.get("run_tcpdump", "yes") == "yes": cmd = "%s -npvi any 'dst port 68'" % kvm_utils.find_command("tcpdump") logging.debug("Starting tcpdump (%s)...", cmd) env["tcpdump"] = kvm_subprocess.Tail( command=cmd, output_func=_update_address_cache, output_params=(env["address_cache"],)) if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(), 0.1, 0.1, 1.0): logging.warn("Could not start tcpdump") logging.warn("Status: %s" % env["tcpdump"].get_status()) logging.warn("Output:" + kvm_utils.format_str_for_message( env["tcpdump"].get_output())) # Destroy and remove VMs that are no longer needed in the environment requested_vms = params.objects("vms") for key in env.keys(): vm = env[key] if not kvm_utils.is_vm(vm): continue if not vm.name in requested_vms: logging.debug("VM '%s' found in environment but not required for " "test; removing it..." % vm.name) vm.destroy() del env[key] # Get the KVM kernel module version and write it as a keyval logging.debug("Fetching KVM module version...") if os.path.exists("/dev/kvm"): try: kvm_version = open("/sys/module/kvm/version").read().strip() except: kvm_version = os.uname()[2] else: kvm_version = "Unknown" logging.debug("KVM module not loaded") logging.debug("KVM version: %s" % kvm_version) test.write_test_keyval({"kvm_version": kvm_version}) # Get the KVM userspace version and write it as a keyval logging.debug("Fetching KVM userspace version...") qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary", "qemu")) version_line = commands.getoutput("%s -help | head -n 1" % qemu_path) matches = re.findall("[Vv]ersion .*?,", version_line) if matches: kvm_userspace_version = " ".join(matches[0].split()[1:]).strip(",") else: kvm_userspace_version = "Unknown" logging.debug("Could not fetch KVM userspace version") logging.debug("KVM userspace version: %s" % kvm_userspace_version) test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version}) if params.get("setup_hugepages") == "yes": h = test_setup.HugePageConfig(params) h.setup() if params.get("type") == "unattended_install": u = test_setup.UnattendedInstallConfig(test, params) u.setup() if params.get("type") == "enospc": e = test_setup.EnospcConfig(test, params) e.setup() # Execute any pre_commands if params.get("pre_command"): process_command(test, params, env, params.get("pre_command"), int(params.get("pre_command_timeout", "600")), params.get("pre_command_noncritical") == "yes") # Preprocess all VMs and images process(test, params, env, preprocess_image, preprocess_vm) # Start the screendump thread if params.get("take_regular_screendumps") == "yes": logging.debug("Starting screendump thread") global _screendump_thread, _screendump_thread_termination_event _screendump_thread_termination_event = threading.Event() _screendump_thread = threading.Thread(target=_take_screendumps, args=(test, params, env)) _screendump_thread.start()
def make_qemu_command(self, name=None, params=None, root_dir=None): """ Generate a qemu command line. All parameters are optional. If a parameter is not supplied, the corresponding value stored in the class attributes is used. @param name: The name of the object @param params: A dict containing VM params @param root_dir: Base directory for relative filenames @note: The params dict should contain: mem -- memory size in MBs cdrom -- ISO filename to use with the qemu -cdrom parameter extra_params -- a string to append to the qemu command shell_port -- port of the remote shell daemon on the guest (SSH, Telnet or the home-made Remote Shell Server) shell_client -- client program to use for connecting to the remote shell daemon on the guest (ssh, telnet or nc) x11_display -- if specified, the DISPLAY environment variable will be be set to this value for the qemu process (useful for SDL rendering) images -- a list of image object names, separated by spaces nics -- a list of NIC object names, separated by spaces For each image in images: drive_format -- string to pass as 'if' parameter for this image (e.g. ide, scsi) image_snapshot -- if yes, pass 'snapshot=on' to qemu for this image image_boot -- if yes, pass 'boot=on' to qemu for this image In addition, all parameters required by get_image_filename. For each NIC in nics: nic_model -- string to pass as 'model' parameter for this NIC (e.g. e1000) """ # Helper function for command line option wrappers def has_option(help, option): return bool(re.search(r"^-%s(\s|$)" % option, help, re.MULTILINE)) # Wrappers for all supported qemu command line parameters. # This is meant to allow support for multiple qemu versions. # Each of these functions receives the output of 'qemu -help' as a # parameter, and should add the requested command line option # accordingly. def add_name(help, name): return " -name '%s'" % name def add_human_monitor(help, filename): return " -monitor unix:'%s',server,nowait" % filename def add_qmp_monitor(help, filename): return " -qmp unix:'%s',server,nowait" % filename def add_serial(help, filename): return " -serial unix:'%s',server,nowait" % filename def add_mem(help, mem): return " -m %s" % mem def add_smp(help, smp): return " -smp %s" % smp def add_cdrom(help, filename, index=None): if has_option(help, "drive"): cmd = " -drive file='%s',media=cdrom" % filename if index is not None: cmd += ",index=%s" % index return cmd else: return " -cdrom '%s'" % filename def add_drive(help, filename, index=None, format=None, cache=None, werror=None, serial=None, snapshot=False, boot=False): cmd = " -drive file='%s'" % filename if index is not None: cmd += ",index=%s" % index if format: cmd += ",if=%s" % format if cache: cmd += ",cache=%s" % cache if werror: cmd += ",werror=%s" % werror if serial: cmd += ",serial='%s'" % serial if snapshot: cmd += ",snapshot=on" if boot: cmd += ",boot=on" return cmd def add_nic(help, vlan, model=None, mac=None, netdev_id=None, nic_extra_params=None): if has_option(help, "netdev"): netdev_vlan_str = ",netdev=%s" % netdev_id else: netdev_vlan_str = ",vlan=%d" % vlan if has_option(help, "device"): if not model: model = "rtl8139" elif model == "virtio": model = "virtio-net-pci" cmd = " -device %s" % model + netdev_vlan_str if mac: cmd += ",mac='%s'" % mac if nic_extra_params: cmd += ",%s" % nic_extra_params else: cmd = " -net nic" + netdev_vlan_str if model: cmd += ",model=%s" % model if mac: cmd += ",macaddr='%s'" % mac return cmd def add_net(help, vlan, mode, ifname=None, script=None, downscript=None, tftp=None, bootfile=None, hostfwd=[], netdev_id=None, netdev_extra_params=None): if has_option(help, "netdev"): cmd = " -netdev %s,id=%s" % (mode, netdev_id) if netdev_extra_params: cmd += ",%s" % netdev_extra_params else: cmd = " -net %s,vlan=%d" % (mode, vlan) if mode == "tap": if ifname: cmd += ",ifname='%s'" % ifname if script: cmd += ",script='%s'" % script cmd += ",downscript='%s'" % (downscript or "no") elif mode == "user": if tftp and "[,tftp=" in help: cmd += ",tftp='%s'" % tftp if bootfile and "[,bootfile=" in help: cmd += ",bootfile='%s'" % bootfile if "[,hostfwd=" in help: for host_port, guest_port in hostfwd: cmd += ",hostfwd=tcp::%s-:%s" % (host_port, guest_port) return cmd def add_floppy(help, filename): return " -fda '%s'" % filename def add_tftp(help, filename): # If the new syntax is supported, don't add -tftp if "[,tftp=" in help: return "" else: return " -tftp '%s'" % filename def add_bootp(help, filename): # If the new syntax is supported, don't add -bootp if "[,bootfile=" in help: return "" else: return " -bootp '%s'" % filename def add_tcp_redir(help, host_port, guest_port): # If the new syntax is supported, don't add -redir if "[,hostfwd=" in help: return "" else: return " -redir tcp:%s::%s" % (host_port, guest_port) def add_vnc(help, vnc_port): return " -vnc :%d" % (vnc_port - 5900) def add_sdl(help): if has_option(help, "sdl"): return " -sdl" else: return "" def add_nographic(help): return " -nographic" def add_uuid(help, uuid): return " -uuid '%s'" % uuid def add_pcidevice(help, host): return " -pcidevice host='%s'" % host def add_kernel(help, filename): return " -kernel '%s'" % filename def add_initrd(help, filename): return " -initrd '%s'" % filename def add_kernel_cmdline(help, cmdline): return " -append %s" % cmdline def add_testdev(help, filename): return (" -chardev file,id=testlog,path=%s" " -device testdev,chardev=testlog" % filename) def add_no_hpet(help): if has_option(help, "no-hpet"): return " -no-hpet" else: return "" # End of command line option wrappers if name is None: name = self.name if params is None: params = self.params if root_dir is None: root_dir = self.root_dir qemu_binary = kvm_utils.get_path(root_dir, params.get("qemu_binary", "qemu")) # Get the output of 'qemu -help' (log a message in case this call never # returns or causes some other kind of trouble) logging.debug("Getting output of 'qemu -help'") help = commands.getoutput("%s -help" % qemu_binary) # Start constructing the qemu command qemu_cmd = "" # Set the X11 display parameter if requested if params.get("x11_display"): qemu_cmd += "DISPLAY=%s " % params.get("x11_display") # Add the qemu binary qemu_cmd += qemu_binary # Add the VM's name qemu_cmd += add_name(help, name) # Add monitors for monitor_name in kvm_utils.get_sub_dict_names(params, "monitors"): monitor_params = kvm_utils.get_sub_dict(params, monitor_name) monitor_filename = self.get_monitor_filename(monitor_name) if monitor_params.get("monitor_type") == "qmp": qemu_cmd += add_qmp_monitor(help, monitor_filename) else: qemu_cmd += add_human_monitor(help, monitor_filename) # Add serial console redirection qemu_cmd += add_serial(help, self.get_serial_console_filename()) for image_name in kvm_utils.get_sub_dict_names(params, "images"): image_params = kvm_utils.get_sub_dict(params, image_name) if image_params.get("boot_drive") == "no": continue qemu_cmd += add_drive(help, get_image_filename(image_params, root_dir), image_params.get("drive_index"), image_params.get("drive_format"), image_params.get("drive_cache"), image_params.get("drive_werror"), image_params.get("drive_serial"), image_params.get("image_snapshot") == "yes", image_params.get("image_boot") == "yes") redirs = [] for redir_name in kvm_utils.get_sub_dict_names(params, "redirs"): redir_params = kvm_utils.get_sub_dict(params, redir_name) guest_port = int(redir_params.get("guest_port")) host_port = self.redirs.get(guest_port) redirs += [(host_port, guest_port)] vlan = 0 for nic_name in kvm_utils.get_sub_dict_names(params, "nics"): nic_params = kvm_utils.get_sub_dict(params, nic_name) # Handle the '-net nic' part mac = self.get_mac_address(vlan) qemu_cmd += add_nic(help, vlan, nic_params.get("nic_model"), mac, self.netdev_id[vlan], nic_params.get("nic_extra_params")) # Handle the '-net tap' or '-net user' part script = nic_params.get("nic_script") downscript = nic_params.get("nic_downscript") tftp = nic_params.get("tftp") if script: script = kvm_utils.get_path(root_dir, script) if downscript: downscript = kvm_utils.get_path(root_dir, downscript) if tftp: tftp = kvm_utils.get_path(root_dir, tftp) qemu_cmd += add_net(help, vlan, nic_params.get("nic_mode", "user"), self.get_ifname(vlan), script, downscript, tftp, nic_params.get("bootp"), redirs, self.netdev_id[vlan], nic_params.get("netdev_extra_params")) # Proceed to next NIC vlan += 1 mem = params.get("mem") if mem: qemu_cmd += add_mem(help, mem) smp = params.get("smp") if smp: qemu_cmd += add_smp(help, smp) cdroms = kvm_utils.get_sub_dict_names(params, "cdroms") for cdrom in cdroms: cdrom_params = kvm_utils.get_sub_dict(params, cdrom) iso = cdrom_params.get("cdrom") if iso: qemu_cmd += add_cdrom(help, kvm_utils.get_path(root_dir, iso), cdrom_params.get("drive_index")) # We may want to add {floppy_otps} parameter for -fda # {fat:floppy:}/path/. However vvfat is not usually recommended. floppy = params.get("floppy") if floppy: floppy = kvm_utils.get_path(root_dir, floppy) qemu_cmd += add_floppy(help, floppy) tftp = params.get("tftp") if tftp: tftp = kvm_utils.get_path(root_dir, tftp) qemu_cmd += add_tftp(help, tftp) bootp = params.get("bootp") if bootp: qemu_cmd += add_bootp(help, bootp) kernel = params.get("kernel") if kernel: kernel = kvm_utils.get_path(root_dir, kernel) qemu_cmd += add_kernel(help, kernel) kernel_cmdline = params.get("kernel_cmdline") if kernel_cmdline: qemu_cmd += add_kernel_cmdline(help, kernel_cmdline) initrd = params.get("initrd") if initrd: initrd = kvm_utils.get_path(root_dir, initrd) qemu_cmd += add_initrd(help, initrd) for host_port, guest_port in redirs: qemu_cmd += add_tcp_redir(help, host_port, guest_port) if params.get("display") == "vnc": qemu_cmd += add_vnc(help, self.vnc_port) elif params.get("display") == "sdl": qemu_cmd += add_sdl(help) elif params.get("display") == "nographic": qemu_cmd += add_nographic(help) if params.get("uuid") == "random": qemu_cmd += add_uuid(help, self.uuid) elif params.get("uuid"): qemu_cmd += add_uuid(help, params.get("uuid")) if params.get("testdev") == "yes": qemu_cmd += add_testdev(help, self.get_testlog_filename()) if params.get("disable_hpet") == "yes": qemu_cmd += add_no_hpet(help) # If the PCI assignment step went OK, add each one of the PCI assigned # devices to the qemu command line. if self.pci_assignable: for pci_id in self.pa_pci_ids: qemu_cmd += add_pcidevice(help, pci_id) extra_params = params.get("extra_params") if extra_params: qemu_cmd += " %s" % extra_params return qemu_cmd
def run_whql_submission(test, params, env): """ WHQL submission test: 1) Log into the client machines and into a DTM server machine 2) Copy the automation program binary (dsso_test_binary) to the server machine 3) Run the automation program 4) Pass the program all relevant parameters (e.g. device_data) 5) Wait for the program to terminate 6) Parse and report job results (logs and HTML reports are placed in test.debugdir) @param test: kvm test object @param params: Dictionary with the test parameters @param env: Dictionary with test environment. """ # Log into all client VMs login_timeout = int(params.get("login_timeout", 360)) vms = [] sessions = [] for vm_name in params.objects("vms"): vms.append(env.get_vm(vm_name)) vms[-1].verify_alive() sessions.append(vms[-1].wait_for_login(timeout=login_timeout)) # Make sure all NICs of all client VMs are up for vm in vms: nics = vm.params.objects("nics") for nic_index in range(len(nics)): s = vm.wait_for_login(nic_index, 600) s.close() # Collect parameters server_address = params.get("server_address") server_shell_port = int(params.get("server_shell_port")) server_file_transfer_port = int(params.get("server_file_transfer_port")) server_studio_path = params.get( "server_studio_path", "%programfiles%\\ " "Microsoft Driver Test Manager\\Studio") dsso_test_binary = params.get("dsso_test_binary", "deps/whql_submission_15.exe") dsso_test_binary = kvm_utils.get_path(test.bindir, dsso_test_binary) dsso_delete_machine_binary = params.get("dsso_delete_machine_binary", "deps/whql_delete_machine_15.exe") dsso_delete_machine_binary = kvm_utils.get_path( test.bindir, dsso_delete_machine_binary) test_timeout = float(params.get("test_timeout", 600)) # Copy dsso binaries to the server for filename in dsso_test_binary, dsso_delete_machine_binary: rss_file_transfer.upload(server_address, server_file_transfer_port, filename, server_studio_path, timeout=60) # Open a shell session with the server server_session = kvm_utils.remote_login("nc", server_address, server_shell_port, "", "", sessions[0].prompt, sessions[0].linesep) server_session.set_status_test_command(sessions[0].status_test_command) # Get the computer names of the server and clients cmd = "echo %computername%" server_name = server_session.cmd_output(cmd).strip() client_names = [session.cmd_output(cmd).strip() for session in sessions] # Delete all client machines from the server's data store server_session.cmd("cd %s" % server_studio_path) for client_name in client_names: cmd = "%s %s %s" % (os.path.basename(dsso_delete_machine_binary), server_name, client_name) server_session.cmd(cmd, print_func=logging.debug) # Reboot the client machines sessions = kvm_utils.parallel( (vm.reboot, (session, )) for vm, session in zip(vms, sessions)) # Check the NICs again for vm in vms: nics = vm.params.objects("nics") for nic_index in range(len(nics)): s = vm.wait_for_login(nic_index, 600) s.close() # Run whql_pre_command and close the sessions if params.get("whql_pre_command"): for session in sessions: session.cmd(params.get("whql_pre_command"), int(params.get("whql_pre_command_timeout", 600))) session.close() # Run the automation program on the server pool_name = "%s_pool" % client_names[0] submission_name = "%s_%s" % (client_names[0], params.get("submission_name")) cmd = "%s %s %s %s %s %s" % (os.path.basename(dsso_test_binary), server_name, pool_name, submission_name, test_timeout, " ".join(client_names)) server_session.sendline(cmd) # Helper function: wait for a given prompt and raise an exception if an # error occurs def find_prompt(prompt): m, o = server_session.read_until_last_line_matches( [prompt, server_session.prompt], print_func=logging.info, timeout=600) if m != 0: errors = re.findall("^Error:.*$", o, re.I | re.M) if errors: raise error.TestError(errors[0]) else: raise error.TestError("Error running automation program: " "could not find '%s' prompt" % prompt) # Tell the automation program which device to test find_prompt("Device to test:") server_session.sendline(params.get("test_device")) # Tell the automation program which jobs to run find_prompt("Jobs to run:") server_session.sendline(params.get("job_filter", ".*")) # Set submission DeviceData find_prompt("DeviceData name:") for dd in params.objects("device_data"): dd_params = params.object_params(dd) if dd_params.get("dd_name") and dd_params.get("dd_data"): server_session.sendline(dd_params.get("dd_name")) server_session.sendline(dd_params.get("dd_data")) server_session.sendline() # Set submission descriptors find_prompt("Descriptor path:") for desc in params.objects("descriptors"): desc_params = params.object_params(desc) if desc_params.get("desc_path"): server_session.sendline(desc_params.get("desc_path")) server_session.sendline() # Set machine dimensions for each client machine for vm_name in params.objects("vms"): vm_params = params.object_params(vm_name) find_prompt(r"Dimension name\b.*:") for dp in vm_params.objects("dimensions"): dp_params = vm_params.object_params(dp) if dp_params.get("dim_name") and dp_params.get("dim_value"): server_session.sendline(dp_params.get("dim_name")) server_session.sendline(dp_params.get("dim_value")) server_session.sendline() # Set extra parameters for tests that require them (e.g. NDISTest) for vm_name in params.objects("vms"): vm_params = params.object_params(vm_name) find_prompt(r"Parameter name\b.*:") for dp in vm_params.objects("device_params"): dp_params = vm_params.object_params(dp) if dp_params.get("dp_name") and dp_params.get("dp_regex"): server_session.sendline(dp_params.get("dp_name")) server_session.sendline(dp_params.get("dp_regex")) # Make sure the prompt appears again (if the device isn't found # the automation program will terminate) find_prompt(r"Parameter name\b.*:") server_session.sendline() # Wait for the automation program to terminate try: o = server_session.read_up_to_prompt(print_func=logging.info, timeout=test_timeout + 300) # (test_timeout + 300 is used here because the automation program is # supposed to terminate cleanly on its own when test_timeout expires) done = True except kvm_subprocess.ExpectError, e: o = e.output done = False
def preprocess(test, params, env): """ Preprocess all VMs and images according to the instructions in params. Also, collect some host information, such as the KVM version. @param test: An Autotest test object. @param params: A dict containing all VM and image parameters. @param env: The environment (a dict-like object). """ # Start tcpdump if it isn't already running if not env.has_key("address_cache"): env["address_cache"] = {} if env.has_key("tcpdump") and not env["tcpdump"].is_alive(): env["tcpdump"].close() del env["tcpdump"] if not env.has_key("tcpdump"): command = "/usr/sbin/tcpdump -npvi any 'dst port 68'" logging.debug("Starting tcpdump (%s)...", command) env["tcpdump"] = kvm_subprocess.kvm_tail( command=command, output_func=_update_address_cache, output_params=(env["address_cache"],)) if kvm_utils.wait_for(lambda: not env["tcpdump"].is_alive(), 0.1, 0.1, 1.0): logging.warn("Could not start tcpdump") logging.warn("Status: %s" % env["tcpdump"].get_status()) logging.warn("Output:" + kvm_utils.format_str_for_message( env["tcpdump"].get_output())) # Destroy and remove VMs that are no longer needed in the environment requested_vms = kvm_utils.get_sub_dict_names(params, "vms") for key in env.keys(): vm = env[key] if not kvm_utils.is_vm(vm): continue if not vm.name in requested_vms: logging.debug("VM '%s' found in environment but not required for" " test; removing it..." % vm.name) vm.destroy() del env[key] # Execute any pre_commands if params.get("pre_command"): process_command(test, params, env, params.get("pre_command"), int(params.get("pre_command_timeout", "600")), params.get("pre_command_noncritical") == "yes") # Preprocess all VMs and images process(test, params, env, preprocess_image, preprocess_vm) # Get the KVM kernel module version and write it as a keyval logging.debug("Fetching KVM module version...") if os.path.exists("/dev/kvm"): kvm_version = os.uname()[2] try: file = open("/sys/module/kvm/version", "r") kvm_version = file.read().strip() file.close() except: pass else: kvm_version = "Unknown" logging.debug("KVM module not loaded") logging.debug("KVM version: %s" % kvm_version) test.write_test_keyval({"kvm_version": kvm_version}) # Get the KVM userspace version and write it as a keyval logging.debug("Fetching KVM userspace version...") qemu_path = kvm_utils.get_path(test.bindir, params.get("qemu_binary", "qemu")) version_line = commands.getoutput("%s -help | head -n 1" % qemu_path) exp = re.compile("[Vv]ersion .*?,") match = exp.search(version_line) if match: kvm_userspace_version = " ".join(match.group().split()[1:]).strip(",") else: kvm_userspace_version = "Unknown" logging.debug("Could not fetch KVM userspace version") logging.debug("KVM userspace version: %s" % kvm_userspace_version) test.write_test_keyval({"kvm_userspace_version": kvm_userspace_version})