def run_mac_change(test, params, env): """ Change MAC address of guest. 1) Get a new mac from pool, and the old mac addr of guest. 2) Set new mac in guest and regain new IP. 3) Re-log into guest with new MAC. @param test: KVM test object. @param params: Dictionary with the test parameters. @param env: Dictionary with test environment. """ timeout = int(params.get("login_timeout", 360)) vm = kvm_test_utils.get_living_vm(env, params.get("main_vm")) session_serial = kvm_test_utils.wait_for_login(vm, 0, timeout, 0, 2, serial=True) # This session will be used to assess whether the IP change worked session = kvm_test_utils.wait_for_login(vm, 0, timeout, 0, 2) old_mac = vm.get_mac_address(0) while True: vm.free_mac_address(0) new_mac = kvm_utils.generate_mac_address(vm.instance, 0) if old_mac != new_mac: break logging.info("The initial MAC address is %s", old_mac) interface = kvm_test_utils.get_linux_ifname(session_serial, old_mac) # Start change MAC address logging.info("Changing MAC address to %s", new_mac) change_cmd = ("ifconfig %s down && ifconfig %s hw ether %s && " "ifconfig %s up" % (interface, interface, new_mac, interface)) session_serial.cmd(change_cmd) # Verify whether MAC address was changed to the new one logging.info("Verifying the new mac address") session_serial.cmd("ifconfig | grep -i %s" % new_mac) # Restart `dhclient' to regain IP for new mac address logging.info("Restart the network to gain new IP") dhclient_cmd = "dhclient -r && dhclient %s" % interface session_serial.sendline(dhclient_cmd) # Re-log into the guest after changing mac address if kvm_utils.wait_for(session.is_responsive, 120, 20, 3): # Just warning when failed to see the session become dead, # because there is a little chance the ip does not change. logging.warn("The session is still responsive, settings may fail.") session.close() # Re-log into guest and check if session is responsive logging.info("Re-log into the guest") session = kvm_test_utils.wait_for_login(vm, timeout=int(params.get("login_timeout", 360))) if not session.is_responsive(): raise error.TestFail("The new session is not responsive.") session.close()
def run_mac_change(test, params, env): """ Change MAC address of guest. 1) Get a new mac from pool, and the old mac addr of guest. 2) Set new mac in guest and regain new IP. 3) Re-log into guest with new MAC. @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_serial = vm.wait_for_serial_login(timeout=timeout) # This session will be used to assess whether the IP change worked session = vm.wait_for_login(timeout=timeout) old_mac = vm.get_mac_address(0) while True: vm.free_mac_address(0) new_mac = kvm_utils.generate_mac_address(vm.instance, 0) if old_mac != new_mac: break logging.info("The initial MAC address is %s", old_mac) interface = kvm_test_utils.get_linux_ifname(session_serial, old_mac) # Start change MAC address logging.info("Changing MAC address to %s", new_mac) change_cmd = ("ifconfig %s down && ifconfig %s hw ether %s && " "ifconfig %s up" % (interface, interface, new_mac, interface)) session_serial.cmd(change_cmd) # Verify whether MAC address was changed to the new one logging.info("Verifying the new mac address") session_serial.cmd("ifconfig | grep -i %s" % new_mac) # Restart `dhclient' to regain IP for new mac address logging.info("Restart the network to gain new IP") dhclient_cmd = "dhclient -r && dhclient %s" % interface session_serial.sendline(dhclient_cmd) # Re-log into the guest after changing mac address if kvm_utils.wait_for(session.is_responsive, 120, 20, 3): # Just warning when failed to see the session become dead, # because there is a little chance the ip does not change. logging.warn("The session is still responsive, settings may fail.") session.close() # Re-log into guest and check if session is responsive logging.info("Re-log into the guest") session = vm.wait_for_login(timeout=timeout) if not session.is_responsive(): raise error.TestFail("The new session is not responsive.") session.close()
def run_nic_hotplug(test, params, env): """ Test hotplug of NIC devices 1) Boot up guest with one nic 2) Add a host network device through monitor cmd and check if it's added 3) Add nic device through monitor cmd and check if it's added 4) Check if new interface gets ip address 5) Disable primary link of guest 6) Ping guest new ip from host 7) Delete nic device and netdev 8) Re-enable primary link of guest @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)) guest_delay = int(params.get("guest_delay", 20)) session = kvm_test_utils.wait_for_login(vm, timeout=timeout) romfile = params.get("romfile") # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session.get_command_output("modprobe %s" % module) def netdev_add(vm): netdev_id = kvm_utils.generate_random_id() attach_cmd = ("netdev_add tap,id=%s" % netdev_id) nic_script = params.get("nic_script") if nic_script: attach_cmd += ",script=%s" % kvm_utils.get_path( vm.root_dir, 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 netdev_del(vm, n_id): vm.monitor.cmd("netdev_del %s" % n_id) network = vm.monitor.info("network") if n_id in network: logging.error(network) raise error.TestError("Fail to remove netdev %s" % n_id) 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_del(vm, nic_id, wait=True): """ Remove the nic from pci tree. @vm: VM object @id: the nic id @wait: Whether need to wait for the guest to unplug the device """ nic_del_cmd = "device_del %s" % nic_id vm.monitor.cmd(nic_del_cmd) if wait: logging.info("waiting for the guest to finish the unplug") if not kvm_utils.wait_for( lambda: nic_id not in vm.monitor.info("qtree"), guest_delay, 5, 1): logging.error(vm.monitor.info("qtree")) raise error.TestError("Device is not unplugged by " "guest, please check whether the " "hotplug module was loaded in guest") logging.info("Attach a virtio nic to vm") mac = kvm_utils.generate_mac_address(vm.instance, 1) if not mac: mac = "00:00:02:00:00:02" netdev_id = netdev_add(vm) device_id = nic_add(vm, "virtio", netdev_id, mac, romfile) if "Win" not in params.get("guest_name", ""): session.sendline("dhclient %s &" % kvm_test_utils.get_linux_ifname(session, mac)) logging.info("Shutting down the primary link") vm.monitor.cmd("set_link %s down" % vm.netdev_id[0]) try: logging.info("Waiting for new nic's ip address acquisition...") if not kvm_utils.wait_for( lambda: (vm.address_cache.get(mac) is not None), 10, 1): raise error.TestFail("Could not get ip address of new nic") ip = vm.address_cache.get(mac) if not kvm_utils.verify_ip_address_ownership(ip, mac): raise error.TestFail("Could not verify the ip address of new nic") else: logging.info("Got the ip address of new nic: %s", ip) logging.info("Ping test the new nic ...") s, o = kvm_test_utils.ping(ip, 100) if s != 0: logging.error(o) raise error.TestFail("New nic failed ping test") logging.info("Detaching a virtio nic from vm") nic_del(vm, device_id) netdev_del(vm, netdev_id) finally: vm.free_mac_address(1) logging.info("Re-enabling the primary link") vm.monitor.cmd("set_link %s up" % vm.netdev_id[0])
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_nic_hotplug(test, params, env): """ Test hotplug of NIC devices 1) Boot up guest with one nic 2) Add a host network device through monitor cmd and check if it's added 3) Add nic device through monitor cmd and check if it's added 4) Check if new interface gets ip address 5) Disable primary link of guest 6) Ping guest new ip from host 7) Delete nic device and netdev 8) Re-enable primary link of guest @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)) guest_delay = int(params.get("guest_delay", 20)) session_serial = kvm_test_utils.wait_for_login(vm, timeout=timeout, serial=True) # Modprobe the module if specified in config file module = params.get("modprobe_module") if module: session_serial.get_command_output("modprobe %s" % module) 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 netdev_del(vm, n_id): vm.monitor.cmd("netdev_del %s" % n_id) network = vm.monitor.info("network") if n_id in network: logging.error(network) raise error.TestError("Fail to remove netdev %s" % n_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 nic_del(vm, nic_id, wait=True): """ Remove the nic from pci tree. @vm: VM object @id: the nic id @wait: Whether need to wait for the guest to unplug the device """ nic_del_cmd = "device_del %s" % nic_id vm.monitor.cmd(nic_del_cmd) if wait: logging.info("waiting for the guest to finish the unplug") if not kvm_utils.wait_for(lambda: nic_id not in vm.monitor.info("qtree"), guest_delay, 5 ,1): logging.error(vm.monitor.info("qtree")) raise error.TestError("Device is not unplugged by " "guest, please check whether the " "hotplug module was loaded in guest") logging.info("Attach a virtio nic to vm") mac = kvm_utils.generate_mac_address(vm.instance, 1) if not mac: mac = "00:00:02:00:00:02" netdev_id = netdev_add(vm) device_id = nic_add(vm, "virtio", netdev_id, mac) if "Win" not in params.get("guest_name", ""): session_serial.sendline("dhclient %s &" % kvm_test_utils.get_linux_ifname(session_serial, mac)) logging.info("Shutting down the primary link") vm.monitor.cmd("set_link %s down" % vm.netdev_id[0]) try: logging.info("Waiting for new nic's ip address acquisition...") if not kvm_utils.wait_for(lambda: (vm.address_cache.get(mac) is not None), 10, 1): raise error.TestFail("Could not get ip address of new nic") ip = vm.address_cache.get(mac) if not kvm_utils.verify_ip_address_ownership(ip, mac): raise error.TestFail("Could not verify the ip address of new nic") else: logging.info("Got the ip address of new nic: %s", ip) logging.info("Ping test the new nic ...") s, o = kvm_test_utils.ping(ip, 100) if s != 0: logging.error(o) raise error.TestFail("New nic failed ping test") logging.info("Detaching a virtio nic from vm") nic_del(vm, device_id) netdev_del(vm, netdev_id) finally: vm.free_mac_address(1) logging.info("Re-enabling the primary link") vm.monitor.cmd("set_link %s up" % vm.netdev_id[0])