def nic_add(vm, model, netdev_id, mac, rom=None): """ Add a nic to virtual machine @vm: VM object @model: nic model @netdev_id: id of netdev @mac: Mac address of new nic @rom: Rom file """ nic_id = kvm_utils.generate_random_id() if model == "virtio": model = "virtio-net-pci" device_add_cmd = "device_add %s,netdev=%s,mac=%s,id=%s" % ( model, netdev_id, mac, nic_id) if rom: device_add_cmd += ",romfile=%s" % rom logging.info("Adding nic through %s", device_add_cmd) vm.monitor.cmd(device_add_cmd) qdev = vm.monitor.info("qtree") if not nic_id in qdev: logging.error(qdev) raise error.TestFail("Device %s was not plugged into qdev" "tree" % nic_id) else: return nic_id
def nic_add(vm, model, netdev_id, mac): """ Add a nic to virtual machine @vm: VM object @model: nic model @netdev_id: id of netdev @mac: Mac address of new nic """ nic_id = kvm_utils.generate_random_id() if model == "virtio": model = "virtio-net-pci" device_add_cmd = "device_add %s,netdev=%s,mac=%s,id=%s" % (model, netdev_id, mac, nic_id) logging.info("Adding nic through %s", device_add_cmd) vm.monitor.cmd(device_add_cmd) qdev = vm.monitor.info("qtree") if id not in qdev: logging.error(qdev) raise error.TestFail("Device %s was not plugged into qdev" "tree" % nic_id) else: return nic_id
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_pci_hotplug(test, params, env): """ Test hotplug of PCI devices. (Elements between [] are configurable test parameters) 1) PCI add a deivce (NIC / block) 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. @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() timeout = int(params.get("login_timeout", 360)) session = vm.wait_for_login(timeout=timeout) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.cmd("modprobe %s" % module) # Get output of command 'info pci' as reference info_pci_ref = vm.monitor.info("pci") # Get output of command as reference reference = session.cmd_output(params.get("reference_cmd")) tested_model = params.get("pci_model") test_type = params.get("pci_type") image_format = params.get("image_format_stg") # Probe qemu to verify what is the supported syntax for PCI hotplug cmd_output = vm.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") # Determine syntax of drive hotplug # __com.redhat_drive_add == qemu-kvm-0.12 on RHEL 6 if len(re.findall("\n__com.redhat_drive_add", cmd_output)) > 0: drive_cmd_type = "__com.redhat_drive_add" # drive_add == qemu-kvm-0.13 onwards elif len(re.findall("\ndrive_add", cmd_output)) > 0: drive_cmd_type = "drive_add" else: raise error.TestError("Unknow version of qemu") # Probe qemu for a list of supported devices devices_support = vm.monitor.cmd("%s ?" % cmd_type) if cmd_type == "pci_add": if test_type == "nic": pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % tested_model elif test_type == "block": image_params = params.object_params("stg") image_filename = kvm_vm.get_image_filename(image_params, test.bindir) pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" % (image_filename, tested_model)) # Execute pci_add (should be replaced by a proper monitor method call) add_output = vm.monitor.cmd(pci_add_cmd) if not "OK domain" in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) after_add = vm.monitor.info("pci") elif cmd_type == "device_add": driver_id = test_type + "-" + kvm_utils.generate_random_id() device_id = test_type + "-" + kvm_utils.generate_random_id() if test_type == "nic": if tested_model == "virtio": tested_model = "virtio-net-pci" pci_add_cmd = "device_add id=%s,driver=%s" % (device_id, tested_model) elif test_type == "block": image_params = params.object_params("stg") image_filename = kvm_vm.get_image_filename(image_params, test.bindir) controller_model = None if tested_model == "virtio": tested_model = "virtio-blk-pci" if tested_model == "scsi": tested_model = "scsi-disk" controller_model = "lsi53c895a" if len(re.findall(controller_model, devices_support)) == 0: raise error.TestError("scsi controller device (%s) not " "supported by qemu" % controller_model) if controller_model is not None: controller_id = "controller-" + device_id controller_add_cmd = ("device_add %s,id=%s" % (controller_model, controller_id)) vm.monitor.cmd(controller_add_cmd) if drive_cmd_type == "drive_add": driver_add_cmd = ("drive_add auto " "file=%s,if=none,id=%s,format=%s" % (image_filename, driver_id, image_format)) elif drive_cmd_type == "__com.redhat_drive_add": driver_add_cmd = ("__com.redhat_drive_add " "file=%s,format=%s,id=%s" % (image_filename, image_format, driver_id)) pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" % (device_id, tested_model, driver_id)) vm.monitor.cmd(driver_add_cmd) # Check if the device is support in qemu if len(re.findall(tested_model, devices_support)) > 0: add_output = vm.monitor.cmd(pci_add_cmd) else: raise error.TestError("%s doesn't support device: %s" % (cmd_type, tested_model)) after_add = vm.monitor.info("pci") if not device_id in after_add: raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) # Define a helper function to delete the device def pci_del(ignore_failure=False): if cmd_type == "pci_add": result_domain, bus, slot, function = add_output.split(',') domain = int(result_domain.split()[2]) bus = int(bus.split()[1]) slot = int(slot.split()[1]) pci_addr = "%x:%x:%x" % (domain, bus, slot) cmd = "pci_del pci_addr=%s" % pci_addr elif cmd_type == "device_add": cmd = "device_del %s" % device_id # This should be replaced by a proper monitor method call vm.monitor.cmd(cmd) def device_removed(): after_del = vm.monitor.info("pci") return after_del != after_add if (not kvm_utils.wait_for(device_removed, 10, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (tested_model, cmd)) try: # 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'") # Define a helper function to compare the output def new_shown(): o = session.cmd_output(params.get("reference_cmd")) return o != reference secs = int(params.get("wait_secs_for_hook_up")) if not kvm_utils.wait_for(new_shown, 30, secs, 3): raise error.TestFail("No new device shown in output of command " "executed inside the guest: %s" % params.get("reference_cmd")) # Define a helper function to catch PCI device string def find_pci(): o = session.cmd_output(params.get("find_pci_cmd")) return params.get("match_string") in o if not kvm_utils.wait_for(find_pci, 30, 3, 3): raise error.TestFail( "PCI %s %s device not found in guest. " "Command was: %s" % (tested_model, test_type, params.get("find_pci_cmd"))) # Test the newly added device try: session.cmd(params.get("pci_test_cmd")) except kvm_subprocess.ShellError, e: raise error.TestFail("Check for %s device failed after PCI " "hotplug. Output: %r" % (test_type, e.output)) session.close()
def run_pci_hotplug(test, params, env): """ Test hotplug of PCI devices. (Elements between [] are configurable test parameters) 1) PCI add a deivce (NIC / block) 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. @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")) timeout = int(params.get("login_timeout", 360)) session = kvm_test_utils.wait_for_login(vm, timeout=timeout) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.cmd("modprobe %s" % module) # Get output of command 'info pci' as reference info_pci_ref = vm.monitor.info("pci") # Get output of command as reference reference = session.cmd_output(params.get("reference_cmd")) tested_model = params.get("pci_model") test_type = params.get("pci_type") image_format = params.get("image_format_stg") # Probe qemu to verify what is the supported syntax for PCI hotplug cmd_output = vm.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") if cmd_type == "pci_add": if test_type == "nic": pci_add_cmd = "pci_add pci_addr=auto nic model=%s" % tested_model elif test_type == "block": image_params = kvm_utils.get_sub_dict(params, "stg") image_filename = kvm_vm.get_image_filename(image_params, test.bindir) pci_add_cmd = ("pci_add pci_addr=auto storage file=%s,if=%s" % (image_filename, tested_model)) # Execute pci_add (should be replaced by a proper monitor method call) add_output = vm.monitor.cmd(pci_add_cmd) if not "OK domain" in add_output: raise error.TestFail("Add PCI device failed. " "Monitor command is: %s, Output: %r" % (pci_add_cmd, add_output)) after_add = vm.monitor.info("pci") elif cmd_type == "device_add": driver_id = test_type + "-" + kvm_utils.generate_random_id() id = test_type + "-" + kvm_utils.generate_random_id() if test_type == "nic": if tested_model == "virtio": tested_model = "virtio-net-pci" pci_add_cmd = "device_add id=%s,driver=%s" % (id, tested_model) elif test_type == "block": image_params = kvm_utils.get_sub_dict(params, "stg") image_filename = kvm_vm.get_image_filename(image_params, test.bindir) if tested_model == "virtio": tested_model = "virtio-blk-pci" if tested_model == "scsi": tested_model = "scsi-disk" driver_add_cmd = (" __com.redhat_drive_add " "file=%s,format=%s,id=%s" % (image_filename, image_format, driver_id)) pci_add_cmd = ("device_add id=%s,driver=%s,drive=%s" % (id, tested_model, driver_id)) driver_output = vm.monitor.cmd(driver_add_cmd) # Check if the device is support in qemu devices_support = vm.monitor.cmd("%s ?" % cmd_type) if len(re.findall(tested_model, devices_support)) > 0: add_output = vm.monitor.cmd(pci_add_cmd) else: raise error.TestError("%s doesn't support device: %s" % (cmd_type, tested_model)) after_add = vm.monitor.info("pci") if not id in after_add: raise error.TestFail("Add device failed. Monitor command is: %s" ". Output: %r" % (pci_add_cmd, add_output)) # Define a helper function to delete the device def pci_del(ignore_failure=False): if cmd_type == "pci_add": result_domain, bus, slot, function = add_output.split(',') domain = int(result_domain.split()[2]) bus = int(bus.split()[1]) slot = int(slot.split()[1]) pci_addr = "%x:%x:%x" % (domain, bus, slot) cmd = "pci_del pci_addr=%s" % pci_addr elif cmd_type == "device_add": cmd = "device_del %s" % id # This should be replaced by a proper monitor method call vm.monitor.cmd(cmd) def device_removed(): after_del = vm.monitor.info("pci") return after_del != after_add if (not kvm_utils.wait_for(device_removed, 10, 0, 1) and not ignore_failure): raise error.TestFail("Failed to hot remove PCI device: %s. " "Monitor command: %s" % (tested_model, cmd)) try: # 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'") # Define a helper function to compare the output def new_shown(): o = session.cmd_output(params.get("reference_cmd")) return o != reference secs = int(params.get("wait_secs_for_hook_up")) if not kvm_utils.wait_for(new_shown, 30, secs, 3): raise error.TestFail("No new device shown in output of command " "executed inside the guest: %s" % params.get("reference_cmd")) # Define a helper function to catch PCI device string def find_pci(): o = session.cmd_output(params.get("find_pci_cmd")) return params.get("match_string") in o if not kvm_utils.wait_for(find_pci, 30, 3, 3): raise error.TestFail("PCI %s %s device not found in guest. " "Command was: %s" % (tested_model, test_type, params.get("find_pci_cmd"))) # Test the newly added device try: session.cmd(params.get("pci_test_cmd")) except kvm_subprocess.ShellError, e: raise error.TestFail("Check for %s device failed after PCI " "hotplug. Output: %r" % (test_type, e.output)) session.close()
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