def test_connection(): """ Test network connections 1. Create a network 2. Attach the interfaces and check network connections 3. Check the network connections after detaching ifaces, restarting libvirtd and destroying the VM """ vf_no = int(params.get("vf_no", "4")) net_name = params.get("net_name") iface_type = params.get("iface_type") logging.info("Define network - %s.", net_name) create_network(params) libvirt_vmxml.remove_vm_devices_by_type(vm, 'interface') libvirt_pcicontr.reset_pci_num(vm_name) vm.start() vm.wait_for_serial_login(timeout=240) logging.info("Attach 4 interfaces to the guest.") opts = ' '.join( ["network", net_name, params.get('attach_extra_opts', "")]) for i in range(vf_no): virsh.attach_interface(vm_name, option=opts, debug=True, ignore_status=False) libvirt_network.check_network_connection(net_name, i + 1) logging.info("Try to attach one more interface.") res = virsh.attach_interface(vm_name, option=opts, debug=True) libvirt.check_exit_status(res, True) logging.info("Detach an interface.") vm_ifaces = [ iface for iface in vm_xml.VMXML.new_from_dumpxml( vm_name).devices.by_device_tag("interface") ] mac_addr = vm_ifaces[0].get_mac_address() opts = ' '.join([iface_type, "--mac %s" % mac_addr]) virsh.detach_interface(vm_name, option=opts, debug=True, wait_for_event=True, ignore_status=False) libvirt_network.check_network_connection(net_name, vf_no - 1) logging.info( "Restart libvirtd service and check the network connection.") utils_libvirtd.Libvirtd().restart() libvirt_network.check_network_connection(net_name, vf_no - 1) logging.info("Destroy the VM and check the network connection.") vm.destroy(gracefully=False) libvirt_network.check_network_connection(net_name, 0)
def modify_network(vm_name, first_nic): """ Modify domain's interface to make sure domain can be login. """ iface_type = first_nic.type iface_source = first_nic.source.get('bridge') mac_address = first_nic.mac_address try: virsh.detach_interface(vm_name, "--type=%s --config" % iface_type, ignore_status=False) virsh.attach_interface(vm_name, "--type=%s --source %s --mac %s --config" % (iface_type, iface_source, mac_address), ignore_status=False) except (remote.LoginError, virt_vm.VMError, aexpect.ShellError), detail: raise error.TestFail("Modify network failed:%s" % detail)
def modify_network(vm_name, first_nic): """ Modify domain's interface to make sure domain can be login. """ iface_type = first_nic.type_name iface_source = first_nic.source.get('bridge') mac_address = first_nic.mac_address try: virsh.detach_interface(vm_name, "--type=%s --config" % iface_type, ignore_status=False) virsh.attach_interface(vm_name, "--type=%s --source %s --mac %s --config" % (iface_type, iface_source, mac_address), ignore_status=False) except (remote.LoginError, virt_vm.VMError, aexpect.ShellError), detail: raise error.TestFail("Modify network failed:%s" % detail)
def detach_device(vm_name): """ Detach a device from the given guest :param vm_name: The guest name :return: None """ attach_dev_type = params.get("attach_dev_type", 'disk') detach_option = params.get("detach_option") if attach_dev_type == 'interface': ret = virsh.detach_interface(vm_name, detach_option, **virsh_dargs) else: logging.debug("No need to detach any device.")
def network_hook(): """ Check network hooks. """ # Set interface to use default network net_name = params.get("net_name", "default") edit_iface(net_name) prepare_hook_file(hook_script % (net_name, hook_log)) try: # destroy the network ret = virsh.net_destroy(net_name, **virsh_dargs) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " stopped end -" assert check_hooks(hook_str) # start network ret = virsh.net_start(net_name, **virsh_dargs) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " start begin -" assert check_hooks(hook_str) hook_str = hook_file + " " + net_name + " started begin -" assert check_hooks(hook_str) # plug a interface if vm.is_dead(): vm.start() vm.wait_for_login().close() mac_addr = "52:54:00:9a:53:a9" ret = virsh.attach_interface(vm_name, ("network %s --mac %s" % (net_name, mac_addr))) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " plugged begin -" assert check_hooks(hook_str) ret = virsh.detach_interface(vm_name, "network --mac %s" % mac_addr) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " unplugged begin -" assert check_hooks(hook_str) # remove the log file if os.path.exists(hook_log): os.remove(hook_log) # destroy the domain vm.destroy() hook_str = hook_file + " " + net_name + " unplugged begin -" assert check_hooks(hook_str) except AssertionError: utils_misc.log_last_traceback() test.fail("Failed to check" " network hooks")
def network_hook(): """ Check network hooks. """ # Set interface to use default network net_name = params.get("net_name", "default") edit_iface(net_name) prepare_hook_file(hook_script % (net_name, hook_log)) try: # destroy the network ret = virsh.net_destroy(net_name, **virsh_dargs) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " stopped end -" assert check_hooks(hook_str) # start network ret = virsh.net_start(net_name, **virsh_dargs) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " start begin -" assert check_hooks(hook_str) hook_str = hook_file + " " + net_name + " started begin -" assert check_hooks(hook_str) # plug a interface if vm.is_dead(): vm.start() vm.wait_for_login().close() mac_addr = "52:54:00:9a:53:a9" ret = virsh.attach_interface(vm_name, ("network %s --mac %s" % (net_name, mac_addr))) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " plugged begin -" assert check_hooks(hook_str) ret = virsh.detach_interface(vm_name, "network --mac %s" % mac_addr) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " unplugged begin -" assert check_hooks(hook_str) # remove the log file if os.path.exists(hook_log): os.remove(hook_log) # destroy the domain vm.destroy() hook_str = hook_file + " " + net_name + " unplugged begin -" assert check_hooks(hook_str) except AssertionError: utils.log_last_traceback() raise error.TestFail("Failed to check" " network hooks")
def run(test, params, env): """ Test virsh interface related commands. (1) If using given exist interface for testing(eg. lo or ethX): 1.1 Dumpxml for the interface(with --inactive option) 1.2 Destroy the interface 1.3 Undefine the interface (2) Define an interface from XML file (3) List interfaces with '--inactive' optioin (4) Start the interface (5) List interfaces with no option (6) Dumpxml for the interface (7) Get interface MAC address by interface name (8) Get interface name by interface MAC address (9) Delete interface if not use the exist interface for testing 9.1 Destroy the interface 9.2 Undefine the interface Caveat, this test may affect the host network, so using the loopback(lo) device by default. You can specify the interface which you want, but be careful. """ iface_name = params.get("iface_name") iface_xml = params.get("iface_xml") iface_type = params.get("iface_type", "ethernet") iface_pro = params.get("iface_pro", "") iface_eth = params.get("iface_eth", "") iface_tag = params.get("iface_tag", "0") if iface_type == "vlan": iface_name = iface_eth + "." + iface_tag iface_eth_using = "yes" == params.get("iface_eth_using", "no") ping_ip = params.get("ping_ip", "localhost") use_exist_iface = "yes" == params.get("use_exist_iface", "no") status_error = "yes" == params.get("status_error", "no") net_restart = "yes" == params.get("iface_net_restart", "no") if ping_ip.count("ENTER"): raise error.TestNAError("Please input a valid ip address") if iface_name.count("ENTER"): raise error.TestNAError("Please input a existing bridge/ethernet name") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm: xml_bak = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_script = NETWORK_SCRIPT + iface_name iface_script_bk = os.path.join(test.tmpdir, "iface-%s.bk" % iface_name) net_bridge = utils_net.Bridge() if use_exist_iface: if iface_type == "bridge": if iface_name not in net_bridge.list_br(): raise error.TestError("Bridge '%s' not exists" % iface_name) ifaces = net_bridge.get_structure()[iface_name] if len(ifaces) < 1: # In this situation, dhcp maybe cannot get ip address # Unless you use static, we'd better skip such case raise error.TestNAError("Bridge '%s' has no interface" " bridged, perhaps cannot get" " ipaddress" % iface_name) net_iface = utils_net.Interface(name=iface_name) iface_is_up = True list_option = "--all" if use_exist_iface: if not libvirt.check_iface(iface_name, "exists", "--all"): raise error.TestError("Interface '%s' not exists" % iface_name) iface_xml = os.path.join(test.tmpdir, "iface.xml.tmp") iface_is_up = net_iface.is_up() else: # Note, if not use the interface which already exists, iface_name must # be equal to the value specified in XML file if libvirt.check_iface(iface_name, "exists", "--all"): raise error.TestError("Interface '%s' already exists" % iface_name) if not iface_xml: raise error.TestError("XML file is needed.") iface_xml = os.path.join(test.tmpdir, iface_xml) create_xml_file(iface_xml, params) # Stop NetworkManager as which may conflict with virsh iface commands try: NM = utils_misc.find_command("NetworkManager") except ValueError: logging.debug("No NetworkManager service.") NM = None NM_is_running = False if NM is not None: NM_service = service.Factory.create_service("NetworkManager") NM_is_running = NM_service.status() if NM_is_running: NM_service.stop() # run test cases try: if use_exist_iface: # back up the interface script utils.run("cp %s %s" % (iface_script, iface_script_bk)) # step 1.1 # dumpxml for interface xml = virsh.iface_dumpxml(iface_name, "--inactive", to_file=iface_xml, debug=True) # Step 1.2 # Destroy interface if iface_is_up: result = virsh.iface_destroy(iface_name, debug=True) libvirt.check_exit_status(result, status_error) # Step 1.3 # Undefine interface result = virsh.iface_undefine(iface_name, debug=True) libvirt.check_exit_status(result, status_error) if not status_error: if libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("%s is still present." % iface_name) # Step 2 # Define interface result = virsh.iface_define(iface_xml, debug=True) if iface_type == "bond" and not ping_ip: libvirt.check_exit_status(result, True) return else: libvirt.check_exit_status(result, status_error) if net_restart: network = service.Factory.create_service("network") network.restart() # After network restart, (ethernet)interface will be started if (not net_restart and iface_type in ("bridge", "ethernet")) or\ (not use_exist_iface and iface_type in ("vlan", "bond")): # Step 3 # List inactive interfaces list_option = "--inactive" if not status_error: if not libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("Fail to find %s." % iface_name) # Step 4 # Start interface result = virsh.iface_start(iface_name, debug=True) if not net_restart and not use_exist_iface and\ (iface_type == "ethernet" and iface_pro in ["", "dhcp"] or iface_type == "bridge" and iface_pro == "dhcp"): libvirt.check_exit_status(result, True) else: libvirt.check_exit_status(result, status_error) if not status_error: iface_ip = net_iface.get_ip() ping_ip = ping_ip if not iface_ip else iface_ip if ping_ip: if not libvirt.check_iface(iface_name, "ping", ping_ip): raise error.TestFail("Ping %s fail." % ping_ip) # Step 5 # List active interfaces if use_exist_iface or\ (iface_pro != "dhcp" and iface_type == "bridge") or\ (iface_eth_using and iface_type == "vlan"): list_option = "" if not status_error: if not libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("Fail to find %s in active " "interface list" % iface_name) if vm: iface_mac_list = vm_xml.VMXML.get_iface_dev(vm_name) # Before test, detach all interfaces in guest for mac in iface_mac_list: iface_info = vm_xml.VMXML.get_iface_by_mac(vm_name, mac) type = iface_info.get('type') virsh.detach_interface( vm_name, "--type %s --mac %s" " --config" % (type, mac)) virsh.attach_interface( vm_name, "--type %s --source %s" " --config" % (iface_type, iface_name)) vm.start() try: # Test if guest can be login vm.wait_for_login() except remote.LoginError: raise error.TestFail("Cannot login guest with %s" % iface_name) # Step 6 # Dumpxml for interface xml = virsh.iface_dumpxml(iface_name, "", to_file="", debug=True) logging.debug("Interface '%s' XML:\n%s", iface_name, xml) # Step 7 # Get interface MAC address by name result = virsh.iface_mac(iface_name, debug=True) libvirt.check_exit_status(result, status_error) if not status_error and result.stdout.strip(): if not libvirt.check_iface(iface_name, "mac", result.stdout.strip()): raise error.TestFail("Mac address check fail") # Step 8 # Get interface name by MAC address # Bridge's Mac equal to bridged interface's mac if iface_type not in ("bridge", "vlan") and result.stdout.strip(): iface_mac = net_iface.get_mac() result = virsh.iface_name(iface_mac, debug=True) libvirt.check_exit_status(result, status_error) # Step 9 if not use_exist_iface: # Step 9.1 # Destroy interface result = virsh.iface_destroy(iface_name, debug=True) if not net_restart and\ iface_type == "ethernet" and iface_pro in ["", "dhcp"] or\ iface_type == "bridge" and iface_pro == "dhcp": libvirt.check_exit_status(result, True) else: libvirt.check_exit_status(result, status_error) # Step 9.2 # Undefine interface result = virsh.iface_undefine(iface_name, debug=True) libvirt.check_exit_status(result, status_error) list_option = "--all" if not status_error: if libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("%s is still present." % iface_name) finally: if os.path.exists(iface_xml): os.remove(iface_xml) if os.path.exists(iface_script): os.remove(iface_script) if use_exist_iface: if not os.path.exists(iface_script): utils.run("mv %s %s" % (iface_script_bk, iface_script)) if iface_is_up and\ not libvirt.check_iface(iface_name, "exists", ""): # Need reload script utils.run("ifup %s" % iface_name) elif not iface_is_up and libvirt.check_iface( iface_name, "exists", ""): net_iface.down() if vm: xml_bak.sync() else: if libvirt.check_iface(iface_name, "exists", "--all"): # Remove the interface try: utils_net.bring_down_ifname(iface_name) except utils_net.TAPBringDownError: pass if iface_type == "bridge": if iface_name in net_bridge.list_br(): try: net_bridge.del_bridge(iface_name) except IOError: pass if NM_is_running: NM_service.start()
def run(test, params, env): """ Test virsh nwfilter-binding-list 1)Prepare parameters 2)Run nwfilter_binding_list command 3)check result 4)Clean env """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) status_error = "yes" == params.get("status_error") new_filter_1 = params.get("newfilter_1") new_filter_2 = params.get("newfilter_2") time_wait = params.get("time_wait", 10) option = params.get("option") vmxml_backup = libvirt_xml.vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # prepare vm filterrfer parameters dict list filter_param_list_1 = [] params_key_1 = [] filter_param_list_2 = [] params_key_2 = [] for i in params.keys(): if 'parameters_name_' in i: params_key_1.append(i) params_key_1.sort() for i in range(len(params_key_1)): params_dict = {} params_dict['name'] = params[params_key_1[i]] params_dict['value'] = params['parameters_value_%s' % i] filter_param_list_1.append(params_dict) filterref_dict_1 = {} filterref_dict_1['name'] = new_filter_1 filterref_dict_1['parameters'] = filter_param_list_1 for i in params.keys(): if 'parameters_dhcp_' in i: params_key_2.append(i) params_key_2.sort() for i in range(len(params_key_2)): params_dict = {} params_dict['name'] = params[params_key_2[i]] params_dict['value'] = params['dhcp_value_%s' % i] filter_param_list_2.append(params_dict) filterref_dict_2 = {} filterref_dict_2['name'] = new_filter_2 filterref_dict_2['parameters'] = filter_param_list_2 def env_setting(filterref_dict_1, filterref_dict_2): ret = virsh.attach_interface(vm_name, option) utlv.check_exit_status(ret, status_error) vmxml = libvirt_xml.VMXML.new_from_dumpxml(vm_name) devices = vmxml.get_devices('interface') iface_xml = devices[0] logging.debug("iface_xml : %s" % iface_xml) iface_xml_2 = devices[1] vmxml.del_device(iface_xml) vmxml.del_device(iface_xml_2) new_iface_1 = interface.Interface('network') logging.debug("new_iface_1 : %s" % new_iface_1) new_iface_2 = interface.Interface('network') new_iface_1.xml = iface_xml.xml new_iface_1.type_name = "network" logging.debug("new_iface_1 : %s" % new_iface_1) new_iface_2.xml = iface_xml_2.xml new_iface_1.source = {'network': "default"} new_filterref = new_iface_1.new_filterref(**filterref_dict_1) new_iface_1.filterref = new_filterref new_filterref = new_iface_2.new_filterref(**filterref_dict_2) new_iface_2.filterref = new_filterref logging.debug("new interface xml is: %s \n %s" % (new_iface_1, new_iface_2)) vmxml.add_device(new_iface_1) vmxml.add_device(new_iface_2) vmxml.sync() return new_iface_1, new_iface_2 def attach_new_device(): newnet_iface = interface.Interface('network') newnet_iface.source = {'network': "default"} filterref_dict = {} filterref_list = [{'name': "CTRL_IP_LEARNING", 'value': "dhcp"}] filterref_dict['name'] = "clean-traffic" filterref_dict['parameters'] = filterref_list newnet_iface.filterref = newnet_iface.new_filterref(**filterref_dict) ret = virsh.attach_device(domainarg=vm_name, filearg=newnet_iface.xml, debug=True) utlv.check_exit_status(ret, status_error) try: # set env of start vm new_iface_1, new_iface_2 = env_setting(filterref_dict_1, filterref_dict_2) # start vm virsh.start(vm_name, debug=True) # list binding port dev ret = virsh.nwfilter_binding_list(debug=True) utlv.check_exit_status(ret, status_error) # detach a interface option = "--type network" + " --mac " + new_iface_1.mac_address time.sleep(time_wait) ret = virsh.detach_interface(vm_name, option, debug=True) utlv.check_exit_status(ret, status_error) ret = virsh.nwfilter_binding_list(debug=True) utlv.check_exit_status(ret, status_error) # update_device vnet1_iface = interface.Interface('network') vnet1_iface.xml = new_iface_2.xml target = {'dev': "vnet1"} vnet1_iface.target = target virsh.update_device(domainarg=vm_name, filearg=vnet1_iface.xml, debug=True) ret = virsh.nwfilter_binding_list(debug=True) utlv.check_exit_status(ret, status_error) # attach new interface attach_new_device() ret = virsh.nwfilter_binding_list(debug=True) utlv.check_exit_status(ret, status_error) finally: if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ Test bridge support from network 1) create a linux bridge and connect a physical interface to it 2) define nwfilter with "vdsm-no-mac-spoofing" 3) redefine the vm with the new create bridge and filter 4) check if guest can get public ip after vm start 5) check if guest and host can ping each other 6) check if guest and host can ping outside 7) start another vm connected to the same bridge 8) check if the 2 guests can ping each other """ def create_bridge(br_name, iface_name): """ Create a linux bridge by virsh cmd: 1. Stop NetworkManager and Start network service 2. virsh iface-bridge <iface> <name> [--no-stp] :param br_name: bridge name :param iface_name: physical interface name :return: bridge created or raise exception """ # Make sure the bridge not exist if libvirt.check_iface(br_name, "exists", "--all"): test.cancel("The bridge %s already exist" % br_name) # Create bridge utils_package.package_install('tmux') cmd = 'tmux -c "ip link add name {0} type bridge; ip link set {1} up;' \ ' ip link set {1} master {0}; ip link set {0} up;' \ ' pkill dhclient; sleep 6; dhclient {0}; ifconfig {1} 0"'.format(br_name, iface_name) process.run(cmd, shell=True, verbose=True) def create_bridge_network(br_name, net_name): """ Define and start the bridge type network """ # check if network with the same name already exists output_all = virsh.net_list("--all").stdout.strip() if re.search(net_name, output_all): test.cancel("Network with the same name already exists!") test_xml = network_xml.NetworkXML(network_name="%s" % net_name) test_xml.forward = {"mode": "bridge"} test_xml.bridge = {"name": br_name} test_xml.create() def define_nwfilter(filter_name): """ Define nwfilter vdsm-no-mac-spoofing with content like: <filter name='vdsm-no-mac-spoofing' chain='root'> <filterref filter='no-mac-spoofing'/> <filterref filter='no-arp-mac-spoofing'/> </filter> :param filter_name: the name of nwfilter :return: filter created or raise exception """ filter_uuid = params.get("filter_uuid", "11111111-b071-6127-b4ec-111111111111") filter_params = { "filter_name": "vdsm-no-mac-spoofing", "filter_chain": "root", "filter_uuid": filter_uuid, "filterref_name_1": "no-mac-spoofing", "filterref_name_2": "no-arp-mac-spoofing" } filter_xml = libvirt.create_nwfilter_xml(filter_params).xml # Run command result = virsh.nwfilter_define(filter_xml, ignore_status=True, debug=True) if result.exit_status: test.fail("Failed to define nwfilter with %s" % filter_xml) def ping(src_ip, dest_ip, ping_count, timeout, session=None): """ Wrap of ping :param src_ip: source address :param dest_ip: destination address :param ping_count: count of icmp packet :param timeout: timeout for the ping command :param session: local execution or session to execute the ping command :return: ping succeed or raise exception """ status, output = utils_net.ping(dest=dest_ip, count=ping_count, interface=src_ip, timeout=timeout, session=session, force_ipv4=True) if status: test.fail("Fail to ping %s from %s" % (dest_ip, src_ip)) def check_net_functions(guest_ip, ping_count, ping_timeout, guest_session, host_ip, remote_url, endpoint_ip): # make sure host network works well # host ping remote url ping(host_ip, remote_url, ping_count, ping_timeout) # host ping guest ping(host_ip, guest_ip, ping_count, ping_timeout) # guest ping host ping(guest_ip, host_ip, ping_count, ping_timeout, session=guest_session) # guest ping remote url ping(guest_ip, remote_url, ping_count, ping_timeout, session=guest_session) # guest ping endpoint ping(guest_ip, endpoint_ip, ping_count, ping_timeout, session=guest_session) # Get test params bridge_name = params.get("bridge_name", "test_br0") filter_name = params.get("filter_name", "vdsm-no-mac-spoofing") ping_count = params.get("ping_count", "5") ping_timeout = float(params.get("ping_timeout", "10")) iface_name = utils_net.get_net_if(state="UP")[0] bridge_script = NETWORK_SCRIPT + bridge_name iface_script = NETWORK_SCRIPT + iface_name iface_script_bk = os.path.join(data_dir.get_tmp_dir(), "iface-%s.bk" % iface_name) attach_interface = "yes" == params.get("attach_interface", "no") iface_model = params.get("iface_model", "virtio") iface_source = eval(params.get("iface_source", "{'bridge':'test_br0'}")) iface_type = params.get("iface_type", None) iface_target = params.get("iface_target", "br_target") iface_alias = params.get("iface_alias", None) hotplug = "yes" == params.get("hotplug", "no") iface_driver = params.get("iface_driver", None) start_vm2 = "yes" == params.get("start_vm2", "no") create_network = "yes" == params.get("create_network", "no") update_device = "yes" == params.get("update_with_diff_type", "no") vms = params.get("vms").split() if len(vms) <= 1: test.cancel("Need two VMs to test") else: vm1_name = vms[0] vm2_name = vms[1] vm1 = env.get_vm(vm1_name) vm2 = env.get_vm(vm2_name) # Back up the interface script process.run("cp %s %s" % (iface_script, iface_script_bk), shell=True, verbose=True) # Back up vm xml vm1_xml_bak = vm_xml.VMXML.new_from_dumpxml(vm1_name) vm2_xml_bak = vm_xml.VMXML.new_from_dumpxml(vm2_name) # Stop NetworkManager service NM_service = service.Factory.create_service("NetworkManager") NM_status = NM_service.status() if not NM_status: NM_service.start() mac = utils_net.generate_mac_address_simple() try: create_bridge(bridge_name, iface_name) define_nwfilter(filter_name) if hotplug: err_msgs = ("No more available PCI slots", "No more available PCI addresses") # delete the original interface on the vm before hot-plug if vm1.is_alive(): vm1.destroy() vmxml = vm_xml.VMXML.new_from_dumpxml(vm1_name) iface_xml = vmxml.get_devices('interface')[0] logging.debug("Delete the original interface") vmxml.del_device(iface_xml) vmxml.sync() vm1.start() # do hot-plug if attach_interface: logging.info("Try to hot-plug interface") options = ( "%s %s --model %s --mac %s" % (iface_type, iface_source['bridge'], iface_model, mac)) ret = virsh.attach_interface(vm1_name, options, ignore_status=True) else: logging.info("Try to hot-plug device") if create_network: create_bridge_network(bridge_name, iface_source["network"]) target = str({'dev': iface_target}) iface_alias = str({'name': iface_alias}) vm_iface_source = str(iface_source) iface_params = { "type": iface_type, "source": vm_iface_source, "filter": filter_name, "mac": mac, 'alias': iface_alias, 'target': target, 'model': iface_model, 'driver': iface_driver } attach_xml = interface.Interface(iface_params['type']) attach_xml.xml = libvirt.modify_vm_iface( vm1_name, 'get_xml', iface_params) ret = virsh.attach_device(vm1_name, attach_xml.xml, ignore_status=True, debug=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): test.error("No more pci slots, can't attach more devices") else: test.fail("Failed to attach-interface: %s" % ret.stderr.strip()) else: logging.debug("Hot-plug interface or device pass") if update_device: # As the interface type will change to actual type "bridge" in live xml, we need to ensure # the update with original "network" type will not fail. # Try to delete the nwfilter with original type in iface_params update_xml = interface.Interface(iface_type) iface_params_update = { "del_filter": "yes", "type": "network", "source": vm_iface_source } update_xml.xml = libvirt.modify_vm_iface( vm1_name, 'get_xml', iface_params_update) ret = virsh.update_device(vm1_name, update_xml.xml, ignore_status=True, debug=True) libvirt.check_exit_status(ret) else: vm_iface_source = str(iface_source) vm1_iface_params = { "type": "bridge", "source": vm_iface_source, "filter": filter_name, "mac": mac, 'driver': iface_driver, "iface_model": iface_model } libvirt.modify_vm_iface(vm1_name, "update_iface", vm1_iface_params) if vm1.is_alive(): vm1.destroy() vm1.start() # apply ip address as it may not be initialized session1 = session2 = None session1 = vm1.wait_for_serial_login() utils_net.restart_guest_network(session1) output = session1.cmd_output("ifconfig || ip a") logging.debug("guest1 ip info %s" % output) # Check guest's network function host_ip = utils_net.get_ip_address_by_interface(bridge_name) remote_url = params.get("remote_ip", "www.google.com") try: vm1_ip = utils_net.get_guest_ip_addr(session1, mac) except Exception as errs: test.fail("vm1 can't get IP with the new create bridge: %s" % errs) if hotplug: # reboot vm1 then check network function to ensure the interface still there and works fine logging.info("reboot the vm") virsh.reboot(vm1) if session1 is None: session1 = vm1.wait_for_serial_login() ping(vm1_ip, remote_url, ping_count, ping_timeout, session=session1) # restart libvirtd service then check the interface still works fine libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() vm1.cleanup_serial_console() vm1.create_serial_console() session1 = vm1.wait_for_serial_login() ping(vm1_ip, remote_url, ping_count, ping_timeout, session=session1) logging.info( "after reboot and restart libvirtd, the network works fine") if iface_driver: try: driver_dict = eval(iface_driver) if session1 is None: session1 = vm1.wait_for_serial_login() guest_iface_info = session1.cmd_output("ip l").strip() guest_iface_name = re.findall( r"^\d+: (\S+?)[@:].*state UP.*$", guest_iface_info, re.MULTILINE)[0] comb_size = driver_dict.get('queues') rx_size = driver_dict.get('rx_queue_size') session1.cmd_status("ethtool -L %s combined %s" % (guest_iface_name, comb_size)) ret, outp = session1.cmd_status_output("ethtool -l %s" % guest_iface_name) logging.debug("ethtool cmd output:%s" % outp) if not ret: pre_comb = re.search( "Pre-set maximums:[\s\S]*?Combined:.*?(\d+)", outp).group(1) cur_comb = re.search( "Current hardware settings:[\s\S]*?Combined:.*?(\d+)", outp).group(1) if int(pre_comb) != int(comb_size) or int( cur_comb) != int(comb_size): test.fail( "Fail to check the combined size: setting: %s," "Pre-set: %s, Current-set: %s" % (comb_size, pre_comb, cur_comb)) else: logging.info( "Getting correct Pre-set and Current set value" ) else: test.error("ethtool list fail: %s" % outp) # as tx_queue size is only supported for vhost-user interface, only check rx_queue size ret1, outp1 = session1.cmd_status_output("ethtool -g %s" % guest_iface_name) logging.debug("guest queue size setting is %s" % outp1) if not ret1: pre_set = re.search(r"Pre-set maximums:\s*RX:\s*(\d+)", outp1).group(1) cur_set = re.search( r"Current hardware settings:\s*RX:\s*(\d+)", outp1).group(1) if int(pre_set) != int(rx_size) or int(cur_set) != int( rx_size): test.fail("Fail to check the rx_queue_size!") except Exception as errs: test.fail("fail to get driver info") # hot-unplug interface/device if attach_interface: ret = virsh.detach_interface(vm1_name, "bridge", ignore_status=True) else: ret = virsh.detach_device(vm1_name, attach_xml.xml, ignore_status=True, debug=True) if ret.exit_status: test.fail("Hot-unplug interface/device fail") else: logging.info("hot-unplug interface/device succeed") else: if start_vm2: # Start vm2 connect to the same bridge mac2 = utils_net.generate_mac_address_simple() vm2_iface_params = { "type": "bridge", "source": vm_iface_source, "filter": filter_name, "mac": mac2 } libvirt.modify_vm_iface(vm2_name, "update_iface", vm2_iface_params) if vm2.is_alive(): vm2.destroy() vm2.start() # Check if vm1 and vm2 can ping each other try: utils_net.update_mac_ip_address(vm2, timeout=120) vm2_ip = vm2.get_address() except Exception as errs: test.fail( "vm2 can't get IP with the new create bridge: %s" % errs) session2 = vm2.wait_for_login() # make sure guest has got ip address utils_net.restart_guest_network(session2) output2 = session2.cmd_output("ifconfig || ip a") logging.debug("guest ip info %s" % output2) # check 2 guests' network functions check_net_functions(vm1_ip, ping_count, ping_timeout, session1, host_ip, remote_url, vm2_ip) check_net_functions(vm2_ip, ping_count, ping_timeout, session2, host_ip, remote_url, vm1_ip) finally: logging.debug("Start to restore") vm1_xml_bak.sync() vm2_xml_bak.sync() virsh.nwfilter_undefine(filter_name, ignore_status=True) if libvirt.check_iface(bridge_name, "exists", "--all"): virsh.iface_unbridge(bridge_name, timeout=60, debug=True) if os.path.exists(iface_script_bk): process.run("mv %s %s" % (iface_script_bk, iface_script), shell=True, verbose=True) if os.path.exists(bridge_script): process.run("rm -rf %s" % bridge_script, shell=True, verbose=True) cmd = 'tmux -c "ip link set {1} nomaster; ip link delete {0};' \ 'pkill dhclient; sleep 6; dhclient {1}"'.format(bridge_name, iface_name) process.run(cmd, shell=True, verbose=True) # reload network configuration NM_service.restart() # recover NetworkManager if NM_status is True: NM_service.start() if 'network' in iface_source and iface_source[ "network"] in virsh.net_state_dict(): virsh.net_destroy(iface_source["network"], ignore_status=False)
def run_virsh_attach_detach_interface(test, params, env): """ Test virsh {at|de}tach-interface command. 1) Prepare test environment and its parameters 2) Attach the required interface 3) According test type(only attach or both attach and detach): a.Go on to test detach(if attaching is correct) b.Return GOOD or raise TestFail(if attaching is wrong) 4) Check if attached interface is correct: a.Try to catch it in vm's XML file b.Try to catch it in vm 5) Detach the attached interface 6) Check result """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) # Test parameters uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) vm_ref = params.get("at_detach_iface_vm_ref", "domname") options_suffix = params.get("at_detach_iface_options_suffix", "") status_error = "yes" == params.get("status_error", "no") start_vm = params.get("start_vm") # Should attach must be pass for detach test. correct_attach = "yes" == params.get("correct_attach", "no") # Interface specific attributes. iface_type = params.get("at_detach_iface_type", "network") iface_source = params.get("at_detach_iface_source", "default") iface_mac = params.get("at_detach_iface_mac", "created") virsh_dargs = {'ignore_status': True, 'uri': uri} # Get a bridge name for test if iface_type is bridge. # If there is no bridge other than virbr0, raise TestNAError if iface_type == "bridge": host_bridge = utils_net.Bridge() bridge_list = host_bridge.list_br() try: bridge_list.remove("virbr0") except AttributeError: pass # If no virbr0, just pass is ok logging.debug("Useful bridges:%s", bridge_list) # just choosing one bridge on host. if len(bridge_list): iface_source = bridge_list[0] else: raise error.TestNAError("No useful bridge on host " "other than 'virbr0'.") dom_uuid = vm.get_uuid() dom_id = vm.get_id() # To confirm vm's state if start_vm == "no" and vm.is_alive(): vm.destroy() # Test both detach and attach, So collect info # both of them for result check. # When something wrong with interface, set it to 1 fail_flag = 0 result_info = [] # Set attach-interface domain if vm_ref == "domname": vm_ref = vm_name elif vm_ref == "domid": vm_ref = dom_id elif vm_ref == "domuuid": vm_ref = dom_uuid elif vm_ref == "hexdomid" and dom_id is not None: vm_ref = hex(int(dom_id)) # Get a mac address if iface_mac is 'created'. if iface_mac == "created" or correct_attach: iface_mac = utils_net.generate_mac_address_simple() # Set attach-interface options and Start attach-interface test if correct_attach: options = set_options("network", "default", iface_mac, "", "attach") attach_result = virsh.attach_interface(vm_name, options, **virsh_dargs) else: options = set_options(iface_type, iface_source, iface_mac, options_suffix, "attach") attach_result = virsh.attach_interface(vm_ref, options, **virsh_dargs) attach_status = attach_result.exit_status logging.debug(attach_result) # If attach interface failed. if attach_status: if not status_error: fail_flag = 1 result_info.append("Attach Failed: %s" % attach_result) elif status_error: # Here we just use it to exit, do not mean test failed fail_flag = 1 # If attach interface succeeded. else: if status_error and not correct_attach: fail_flag = 1 result_info.append("Attach Success with wrong command.") if fail_flag and start_vm == "yes": vm.destroy() if len(result_info): raise error.TestFail(result_info) else: # Exit because it is error_test for attach-interface. return # Check dumpxml file whether the interface is added successfully. status, ret = check_dumpxml_iface(vm_name, iface_mac, iface_type, iface_source) if status: fail_flag = 1 result_info.append(ret) # Login to domain to check new interface. if not vm.is_alive(): vm.start() elif vm.state() == "paused": vm.resume() status, ret = login_to_check(vm, iface_mac) if status: fail_flag = 1 result_info.append(ret) # Set detach-interface options options = set_options(iface_type, None, iface_mac, options_suffix, "detach") # Start detach-interface test detach_result = virsh.detach_interface(vm_ref, options, **virsh_dargs) detach_status = detach_result.exit_status logging.debug(detach_result) # Clean up. if check_dumpxml_iface(vm_name, iface_mac) is not None: cleanup_options = "--type %s --mac %s" % (iface_type, iface_mac) virsh.detach_interface(vm_ref, cleanup_options, **virsh_dargs) # Shutdown vm to be afraid of cleaning up failed if vm.is_alive(): vm.destroy() # Check results. if status_error: if detach_status == 0: raise error.TestFail("Detach Success with wrong command.") else: if detach_status != 0: raise error.TestFail("Detach Failed.") else: if fail_flag: raise error.TestFail("Attach-Detach Success but " "something wrong with its " "functional use:%s" % result_info)
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def create_iface_xml(mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) iface.source = iface_source iface.model = iface_model if iface_model else "virtio" if iface_target: iface.target = {'dev': iface_target} iface.mac_address = mac logging.debug("Create new interface xml: %s", iface) return iface status_error = "yes" == params.get("status_error", "no") # Interface specific attributes. iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_source = eval(params.get("iface_source", "{'network':'default'}")) iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_mac = params.get("iface_mac") attach_device = "yes" == params.get("attach_device", "no") attach_iface = "yes" == params.get("attach_iface", "no") attach_option = params.get("attach_option", "") detach_device = "yes" == params.get("detach_device") stress_test = "yes" == params.get("stress_test") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) #iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) libvirtd = utils_libvirtd.Libvirtd() if vm.is_alive(): time.sleep(20) try: try: # Attach an interface when vm is running iface_list = [] err_msgs = ("No more available PCI slots", "No more available PCI addresses") if attach_device: for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) if iface_mac: mac = iface_mac else: mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't" " attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): raise error.TestNAError(ret.stderr) elif status_error: continue else: logging.error("Command output %s" % ret.stdout.strip()) raise error.TestFail("Failed to attach-device") elif stress_test: # Detach the device immediately for stress test ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True) libvirt.check_exit_status(ret) else: iface_list.append({ 'mac': mac, 'iface_xml': iface_xml_obj }) # Need sleep here for attachment take effect time.sleep(5) elif attach_iface: for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't" " attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): raise error.TestNAError(ret.stderr) elif status_error: continue else: logging.error("Command output %s" % ret.stdout.strip()) raise error.TestFail("Failed to attach-interface") elif stress_test: # Detach the device immediately for stress test ret = virsh.attach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) else: iface_list.append({'mac': mac}) # Need sleep here for attachment take effect time.sleep(5) # Restart libvirtd service if restart_libvirtd: libvirtd.restart() vm.cleanup_serial_console() # Start the domain if needed if vm.is_dead(): vm.start() session = vm.wait_for_serial_login() # Check if interface was attached for iface in iface_list: if iface.has_key('mac'): # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']) if not if_attr: raise error.TestFail("Can't see interface " " in dumpxml") if (if_attr['type'] != iface_type or if_attr['source'] != iface_source['network']): raise error.TestFail("Interface attribute doesn't" " match attachment opitons") # Check interface on guest if not utils_net.get_linux_ifname(session, iface['mac']): raise error.TestFail("Can't see interface" " on guest") # Detach hot/cold-plugged interface at last if detach_device: for iface in iface_list: if iface.has_key('iface_xml'): ret = virsh.detach_device(vm_name, iface['iface_xml'].xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) else: options = ("%s --mac %s" % (iface_type, iface['mac'])) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) # Check if interface was detached for iface in iface_list: if iface.has_key('mac'): # Check interface in dumpxml output if vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']): raise error.TestFail("Interface still exist" " after detachment") session.close() except virt_vm.VMStartError, e: logging.info(str(e)) raise error.TestFail('VM Failed to start for some reason!') finally: # Recover VM. logging.info("Restoring vm...") if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run_virsh_attach_detach_interface(test, params, env): """ Test virsh {at|de}tach-interface command. 1) Prepare test environment and its parameters 2) Attach the required interface 3) According test type(only attach or both attach and detach): a.Go on to test detach(if attaching is correct) b.Return GOOD or raise TestFail(if attaching is wrong) 4) Check if attached interface is correct: a.Try to catch it in vm's XML file b.Try to catch it in vm 5) Detach the attached interface 6) Check result """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) # Test parameters uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) vm_ref = params.get("at_detach_iface_vm_ref", "domname") options_suffix = params.get("at_detach_iface_options_suffix", "") status_error = "yes" == params.get("status_error", "no") start_vm = params.get("start_vm") # Should attach must be pass for detach test. correct_attach = "yes" == params.get("correct_attach", "no") # Interface specific attributes. iface_type = params.get("at_detach_iface_type", "network") iface_source = params.get("at_detach_iface_source", "default") iface_mac = params.get("at_detach_iface_mac", "created") virsh_dargs = {'ignore_status': True, 'uri': uri} # Get a bridge name for test if iface_type is bridge. # If there is no bridge other than virbr0, raise TestNAError if iface_type == "bridge": host_bridge = utils_net.Bridge() bridge_list = host_bridge.list_br() try: bridge_list.remove("virbr0") except AttributeError: pass # If no virbr0, just pass is ok logging.debug("Useful bridges:%s", bridge_list) # just choosing one bridge on host. if len(bridge_list): iface_source = bridge_list[0] else: raise error.TestNAError("No useful bridge on host " "other than 'virbr0'.") dom_uuid = vm.get_uuid() dom_id = vm.get_id() # To confirm vm's state if start_vm == "no" and vm.is_alive(): vm.destroy() # Test both detach and attach, So collect info # both of them for result check. # When something wrong with interface, set it to 1 fail_flag = 0 result_info = [] # Set attach-interface domain if vm_ref == "domname": vm_ref = vm_name elif vm_ref == "domid": vm_ref = dom_id elif vm_ref == "domuuid": vm_ref = dom_uuid elif vm_ref == "hexdomid" and dom_id is not None: vm_ref = hex(int(dom_id)) # Get a mac address if iface_mac is 'created'. if iface_mac == "created" or correct_attach: iface_mac = utils_net.generate_mac_address_simple() # Set attach-interface options and Start attach-interface test if correct_attach: options = set_options("network", "default", iface_mac, "", "attach") attach_result = virsh.attach_interface(vm_name, options, **virsh_dargs) else: options = set_options(iface_type, iface_source, iface_mac, options_suffix, "attach") attach_result = virsh.attach_interface(vm_ref, options, **virsh_dargs) attach_status = attach_result.exit_status logging.debug(attach_result) # If attach interface failed. if attach_status: if not status_error: fail_flag = 1 result_info.append("Attach Failed: %s" % attach_result) elif status_error: # Here we just use it to exit, do not mean test failed fail_flag = 1 # If attach interface succeeded. else: if status_error and not correct_attach: fail_flag = 1 result_info.append("Attach Success with wrong command.") if fail_flag and start_vm == "yes": vm.destroy() if len(result_info): raise error.TestFail(result_info) else: # Exit because it is error_test for attach-interface. return # Check dumpxml file whether the interface is added successfully. status, ret = check_dumpxml_iface( vm_name, iface_mac, iface_type, iface_source) if status: fail_flag = 1 result_info.append(ret) # Login to domain to check new interface. if not vm.is_alive(): vm.start() elif vm.state() == "paused": vm.resume() status, ret = login_to_check(vm, iface_mac) if status: fail_flag = 1 result_info.append(ret) # Set detach-interface options options = set_options(iface_type, None, iface_mac, options_suffix, "detach") # Start detach-interface test detach_result = virsh.detach_interface(vm_ref, options, **virsh_dargs) detach_status = detach_result.exit_status logging.debug(detach_result) # Clean up. if check_dumpxml_iface(vm_name, iface_mac) is not None: cleanup_options = "--type %s --mac %s" % (iface_type, iface_mac) virsh.detach_interface(vm_ref, cleanup_options, **virsh_dargs) # Shutdown vm to be afraid of cleaning up failed if vm.is_alive(): vm.destroy() # Check results. if status_error: if detach_status == 0: raise error.TestFail("Detach Success with wrong command.") else: if detach_status != 0: raise error.TestFail("Detach Failed.") else: if fail_flag: raise error.TestFail("Attach-Detach Success but " "something wrong with its " "functional use:%s" % result_info)
vm_cmd(cmd) if checkpoint == 'sync_ntp': logging.info('Sync time with %s', ntp_server) cmd = ['yum -y install ntpdate', 'ntpdate %s' % ntp_server] vm_cmd(cmd) if checkpoint == 'blank_2nd_disk': disk_path = os.path.join(data_dir.get_tmp_dir(), 'blank.img') logging.info('Create blank disk %s', disk_path) process.run('truncate -s 1G %s' % disk_path) logging.info('Attach blank disk to vm') attach_removable_media('disk', disk_path, 'vdc') logging.debug(virsh.dumpxml(vm_name)) if checkpoint in ['only_net', 'only_br']: logging.info('Detatch all networks') virsh.detach_interface(vm_name, 'network --current', debug=True) logging.info('Detatch all bridges') virsh.detach_interface(vm_name, 'bridge --current', debug=True) if checkpoint == 'only_net': logging.info('Attach network') virsh.attach_interface(vm_name, 'network default --current', debug=True) v2v_params.pop('bridge') if checkpoint == 'only_br': logging.info('Attatch bridge') virsh.attach_interface(vm_name, 'bridge virbr0 --current', debug=True) v2v_params.pop('network') if checkpoint == 'no_libguestfs_backend': os.environ.pop('LIBGUESTFS_BACKEND') if checkpoint == 'file_image': vm = env.get_vm(vm_name) disk = vm.get_first_disk_devices()
def vm_stress_events(self, event, vm, params): """ Stress events :param event: event name :param vm: vm object """ current_vcpu = int(params.get("smp", 2)) max_vcpu = int(params.get("vcpu_maxcpus", 2)) iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_model = params.get("iface_model", "virtio") iface_source = eval(params.get("iface_source", "{'network':'default'}")) attach_option = params.get("attach_option", "") detach_option = params.get("detach_option", "") disk_size = params.get("virt_disk_device_size", "1") disk_type = params.get("disk_type", "file") disk_device = params.get("disk_device", "disk") disk_format = params.get("disk_format", "qcow2") device_target = params.get("virt_disk_device_target", "vda").split() path = params.get("path", "") device_source_names = params.get("virt_disk_device_source", "").split() disk_driver = params.get("driver_name", "qemu") self.ignore_status = params.get("ignore_status", "no") == "yes" dargs = {'ignore_status': True, 'debug': True} for itr in range(self.iterations): if "vcpupin" in event: for vcpu in range(current_vcpu): result = virsh.vcpupin(vm.name, vcpu, random.choice(self.host_cpu_list), **dargs) if not self.ignore_status: libvirt.check_exit_status(result) elif "emulatorpin" in event: result = virsh.emulatorpin(vm.name, random.choice(self.host_cpu_list), **dargs) if not self.ignore_status: libvirt.check_exit_status(result) elif "suspend" in event: result = virsh.suspend(vm.name, **dargs) if not self.ignore_status: libvirt.check_exit_status(result) time.sleep(self.event_sleep_time) result = virsh.resume(vm.name, **dargs) if not self.ignore_status: libvirt.check_exit_status(result) elif "cpuhotplug" in event: result = virsh.setvcpus(vm.name, max_vcpu, "--live", **dargs) if not self.ignore_status: libvirt.check_exit_status(result) exp_vcpu = { 'max_config': max_vcpu, 'max_live': max_vcpu, 'cur_config': current_vcpu, 'cur_live': max_vcpu, 'guest_live': max_vcpu } utils_hotplug.check_vcpu_value(vm, exp_vcpu, option="--live") time.sleep(self.event_sleep_time) result = virsh.setvcpus(vm.name, current_vcpu, "--live", **dargs) if not self.ignore_status: libvirt.check_exit_status(result) exp_vcpu = { 'max_config': max_vcpu, 'max_live': max_vcpu, 'cur_config': current_vcpu, 'cur_live': current_vcpu, 'guest_live': current_vcpu } utils_hotplug.check_vcpu_value(vm, exp_vcpu, option="--live") elif "reboot" in event: vm.reboot() elif "nethotplug" in event: for iface_num in range(int(iface_num)): logging.debug("Try to attach interface %d" % iface_num) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) logging.debug( "VM name: %s , Options for Network attach: %s", vm.name, options) ret = virsh.attach_interface(vm.name, options, ignore_status=True) time.sleep(self.event_sleep_time) if not self.ignore_status: libvirt.check_exit_status(ret) if detach_option: options = ("--type %s --mac %s %s" % (iface_type, mac, detach_option)) logging.debug( "VM name: %s , Options for Network detach: %s", vm.name, options) ret = virsh.detach_interface(vm.name, options, ignore_status=True) if not self.ignore_status: libvirt.check_exit_status(ret) elif "diskhotplug" in event: for disk_num in range(len(device_source_names)): disk = {} disk_attach_error = False disk_name = os.path.join(path, vm.name, device_source_names[disk_num]) device_source = libvirt.create_local_disk( disk_type, disk_name, disk_size, disk_format=disk_format) disk.update({ "format": disk_format, "source": device_source }) disk_xml = Disk(disk_type) disk_xml.device = disk_device disk_xml.driver = { "name": disk_driver, "type": disk_format } ret = virsh.attach_disk(vm.name, disk["source"], device_target[disk_num], attach_option, debug=True) if not self.ignore_status: libvirt.check_exit_status(ret, disk_attach_error) if detach_option: ret = virsh.detach_disk(vm.name, device_target[disk_num], extra=detach_option) if not self.ignore_status: libvirt.check_exit_status(ret) libvirt.delete_local_disk(disk_type, disk_name) else: raise NotImplementedError time.sleep(self.itr_sleep_time)
def run(test, params, env): """ convert specific kvm guest to rhev """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') hypervisor = params.get("hypervisor") vm_name = params.get('main_vm', 'EXAMPLE') target = params.get('target') remote_host = params.get('remote_host', 'EXAMPLE') input_mode = params.get("input_mode") output_mode = params.get('output_mode') output_format = params.get('output_format') source_user = params.get("username", "root") storage = params.get('output_storage') storage_name = params.get('storage_name') bridge = params.get('bridge') network = params.get('network') ntp_server = params.get('ntp_server') vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") address_cache = env.get('address_cache') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = utlv.PoolVolumeTest(test, params) v2v_opts = params.get('v2v_opts', '-v -x') v2v_timeout = int(params.get('v2v_timeout', 3600)) skip_check = 'yes' == params.get('skip_check', 'no') status_error = 'yes' == params.get('status_error', 'no') checkpoint = params.get('checkpoint', '') debug_kernel = 'debug_kernel' == checkpoint backup_list = ['floppy', 'floppy_devmap', 'fstab_cdrom', 'sata_disk', 'network_rtl8139', 'network_e1000', 'spice', 'spice_encrypt', 'spice_qxl', 'spice_cirrus', 'vnc_qxl', 'vnc_cirrus', 'blank_2nd_disk', 'listen_none', 'listen_socket', 'only_net', 'only_br'] error_list = [] # Prepare step for different hypervisor if hypervisor == "esx": source_ip = params.get("vpx_hostname") source_pwd = params.get("vpx_password") vpx_passwd_file = params.get("vpx_passwd_file") # Create password file to access ESX hypervisor with open(vpx_passwd_file, 'w') as f: f.write(source_pwd) elif hypervisor == "xen": source_ip = params.get("xen_hostname") source_pwd = params.get("xen_host_passwd") # Set up ssh access using ssh-agent and authorized_keys ssh_key.setup_ssh_key(source_ip, source_user, source_pwd) try: utils_misc.add_identities_into_ssh_agent() except Exception as e: process.run("ssh-agent -k") test.error("Fail to setup ssh-agent \n %s" % str(e)) elif hypervisor == "kvm": source_ip = None source_pwd = None else: test.cancel("Unspported hypervisor: %s" % hypervisor) # Create libvirt URI v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) logging.debug("libvirt URI for converting: %s", remote_uri) # Make sure the VM exist before convert v2v_virsh = None close_virsh = False if hypervisor == 'kvm': v2v_virsh = virsh else: virsh_dargs = {'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'debug': True} v2v_virsh = virsh.VirshPersistent(**virsh_dargs) close_virsh = True if not v2v_virsh.domain_exists(vm_name): test.error("VM '%s' not exist" % vm_name) def log_fail(msg): """ Log error and update error list """ logging.error(msg) error_list.append(msg) def vm_shell(func): """ Decorator of shell session to vm """ def wrapper(*args, **kwargs): vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_dead(): logging.info('VM is down. Starting it now.') vm.start() session = vm.wait_for_login() kwargs['session'] = session kwargs['vm'] = vm func(*args, **kwargs) if session: session.close() vm.shutdown() return wrapper def check_disks(vmcheck): """ Check disk counts inside the VM """ # Initialize windows boot up os_type = params.get("os_type", "linux") expected_disks = int(params.get("ori_disks", "1")) logging.debug("Expect %s disks im VM after convert", expected_disks) # Get disk counts if os_type == "linux": cmd = "lsblk |grep disk |wc -l" disks = int(vmcheck.session.cmd(cmd).strip()) else: cmd = r"echo list disk > C:\list_disk.txt" vmcheck.session.cmd(cmd) cmd = r"diskpart /s C:\list_disk.txt" output = vmcheck.session.cmd(cmd).strip() logging.debug("Disks in VM: %s", output) disks = len(re.findall('Disk\s\d', output)) logging.debug("Find %s disks in VM after convert", disks) if disks == expected_disks: logging.info("Disk counts is expected") else: log_fail("Disk counts is wrong") def check_vmlinuz_initramfs(v2v_output): """ Check if vmlinuz matches initramfs on multi-kernel case """ logging.debug('Checking if vmlinuz matches initramfs') kernel_strs = re.findall('(\* kernel.*?\/boot\/config){1,}', v2v_output, re.DOTALL) if len(kernel_strs) == 0: test.error("Not find kernel information") # Remove duplicate items by set logging.debug('Boots and kernel info: %s' % set(kernel_strs)) for str_i in set(kernel_strs): # Fine all versions kernel_vers = re.findall('((?:\d+\.){1,}\d+-(?:\d+\.){1,}\w+)', str_i) logging.debug('kernel related versions: %s' % kernel_vers) # kernel_vers = [kernel, vmlinuz, initramfs] and they should be same if len(kernel_vers) < 3 or len(set(kernel_vers)) != 1: log_fail("kernel versions does not match: %s" % kernel_vers) def check_boot_kernel(vmcheck): """ Check if converted vm use the latest kernel """ _, current_kernel = vmcheck.run_cmd('uname -r') if 'debug' in current_kernel: log_fail('Current kernel is a debug kernel: %s' % current_kernel) # 'sort -V' can satisfy our testing, even though it's not strictly perfect. # The last one is always the latest kernel version kernel_normal_list = vmcheck.run_cmd('rpm -q kernel | sort -V')[1].strip().splitlines() status, kernel_debug = vmcheck.run_cmd('rpm -q kernel-debug') if status != 0: test.error('Not found kernel-debug package') all_kernel_list = kernel_normal_list + kernel_debug.strip().splitlines() logging.debug('All kernels: %s' % all_kernel_list) if len(all_kernel_list) < 3: test.error('Needs at least 2 normal kernels and 1 debug kernel in VM') # The latest non-debug kernel must be kernel_normal_list[-1] if current_kernel.strip() != kernel_normal_list[-1].lstrip('kernel-'): log_fail('Check boot kernel failed') def check_floppy_exist(vmcheck): """ Check if floppy exists after convertion """ blk = vmcheck.session.cmd('lsblk') logging.info(blk) if not re.search('fd0', blk): log_fail('Floppy not found') def attach_removable_media(type, source, dev): bus = {'cdrom': 'ide', 'floppy': 'fdc', 'disk': 'virtio'} args = {'driver': 'qemu', 'subdriver': 'raw', 'sourcetype': 'file', 'type': type, 'targetbus': bus[type]} if type == 'cdrom': args.update({'mode': 'readonly'}) config = '' # Join all options together to get command line for key in list(args.keys()): config += ' --%s %s' % (key, args[key]) config += ' --current' virsh.attach_disk(vm_name, source, dev, extra=config) def change_disk_bus(dest): """ Change all disks' bus type to $dest """ bus_list = ['ide', 'sata', 'virtio'] if dest not in bus_list: test.error('Bus type not support') dev_prefix = ['h', 's', 'v'] dev_table = dict(list(zip(bus_list, dev_prefix))) logging.info('Change disk bus to %s' % dest) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.get_disk_all() index = 0 for disk in list(disks.values()): if disk.get('device') != 'disk': continue target = disk.find('target') target.set('bus', dest) target.set('dev', dev_table[dest] + 'd' + string.ascii_lowercase[index]) disk.remove(disk.find('address')) index += 1 vmxml.sync() def change_network_model(model): """ Change network model to $model """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) network_list = vmxml.get_iface_all() for node in list(network_list.values()): if node.get('type') == 'network': node.find('model').set('type', model) vmxml.sync() def attach_network_card(model): """ Attach network card based on model """ if model not in ('e1000', 'virtio', 'rtl8139'): test.error('Network model not support') options = {'type': 'network', 'source': 'default', 'model': model} line = '' for key in options: line += ' --' + key + ' ' + options[key] line += ' --current' logging.debug(virsh.attach_interface(vm_name, option=line)) def check_multi_netcards(mac_list, virsh_instance): """ Check if number and type of network cards meet expectation """ vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=virsh_instance) iflist = vmxml.get_iface_all() logging.debug('MAC list before v2v: %s' % mac_list) logging.debug('MAC list after v2v: %s' % list(iflist.keys())) if set(mac_list).difference(list(iflist.keys())): log_fail('Missing network interface') for mac in iflist: if iflist[mac].find('model').get('type') != 'virtio': log_fail('Network not convert to virtio') @vm_shell def insert_floppy_devicemap(**kwargs): """ Add an entry of floppy to device.map """ session = kwargs['session'] line = '(fd0) /dev/fd0' devmap = '/boot/grub/device.map' if session.cmd_status('ls %s' % devmap): devmap = '/boot/grub2/device.map' cmd_exist = 'grep \'(fd0)\' %s' % devmap cmd_set = 'sed -i \'2i%s\' %s' % (line, devmap) if session.cmd_status(cmd_exist): session.cmd(cmd_set) def make_label(session): """ Label a volume, swap or root volume """ # swaplabel for rhel7 with xfs, e2label for rhel6 or ext* cmd_map = {'root': 'e2label %s ROOT', 'swap': 'swaplabel -L SWAPPER %s'} if not session.cmd_status('swaplabel --help'): blk = 'swap' elif not session.cmd_status('which e2label'): blk = 'root' else: test.error('No tool to make label') entry = session.cmd('blkid|grep %s' % blk).strip() path = entry.split()[0].strip(':') cmd_label = cmd_map[blk] % path if 'LABEL' not in entry: session.cmd(cmd_label) return blk @vm_shell def specify_fstab_entry(type, **kwargs): """ Specify entry in fstab file """ type_list = ['cdrom', 'uuid', 'label', 'sr0', 'invalid'] if type not in type_list: test.error('Not support %s in fstab' % type) session = kwargs['session'] # Specify cdrom device if type == 'cdrom': line = '/dev/cdrom /media/CDROM auto exec' if 'grub2' in utils_misc.get_bootloader_cfg(session): line += ',nofail' line += ' 0 0' logging.debug('fstab entry is "%s"', line) cmd = [ 'mkdir -p /media/CDROM', 'mount /dev/cdrom /media/CDROM', 'echo "%s" >> /etc/fstab' % line ] for i in range(len(cmd)): session.cmd(cmd[i]) elif type == 'sr0': line = params.get('fstab_content') session.cmd('echo "%s" >> /etc/fstab' % line) elif type == 'invalid': line = utils_misc.generate_random_string(6) session.cmd('echo "%s" >> /etc/fstab' % line) else: map = {'uuid': 'UUID', 'label': 'LABEL'} logging.info(type) if session.cmd_status('cat /etc/fstab|grep %s' % map[type]): # Specify device by UUID if type == 'uuid': entry = session.cmd( 'blkid -s UUID|grep swap').strip().split() # Replace path for UUID origin = entry[0].strip(':') replace = entry[1].replace('"', '') # Specify device by label elif type == 'label': blk = make_label(session) entry = session.cmd('blkid|grep %s' % blk).strip() # Remove " from LABEL="****" replace = entry.split()[1].strip().replace('"', '') # Replace the original id/path with label origin = entry.split()[0].strip(':') cmd_fstab = "sed -i 's|%s|%s|' /etc/fstab" % (origin, replace) session.cmd(cmd_fstab) fstab = session.cmd_output('cat /etc/fstab') logging.debug('Content of /etc/fstab:\n%s', fstab) def create_large_file(session, left_space): """ Create a large file to make left space of root less than $left_space MB """ cmd_df = "df -m / --output=avail" df_output = session.cmd(cmd_df).strip() logging.debug('Command output: %s', df_output) avail = int(df_output.strip().split('\n')[-1]) logging.info('Available space: %dM' % avail) if avail > left_space - 1: tmp_dir = data_dir.get_tmp_dir() if session.cmd_status('ls %s' % tmp_dir) != 0: session.cmd('mkdir %s' % tmp_dir) large_file = os.path.join(tmp_dir, 'file.large') cmd_create = 'dd if=/dev/zero of=%s bs=1M count=%d' % \ (large_file, avail - left_space + 2) session.cmd(cmd_create, timeout=v2v_timeout) logging.info('Available space: %sM' % session.cmd(cmd_df).strip()) @vm_shell def corrupt_rpmdb(**kwargs): """ Corrupt rpm db """ session = kwargs['session'] # If __db.* exist, remove them, then touch _db.001 to corrupt db. if not session.cmd_status('ls /var/lib/rpm/__db.001'): session.cmd('rm -f /var/lib/rpm/__db.*') session.cmd('touch /var/lib/rpm/__db.001') if not session.cmd_status('yum update'): test.error('Corrupt rpmdb failed') @vm_shell def grub_serial_terminal(**kwargs): """ Edit the serial and terminal lines of grub.conf """ session = kwargs['session'] vm = kwargs['vm'] grub_file = utils_misc.get_bootloader_cfg(session) if 'grub2' in grub_file: test.cancel('Skip this case on grub2') cmd = "sed -i '1iserial -unit=0 -speed=115200\\n" cmd += "terminal -timeout=10 serial console' %s" % grub_file session.cmd(cmd) @vm_shell def set_selinux(value, **kwargs): """ Set selinux stat of guest """ session = kwargs['session'] current_stat = session.cmd_output('getenforce').strip() logging.debug('Current selinux status: %s', current_stat) if current_stat != value: cmd = "sed -E -i 's/(^SELINUX=).*?/\\1%s/' /etc/selinux/config" % value logging.info('Set selinux stat with command %s', cmd) session.cmd(cmd) @vm_shell def get_firewalld_status(**kwargs): """ Return firewalld service status of vm """ session = kwargs['session'] # Example: Active: active (running) since Fri 2019-03-15 01:03:39 CST; 3min 48s ago firewalld_status = session.cmd('systemctl status firewalld.service|grep Active:', ok_status=[0, 3]).strip() # Exclude the time string because time changes if vm restarts firewalld_status = re.search('Active:\s\w*\s\(\w*\)', firewalld_status).group() logging.info('Status of firewalld: %s', firewalld_status) params[checkpoint] = firewalld_status def check_firewalld_status(vmcheck, expect_status): """ Check if status of firewalld meets expectation """ firewalld_status = vmcheck.session.cmd('systemctl status ' 'firewalld.service|grep Active:', ok_status=[0, 3]).strip() # Exclude the time string because time changes if vm restarts firewalld_status = re.search('Active:\s\w*\s\(\w*\)', firewalld_status).group() logging.info('Status of firewalld after v2v: %s', firewalld_status) if firewalld_status != expect_status: log_fail('Status of firewalld changed after conversion') @vm_shell def vm_cmd(cmd_list, **kwargs): """ Excecute a list of commands on guest. """ session = kwargs['session'] for cmd in cmd_list: logging.info('Send command "%s"', cmd) # 'chronyc waitsync' needs more than 2mins to sync clock, # We set timeout to 300s will not have side-effects for other # commands. status, output = session.cmd_status_output(cmd, timeout=300) logging.debug('Command output:\n%s', output) if status != 0: test.error('Command "%s" failed' % cmd) logging.info('All commands executed') def check_time_keep(vmcheck): """ Check time drift after convertion. """ logging.info('Check time drift') output = vmcheck.session.cmd('chronyc tracking') logging.debug(output) if 'Not synchronised' in output: log_fail('Time not synchronised') lst_offset = re.search('Last offset *?: *(.*) ', output).group(1) drift = abs(float(lst_offset)) logging.debug('Time drift is: %f', drift) if drift > 3: log_fail('Time drift exceeds 3 sec') def check_boot(): """ Check if guest can boot up after configuration """ try: vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_alive(): vm.shutdown() logging.info('Booting up %s' % vm_name) vm.start() vm.wait_for_login() vm.shutdown() logging.info('%s is down' % vm_name) except Exception as e: test.error('Bootup guest and login failed: %s', str(e)) def check_result(result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout + result.stderr if skip_check: logging.info('Skip checking vm after conversion') elif not status_error: if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt(params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') if output_mode == 'libvirt': try: virsh.start(vm_name, debug=True, ignore_status=False) except Exception as e: test.fail('Start vm failed: %s' % str(e)) # Check guest following the checkpoint document after convertion vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if params.get('skip_check') != 'yes': ret = vmchecker.run() if len(ret) == 0: logging.info("All common checkpoints passed") vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=vmchecker.virsh_instance) logging.debug(vmxml) if checkpoint == 'multi_kernel': check_boot_kernel(vmchecker.checker) check_vmlinuz_initramfs(output) if checkpoint == 'floppy': # Convert to rhv will remove all removeable devices(floppy, cdrom) if output_mode in ['local', 'libvirt']: check_floppy_exist(vmchecker.checker) if checkpoint == 'multi_disks': check_disks(vmchecker.checker) if checkpoint == 'multi_netcards': check_multi_netcards(params['mac_address'], vmchecker.virsh_instance) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': vmchecker.check_graphics(params[checkpoint]) else: graph_type = checkpoint.split('_')[0] vmchecker.check_graphics({'type': graph_type}) video_type = vmxml.get_devices('video')[0].model_type if video_type.lower() != 'qxl': log_fail('Video expect QXL, actual %s' % video_type) if checkpoint.startswith('listen'): listen_type = vmxml.get_devices('graphics')[0].listen_type logging.info('listen type is: %s', listen_type) if listen_type != checkpoint.split('_')[-1]: log_fail('listen type changed after conversion') if checkpoint.startswith('selinux'): status = vmchecker.checker.session.cmd( 'getenforce').strip().lower() logging.info('Selinux status after v2v:%s', status) if status != checkpoint[8:]: log_fail('Selinux status not match') if checkpoint == 'guest_firewalld_status': check_firewalld_status(vmchecker.checker, params[checkpoint]) if checkpoint in ['ntpd_on', 'sync_ntp']: check_time_keep(vmchecker.checker) # Merge 2 error lists error_list.extend(vmchecker.errors) log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: v2v_params = { 'target': target, 'hypervisor': hypervisor, 'main_vm': vm_name, 'input_mode': input_mode, 'network': network, 'bridge': bridge, 'storage': storage, 'hostname': source_ip, 'v2v_opts': v2v_opts, 'new_name': vm_name + utils_misc.generate_random_string(3)} if vpx_dc: v2v_params.update({"vpx_dc": vpx_dc}) if esx_ip: v2v_params.update({"esx_ip": esx_ip}) output_format = params.get('output_format') if output_format: v2v_params.update({'output_format': output_format}) # Build rhev related options if output_mode == 'rhev': # Create different sasl_user name for different job params.update({'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3)}) logging.info('sals user name is %s' % params.get("sasl_user")) # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) if output_mode == 'local': v2v_params['storage'] = data_dir.get_tmp_dir() if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') # Set libguestfs environment variable os.environ['LIBGUESTFS_BACKEND'] = 'direct' # Save origin graphic type for result checking if source is KVM if hypervisor == 'kvm': ori_vm_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) params['ori_graphic'] = ori_vm_xml.xmltreefile.find( 'devices').find('graphics').get('type') backup_xml = None # Only kvm guest's xml needs to be backup currently if checkpoint in backup_list and hypervisor == 'kvm': backup_xml = ori_vm_xml if checkpoint == 'multi_disks': new_xml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) disk_count = 0 for disk in list(new_xml.get_disk_all().values()): if disk.get('device') == 'disk': disk_count += 1 if disk_count <= 1: test.error('Not enough disk devices') params['ori_disks'] = disk_count if checkpoint == 'sata_disk': change_disk_bus('sata') if checkpoint.startswith('floppy'): img_path = data_dir.get_tmp_dir() + '/floppy.img' utlv.create_local_disk('floppy', img_path) attach_removable_media('floppy', img_path, 'fda') if checkpoint == 'floppy_devmap': insert_floppy_devicemap() if checkpoint.startswith('fstab'): if checkpoint == 'fstab_cdrom': img_path = data_dir.get_tmp_dir() + '/cdrom.iso' utlv.create_local_disk('iso', img_path) attach_removable_media('cdrom', img_path, 'hdc') specify_fstab_entry(checkpoint[6:]) if checkpoint == 'running': virsh.start(vm_name) logging.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'paused': virsh.start(vm_name, '--paused') logging.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'serial_terminal': grub_serial_terminal() check_boot() if checkpoint == 'no_space': @vm_shell def take_space(**kwargs): create_large_file(kwargs['session'], 20) take_space() if checkpoint.startswith('host_no_space'): session = aexpect.ShellSession('sh') create_large_file(session, 1000) if checkpoint == 'host_no_space_setcache': logging.info('Set LIBGUESTFS_CACHEDIR=/home') os.environ['LIBGUESTFS_CACHEDIR'] = '/home' if checkpoint == 'corrupt_rpmdb': corrupt_rpmdb() if checkpoint.startswith('network'): change_network_model(checkpoint[8:]) if checkpoint == 'multi_netcards': params['mac_address'] = [] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) network_list = vmxml.get_iface_all() for mac in network_list: if network_list[mac].get('type') in ['bridge', 'network']: params['mac_address'].append(mac) if len(params['mac_address']) < 2: test.error('Not enough network interface') logging.debug('MAC address: %s' % params['mac_address']) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': spice_passwd = {'type': 'spice', 'passwd': params.get('spice_passwd', 'redhat')} vm_xml.VMXML.set_graphics_attr(vm_name, spice_passwd) params[checkpoint] = {'type': 'spice', 'passwdValidTo': '1970-01-01T00:00:01'} else: graphic_video = checkpoint.split('_') graphic = graphic_video[0] logging.info('Set graphic type to %s', graphic) vm_xml.VMXML.set_graphics_attr(vm_name, {'type': graphic}) if len(graphic_video) > 1: video_type = graphic_video[1] logging.info('Set video type to %s', video_type) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) video = vmxml.xmltreefile.find( 'devices').find('video').find('model') video.set('type', video_type) # cirrus doesn't support 'ram' and 'vgamem' attribute if video_type == 'cirrus': [video.attrib.pop(attr_i) for attr_i in [ 'ram', 'vgamem'] if attr_i in video.attrib] vmxml.sync() if checkpoint.startswith('listen'): listen_type = checkpoint.split('_')[-1] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) listen = vmxml.xmltreefile.find( 'devices').find('graphics').find('listen') listen.set('type', listen_type) vmxml.sync() if checkpoint == 'host_selinux_on': params['selinux_stat'] = utils_selinux.get_status() utils_selinux.set_status('enforcing') if checkpoint.startswith('selinux'): set_selinux(checkpoint[8:]) if checkpoint.startswith('host_firewalld'): service_mgr = service.ServiceManager() logging.info('Backing up firewall services status') params['bk_firewalld_status'] = service_mgr.status('firewalld') if 'start' in checkpoint: service_mgr.start('firewalld') if 'stop' in checkpoint: service_mgr.stop('firewalld') if checkpoint == 'guest_firewalld_status': get_firewalld_status() if checkpoint == 'remove_securetty': logging.info('Remove /etc/securetty file from guest') cmd = ['rm -f /etc/securetty'] vm_cmd(cmd) if checkpoint == 'ntpd_on': logging.info('Set service chronyd on') cmd = ['yum -y install chrony', 'systemctl start chronyd', 'chronyc add server %s' % ntp_server] vm_cmd(cmd) if checkpoint == 'sync_ntp': logging.info('Sync time with %s', ntp_server) cmd = ['yum -y install chrony', 'systemctl start chronyd', 'chronyc add server %s' % ntp_server, 'chronyc waitsync'] vm_cmd(cmd) if checkpoint == 'blank_2nd_disk': disk_path = os.path.join(data_dir.get_tmp_dir(), 'blank.img') logging.info('Create blank disk %s', disk_path) process.run('truncate -s 1G %s' % disk_path) logging.info('Attach blank disk to vm') attach_removable_media('disk', disk_path, 'vdc') logging.debug(virsh.dumpxml(vm_name)) if checkpoint in ['only_net', 'only_br']: logging.info('Detatch all networks') virsh.detach_interface(vm_name, 'network --current', debug=True) logging.info('Detatch all bridges') virsh.detach_interface(vm_name, 'bridge --current', debug=True) if checkpoint == 'only_net': logging.info('Attach network') virsh.attach_interface( vm_name, 'network default --current', debug=True) v2v_params.pop('bridge') if checkpoint == 'only_br': logging.info('Attatch bridge') virsh.attach_interface( vm_name, 'bridge virbr0 --current', debug=True) v2v_params.pop('network') if checkpoint == 'no_libguestfs_backend': os.environ.pop('LIBGUESTFS_BACKEND') if checkpoint == 'file_image': vm = env.get_vm(vm_name) disk = vm.get_first_disk_devices() logging.info('Disk type is %s', disk['type']) if disk['type'] != 'file': test.error('Guest is not with file image') v2v_result = utils_v2v.v2v_cmd(v2v_params) if v2v_params.get('new_name'): vm_name = params['main_vm'] = v2v_params['new_name'] check_result(v2v_result, status_error) finally: if close_virsh: v2v_virsh.close_session() if params.get('vmchecker'): params['vmchecker'].cleanup() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '') if backup_xml: backup_xml.sync() if params.get('selinux_stat') and params['selinux_stat'] != 'disabled': utils_selinux.set_status(params['selinux_stat']) if 'bk_firewalld_status' in params: service_mgr = service.ServiceManager() if service_mgr.status('firewalld') != params['bk_firewalld_status']: if params['bk_firewalld_status']: service_mgr.start('firewalld') else: service_mgr.stop('firewalld') if checkpoint.startswith('host_no_space'): large_file = os.path.join(data_dir.get_tmp_dir(), 'file.large') if os.path.isfile(large_file): os.remove(large_file) # Cleanup constant files utils_v2v.cleanup_constant_files(params)
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm.is_alive(): vm.wait_for_login() def create_iface_xml(mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) iface.source = iface_source iface.model = iface_model if iface_model else "virtio" if iface_target: iface.target = {'dev': iface_target} iface.mac_address = mac logging.debug("Create new interface xml: %s", iface) return iface status_error = "yes" == params.get("status_error", "no") # Interface specific attributes. iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_source = eval(params.get("iface_source", "{'network':'default'}")) iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_mac = params.get("iface_mac") attach_device = "yes" == params.get("attach_device", "no") attach_iface = "yes" == params.get("attach_iface", "no") attach_option = params.get("attach_option", "") detach_device = "yes" == params.get("detach_device") stress_test = "yes" == params.get("stress_test") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") username = params.get("username") password = params.get("password") poll_timeout = int(params.get("poll_timeout", 10)) # stree_test require detach operation stress_test_detach_device = False stress_test_detach_interface = False if stress_test: if attach_device: stress_test_detach_device = True if attach_iface: stress_test_detach_interface = True # The following detach-device step also using attach option detach_option = attach_option # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) #iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) libvirtd = utils_libvirtd.Libvirtd() # Check virsh command option check_cmds = [] if not status_error: if attach_device and attach_option: check_cmds.append(('attach-device', attach_option)) if attach_iface and attach_option: check_cmds.append(('attach-interface', attach_option)) if (detach_device or stress_test_detach_device) and detach_option: check_cmds.append(('detach-device', detach_option)) if stress_test_detach_interface and detach_option: check_cmds.append(('detach-device', detach_option)) for cmd, option in check_cmds: libvirt.virsh_cmd_has_option(cmd, option) try: try: # Attach an interface when vm is running iface_list = [] err_msgs = ("No more available PCI slots", "No more available PCI addresses") if attach_device: for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) if iface_mac: mac = iface_mac else: mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't" " attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): test.cancel(ret.stderr) elif status_error: continue else: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-device") elif stress_test: # Detach the device immediately for stress test ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr=detach_option, ignore_status=True) libvirt.check_exit_status(ret) else: iface_list.append({'mac': mac, 'iface_xml': iface_xml_obj}) elif attach_iface: for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't" " attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): test.cancel(ret.stderr) elif status_error: continue else: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-interface") elif stress_test: # Detach the device immediately for stress test options = ("--type %s --mac %s %s" % (iface_type, mac, detach_option)) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) else: iface_list.append({'mac': mac}) # Restart libvirtd service if restart_libvirtd: libvirtd.restart() vm.cleanup_serial_console() # Start the domain if needed if vm.is_dead(): vm.start() session = vm.wait_for_serial_login(username=username, password=password) # Check if interface was attached for iface in iface_list: if 'mac' in iface: # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']) if not if_attr: test.fail("Can't see interface in dumpxml") if (if_attr['type'] != iface_type or if_attr['source'] != iface_source['network']): test.fail("Interface attribute doesn't" " match attachment opitons") # Check interface on guest def get_iface(): try: utils_net.get_linux_ifname(session, iface['mac']) return True except Exception: return False if not utils_misc.wait_for(get_iface, timeout=60): test.fail("Can't see interface on guest") # Detach hot/cold-plugged interface at last if detach_device: for iface in iface_list: if 'iface_xml' in iface: ret = virsh.detach_device(vm_name, iface['iface_xml'].xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) else: options = ("%s --mac %s" % (iface_type, iface['mac'])) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) # Check if interface was detached for iface in iface_list: if 'mac' in iface: polltime = time.time() + poll_timeout while True: # Check interface in dumpxml output if not vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']): break else: time.sleep(2) if time.time() > polltime: test.fail("Interface still " "exists after detachment") session.close() except virt_vm.VMStartError as e: logging.info(str(e)) test.fail('VM failed to start:\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ Test virsh interface related commands. (1) If using given exist interface for testing(eg. lo or ethX): 1.1 Dumpxml for the interface(with --inactive option) 1.2 Destroy the interface 1.3 Undefine the interface (2) Define an interface from XML file (3) List interfaces with '--inactive' option (4) Start the interface (5) List interfaces with no option (6) Dumpxml for the interface (7) Get interface MAC address by interface name (8) Get interface name by interface MAC address (9) Delete interface if not use the exist interface for testing 9.1 Destroy the interface 9.2 Undefine the interface Caveat, this test may affect the host network, so using the loopback(lo) device by default. You can specify the interface which you want, but be careful. """ iface_name = params.get("iface_name", "ENTER.BRIDGE.NAME") iface_xml = params.get("iface_xml") iface_type = params.get("iface_type", "ethernet") iface_pro = params.get("iface_pro", "") iface_eth = params.get("iface_eth", "") iface_tag = params.get("iface_tag", "0") if iface_type == "vlan": iface_name = iface_eth + "." + iface_tag iface_eth_using = "yes" == params.get("iface_eth_using", "no") ping_ip = params.get("ping_ip", "localhost") use_exist_iface = "yes" == params.get("use_exist_iface", "no") status_error = "yes" == params.get("status_error", "no") net_restart = "yes" == params.get("iface_net_restart", "no") list_dumpxml_acl = "yes" == params.get("list_dumpxml_acl", "no") if ping_ip.count("ENTER"): test.cancel("Please input a valid ip address") if iface_name.count("ENTER"): test.cancel("Please input a existing bridge/ethernet name") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user', "EXAMPLE") if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': test.cancel("API acl test not supported in current" " libvirt version.") virsh_dargs = {'debug': True} list_dumpxml_dargs = {'debug': True} if params.get('setup_libvirt_polkit') == 'yes': if not list_dumpxml_acl: virsh_dargs['uri'] = uri virsh_dargs['unprivileged_user'] = unprivileged_user else: list_dumpxml_dargs['uri'] = uri list_dumpxml_dargs['unprivileged_user'] = unprivileged_user list_dumpxml_dargs['ignore_status'] = False # acl api negative testing params write_save_status_error = "yes" == params.get("write_save_status_error", "no") start_status_error = "yes" == params.get("start_status_error", "no") stop_status_error = "yes" == params.get("stop_status_error", "no") delete_status_error = "yes" == params.get("delete_status_error", "no") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm: xml_bak = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_script = NETWORK_SCRIPT + iface_name iface_script_bk = os.path.join(data_dir.get_tmp_dir(), "iface-%s.bk" % iface_name) net_bridge = utils_net.Bridge() if use_exist_iface: if iface_type == "bridge": if iface_name not in net_bridge.list_br(): test.error("Bridge '%s' not exists" % iface_name) ifaces = net_bridge.get_structure()[iface_name] if len(ifaces) < 1: # In this situation, dhcp maybe cannot get ip address # Unless you use static, we'd better skip such case test.cancel("Bridge '%s' has no interface" " bridged, perhaps cannot get" " ipaddress" % iface_name) net_iface = utils_net.Interface(name=iface_name) iface_is_up = True list_option = "--all" if use_exist_iface: if not libvirt.check_iface(iface_name, "exists", "--all"): test.error("Interface '%s' not exists" % iface_name) iface_xml = os.path.join(data_dir.get_tmp_dir(), "iface.xml.tmp") iface_is_up = net_iface.is_up() else: # Note, if not use the interface which already exists, iface_name must # be equal to the value specified in XML file if libvirt.check_iface(iface_name, "exists", "--all"): test.error("Interface '%s' already exists" % iface_name) if not iface_xml: test.error("XML file is needed.") iface_xml = os.path.join(data_dir.get_tmp_dir(), iface_xml) create_xml_file(iface_xml, params) # Stop NetworkManager as which may conflict with virsh iface commands try: NM = utils_path.find_command("NetworkManager") except utils_path.CmdNotFoundError: logging.debug("No NetworkManager service.") NM = None NM_is_running = False if NM is not None: NM_service = service.Factory.create_service("NetworkManager") NM_is_running = NM_service.status() if NM_is_running: NM_service.stop() # run test cases try: if use_exist_iface: # back up the interface script process.run("cp %s %s" % (iface_script, iface_script_bk), shell=True) # step 1.1 # dumpxml for interface if list_dumpxml_acl: virsh.iface_list(**list_dumpxml_dargs) xml = virsh.iface_dumpxml(iface_name, "--inactive", to_file=iface_xml, **list_dumpxml_dargs) # Step 1.2 # Destroy interface if iface_is_up: result = virsh.iface_destroy(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and stop_status_error): # acl_test negative test libvirt.check_exit_status(result, stop_status_error) virsh.iface_destroy(iface_name, debug=True) else: libvirt.check_exit_status(result, status_error) # Step 1.3 # Undefine interface result = virsh.iface_undefine(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and delete_status_error): # acl_test negative test libvirt.check_exit_status(result, delete_status_error) virsh.iface_undefine(iface_name, debug=True) else: libvirt.check_exit_status(result, status_error) if not status_error: if libvirt.check_iface(iface_name, "exists", list_option): test.fail("%s is still present." % iface_name) # Step 2 # Define interface result = virsh.iface_define(iface_xml, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and write_save_status_error): # acl_test negative test libvirt.check_exit_status(result, write_save_status_error) virsh.iface_define(iface_xml, debug=True) elif iface_type == "bond" and not ping_ip: libvirt.check_exit_status(result, True) return else: libvirt.check_exit_status(result, status_error) if net_restart: network = service.Factory.create_service("network") network.restart() # After network restart, (ethernet)interface will be started if (not net_restart and iface_type in ("bridge", "ethernet")) or\ (not use_exist_iface and iface_type in ("vlan", "bond")): # Step 3 # List inactive interfaces list_option = "--inactive" if not status_error: if not libvirt.check_iface(iface_name, "exists", list_option): test.fail("Fail to find %s." % iface_name) # Step 4 # Start interface result = virsh.iface_start(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and start_status_error): # acl_test negative test libvirt.check_exit_status(result, start_status_error) virsh.iface_start(iface_name, debug=True) elif (not net_restart and not use_exist_iface and (iface_type == "ethernet" and iface_pro in ["", "dhcp"] or iface_type == "bridge" and iface_pro == "dhcp")): libvirt.check_exit_status(result, True) else: libvirt.check_exit_status(result, status_error) if not status_error: iface_ip = net_iface.get_ip() ping_ip = ping_ip if not iface_ip else iface_ip if ping_ip: if not libvirt.check_iface(iface_name, "ping", ping_ip): test.fail("Ping %s fail." % ping_ip) # Step 5 # List active interfaces if use_exist_iface or\ (iface_pro != "dhcp" and iface_type == "bridge") or\ (iface_eth_using and iface_type == "vlan"): list_option = "" if not status_error: if not libvirt.check_iface(iface_name, "exists", list_option): test.fail("Fail to find %s in active " "interface list" % iface_name) if vm: if vm.is_alive(): vm.destroy() iface_index = 0 iface_mac_list = vm_xml.VMXML.get_iface_dev(vm_name) # Before test, detach all interfaces in guest for mac in iface_mac_list: iface_info = vm_xml.VMXML.get_iface_by_mac(vm_name, mac) type = iface_info.get('type') virsh.detach_interface( vm_name, "--type %s --mac %s" " --config" % (type, mac)) # After detach interface, vm.virtnet also need update, the # easy way is free these mac addresses before start VM vm.free_mac_address(iface_index) iface_index += 1 virsh.attach_interface( vm_name, "--type %s --source %s" " --config" % (iface_type, iface_name)) vm.start() try: # Test if guest can be login vm.wait_for_login() except remote.LoginError: test.fail("Cannot login guest with %s" % iface_name) # Step 6 # Dumpxml for interface if list_dumpxml_acl: virsh.iface_list(**list_dumpxml_dargs) xml = virsh.iface_dumpxml(iface_name, "", to_file="", **list_dumpxml_dargs) logging.debug("Interface '%s' XML:\n%s", iface_name, xml) # Step 7 # Get interface MAC address by name result = virsh.iface_mac(iface_name, debug=True) libvirt.check_exit_status(result, status_error) if not status_error and result.stdout.strip(): if not libvirt.check_iface(iface_name, "mac", result.stdout.strip()): test.fail("Mac address check fail") # Step 8 # Get interface name by MAC address # Bridge's Mac equal to bridged interface's mac if iface_type not in ("bridge", "vlan") and result.stdout.strip(): iface_mac = net_iface.get_mac() result = virsh.iface_name(iface_mac, debug=True) libvirt.check_exit_status(result, status_error) # Step 9 if not use_exist_iface: # Step 9.0 # check if interface's state is active before destroy if libvirt.check_iface(iface_name, "state", "--all"): # Step 9.1 # Destroy interface result = virsh.iface_destroy(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and stop_status_error): # acl_test negative test libvirt.check_exit_status(result, stop_status_error) virsh.iface_destroy(iface_name, debug=True) elif (not net_restart and iface_type == "ethernet" and iface_pro in ["", "dhcp"] or iface_type == "bridge" and iface_pro == "dhcp"): libvirt.check_exit_status(result, True) else: libvirt.check_exit_status(result, status_error) # Step 9.2 # Undefine interface result = virsh.iface_undefine(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and delete_status_error): # acl_test negative test libvirt.check_exit_status(result, delete_status_error) virsh.iface_undefine(iface_name, debug=True) else: libvirt.check_exit_status(result, status_error) list_option = "--all" if not status_error: if libvirt.check_iface(iface_name, "exists", list_option): test.fail("%s is still present." % iface_name) finally: if os.path.exists(iface_xml): os.remove(iface_xml) if os.path.exists(iface_script): os.remove(iface_script) if use_exist_iface: if not os.path.exists(iface_script): process.run("mv %s %s" % (iface_script_bk, iface_script), shell=True) if iface_is_up and\ not libvirt.check_iface(iface_name, "exists", ""): # Need reload script process.run("ifup %s" % iface_name, shell=True) elif not iface_is_up and libvirt.check_iface( iface_name, "exists", ""): net_iface.down() if vm: xml_bak.sync() else: if libvirt.check_iface(iface_name, "exists", "--all"): # Remove the interface try: utils_net.bring_down_ifname(iface_name) except utils_net.TAPBringDownError: pass if iface_type == "bridge": if iface_name in net_bridge.list_br(): try: net_bridge.del_bridge(iface_name) except IOError: pass if NM_is_running: NM_service.start()
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm.is_alive(): vm.wait_for_login() def create_iface_xml(mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) iface.source = iface_source iface.model = iface_model if iface_model else "virtio" if iface_target: iface.target = {'dev': iface_target} iface.mac_address = mac if iface_rom: iface.rom = eval(iface_rom) logging.debug("Create new interface xml: %s", iface) return iface # Interface specific attributes. iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_source = eval(params.get("iface_source", "{'network':'default'}")) iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_mac = params.get("iface_mac") iface_rom = params.get("iface_rom") attach_device = "yes" == params.get("attach_device", "no") attach_iface = "yes" == params.get("attach_iface", "no") attach_option = params.get("attach_option", "") detach_device = "yes" == params.get("detach_device") stress_test = "yes" == params.get("stress_test") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") start_vm = "yes" == params.get("start_vm", "yes") options_test = "yes" == params.get("options_test", "no") username = params.get("username") password = params.get("password") poll_timeout = int(params.get("poll_timeout", 10)) err_msgs1 = params.get("err_msgs1") err_msgs2 = params.get("err_msgs2") err_msg_rom = params.get("err_msg_rom") # stree_test require detach operation stress_test_detach_device = False stress_test_detach_interface = False if stress_test: if attach_device: stress_test_detach_device = True if attach_iface: stress_test_detach_interface = True # The following detach-device step also using attach option detach_option = attach_option # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) #iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) libvirtd = utils_libvirtd.Libvirtd() # Check virsh command option check_cmds = [] sep_options = attach_option.split() logging.debug("sep_options: %s" % sep_options) for sep_option in sep_options: if attach_device and sep_option: check_cmds.append(('attach-device', sep_option)) if attach_iface and sep_option: check_cmds.append(('attach-interface', sep_option)) if (detach_device or stress_test_detach_device) and sep_option: check_cmds.append(('detach-device', sep_option)) if stress_test_detach_interface and sep_option: check_cmds.append(('detach-device', sep_option)) for cmd, option in check_cmds: libvirt.virsh_cmd_has_option(cmd, option) try: try: # Attach an interface when vm is running iface_list = [] err_msgs = ("No more available PCI slots", "No more available PCI addresses") if not start_vm: virsh.destroy(vm_name) for i in range(int(iface_num)): if attach_device: logging.info("Try to attach device loop %s" % i) if iface_mac: mac = iface_mac else: mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True, debug=True) elif attach_iface: logging.info("Try to attach interface loop %s" % i) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): test.cancel(ret.stderr) elif err_msgs1 in ret.stderr: logging.debug("option %s is not supported when domain running is %s" % (attach_option, vm.is_alive())) if start_vm or ("--live" not in sep_options and attach_option): test.fail("return not supported, but it is unexpected") elif err_msgs2 in ret.stderr: logging.debug("options %s are mutually exclusive" % attach_option) if not ("--current" in sep_options and len(sep_options) > 1): test.fail("return mutualy exclusive, but it is unexpected") elif err_msg_rom in ret.stderr: logging.debug("Attach failed with expect err msg: %s" % err_msg_rom) else: test.fail("Failed to attach-interface: %s" % ret.stderr.strip()) elif stress_test: if attach_device: # Detach the device immediately for stress test ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr=detach_option, ignore_status=True) elif attach_iface: # Detach the device immediately for stress test options = ("--type %s --mac %s %s" % (iface_type, mac, detach_option)) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) else: if attach_device: iface_list.append({'mac': mac, 'iface_xml': iface_xml_obj}) elif attach_iface: iface_list.append({'mac': mac}) # Restart libvirtd service if restart_libvirtd: libvirtd.restart() # After restart libvirtd, the old console was invalidated, # so we need create a new serial console vm.cleanup_serial_console() vm.create_serial_console() # in options test, check if the interface is attached # in current state when attach return true def check_iface_exist(): try: session = vm.wait_for_serial_login(username=username, password=password) if utils_net.get_linux_ifname(session, iface['mac']): return True else: logging.debug("can not find interface in vm") except Exception: return False if options_test: for iface in iface_list: if 'mac' in iface: # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']) if vm.is_alive() and attach_option == "--config": if if_attr: test.fail("interface should not exists " "in current live vm while " "attached by --config") else: if if_attr: logging.debug("interface %s found current " "state in xml" % if_attr['mac']) else: test.fail("no interface found in " "current state in xml") if if_attr: if if_attr['type'] != iface_type or \ if_attr['source'] != \ iface_source['network']: test.fail("Interface attribute doesn't " "match attachment options") # check interface in vm only when vm is active if vm.is_alive(): logging.debug("check interface in current state " "in vm") if not utils_misc.wait_for(check_iface_exist, timeout=20): if not attach_option == "--config": test.fail("Can't see interface " "in current state in vm") else: logging.debug("find interface in " "current state in vm") else: logging.debug("find interface in " "current state in vm") # in options test, if the attach is performed # when the vm is running # need to destroy and start to check again vm.destroy() # Start the domain if needed if vm.is_dead(): vm.start() session = vm.wait_for_serial_login(username=username, password=password) # check if interface is attached for iface in iface_list: if 'mac' in iface: logging.debug("check interface in xml") # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']) logging.debug(if_attr) if if_attr: logging.debug("interface {} is found in xml". format(if_attr['mac'])) if (if_attr['type'] != iface_type or if_attr['source'] != iface_source['network']): test.fail("Interface attribute doesn't " "match attachment options") if options_test and start_vm and attach_option \ in ("--current", "--live", ""): test.fail("interface should not exists when " "restart vm in options_test") else: logging.debug("no interface found in xml") if options_test and start_vm and attach_option in \ ("--current", "--live", ""): logging.debug("interface not exists next state " "in xml with %s" % attach_option) else: test.fail("Can't see interface in dumpxml") # Check interface on guest if not utils_misc.wait_for(check_iface_exist, timeout=20): logging.debug("can't see interface next state in vm") if start_vm and attach_option in \ ("--current", "--live", ""): logging.debug("it is expected") else: test.fail("should find interface " "but no seen in next state in vm") # Detach hot/cold-plugged interface at last if detach_device: for iface in iface_list: if 'iface_xml' in iface: ret = virsh.detach_device(vm_name, iface['iface_xml'].xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) else: options = ("%s --mac %s" % (iface_type, iface['mac'])) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) # Check if interface was detached for iface in iface_list: if 'mac' in iface: polltime = time.time() + poll_timeout while True: # Check interface in dumpxml output if not vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']): break else: time.sleep(2) if time.time() > polltime: test.fail("Interface still " "exists after detachment") session.close() except virt_vm.VMStartError as e: logging.info(str(e)) test.fail('VM failed to start:\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ Test virsh nwfilter-binding-list 1)Prepare parameters 2)Run nwfilter_binding_list command 3)check result 4)Clean env """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) status_error = "yes" == params.get("status_error") new_filter_1 = params.get("newfilter_1") new_filter_2 = params.get("newfilter_2") time_wait = params.get("time_wait", 10) option = params.get("option") vmxml_backup = libvirt_xml.vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # prepare vm filterrfer parameters dict list filter_param_list_1 = [] params_key_1 = [] filter_param_list_2 = [] params_key_2 = [] for i in params.keys(): if 'parameters_name_' in i: params_key_1.append(i) params_key_1.sort() for i in range(len(params_key_1)): params_dict = {} params_dict['name'] = params[params_key_1[i]] params_dict['value'] = params['parameters_value_%s' % i] filter_param_list_1.append(params_dict) filterref_dict_1 = {} filterref_dict_1['name'] = new_filter_1 filterref_dict_1['parameters'] = filter_param_list_1 for i in params.keys(): if 'parameters_dhcp_' in i: params_key_2.append(i) params_key_2.sort() for i in range(len(params_key_2)): params_dict = {} params_dict['name'] = params[params_key_2[i]] params_dict['value'] = params['dhcp_value_%s' % i] filter_param_list_2.append(params_dict) filterref_dict_2 = {} filterref_dict_2['name'] = new_filter_2 filterref_dict_2['parameters'] = filter_param_list_2 utils_package.package_install('libvirt-daemon-config-nwfilter') def env_setting(filterref_dict_1, filterref_dict_2): ret = virsh.attach_interface(vm_name, option) utlv.check_exit_status(ret, status_error) vmxml = libvirt_xml.VMXML.new_from_dumpxml(vm_name) devices = vmxml.get_devices('interface') iface_xml = devices[0] logging.debug("iface_xml : %s" % iface_xml) iface_xml_2 = devices[1] vmxml.del_device(iface_xml) vmxml.del_device(iface_xml_2) new_iface_1 = interface.Interface('network') logging.debug("new_iface_1 : %s" % new_iface_1) new_iface_2 = interface.Interface('network') new_iface_1.xml = iface_xml.xml new_iface_1.type_name = "network" logging.debug("new_iface_1 : %s" % new_iface_1) new_iface_2.xml = iface_xml_2.xml new_iface_1.source = {'network': "default"} new_filterref = new_iface_1.new_filterref(**filterref_dict_1) new_iface_1.filterref = new_filterref new_filterref = new_iface_2.new_filterref(**filterref_dict_2) new_iface_2.filterref = new_filterref logging.debug("new interface xml is: %s \n %s" % (new_iface_1, new_iface_2)) vmxml.add_device(new_iface_1) vmxml.add_device(new_iface_2) vmxml.sync() return new_iface_1, new_iface_2 def attach_new_device(): newnet_iface = interface.Interface('network') newnet_iface.source = {'network': "default"} newnet_iface.model = 'virtio' filterref_dict = {} filterref_list = [{'name': "CTRL_IP_LEARNING", 'value': "dhcp"}] filterref_dict['name'] = "clean-traffic" filterref_dict['parameters'] = filterref_list newnet_iface.filterref = newnet_iface.new_filterref(**filterref_dict) ret = virsh.attach_device(domainarg=vm_name, filearg=newnet_iface.xml, debug=True) utlv.check_exit_status(ret, status_error) try: # set env of start vm new_iface_1, new_iface_2 = env_setting(filterref_dict_1, filterref_dict_2) # start vm virsh.start(vm_name, debug=True) # list binding port dev logging.debug("check nwfilter binding for 2 interfaces") ret = virsh.nwfilter_binding_list(debug=True) utlv.check_result(ret, expected_match=[r"vnet\d+\s+clean-traffic"]) utlv.check_result(ret, expected_match=[r"vnet\d+\s+allow-dhcp-server"]) # detach a interface option = "--type network" + " --mac " + new_iface_1.mac_address ret = virsh.detach_interface(vm_name, option, debug=True) time.sleep(time_wait) utlv.check_exit_status(ret, status_error) logging.debug("check nwfilter binding after detach one interface:") time.sleep(3) ret = virsh.nwfilter_binding_list(debug=True) if re.search(r'vnet\d+\s+clean-traffic.*', ret.stdout): test.fail( "vnet binding clean-traffic still exists after detach the interface!" ) utlv.check_result(ret, expected_match=[r"vnet\d+\s+allow-dhcp-server"]) # update_device to delete the filter iface_dict = {'del_filter': True} new_xml = utlv.modify_vm_iface(vm_name, 'get_xml', iface_dict) virsh.update_device(domainarg=vm_name, filearg=new_xml, debug=True) logging.debug("check nwfilter-binding after delete the only interface") ret = virsh.nwfilter_binding_list(debug=True) if re.search(r'vnet\d+\s+allow-dhcp-server.*', ret.stdout): test.fail( "vnet binding allow-dhcp-server still exists after detach the interface!" ) utlv.check_exit_status(ret, status_error) # attach new interface attach_new_device() ret = virsh.nwfilter_binding_list(debug=True) logging.debug("Check nwfilter-binding exists after attach device") utlv.check_result(ret, expected_match=[r"vnet\d+\s+clean-traffic"]) finally: if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ Test mtu feature from virtual network """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) mtu_type = params.get('mtu_type') mtu_size = params.get('mtu_size', '') net = params.get('net', DEFAULT_NET) net_type = params.get('net_type', '') with_iface = 'yes' == params.get('with_iface', 'no') with_net = 'yes' == params.get('with_net', 'no') status_error = 'yes' == params.get('status_error', 'no') check = params.get('check', '') error_msg = params.get('error_msg', '') bridge_name = 'br_mtu' + utils_misc.generate_random_string(3) add_pkg = params.get('add_pkg', '') model = params.get('model', 'virtio') def set_network(size, net='default'): """ Set mtu size to a certain network """ logging.info('Set mtu size of network "%s" to %s', net, size) default_xml = NetworkXML.new_from_net_dumpxml(net) default_xml.mtu = size default_xml.sync() logging.debug(virsh.net_dumpxml(net)) def set_interface(mtu_size='', source_network='default', iface_type='network', iface_model='virtio'): """ Set mtu size to a certain interface """ interface_type = 'bridge' if iface_type in ( 'bridge', 'openvswitch') else iface_type iface_dict = { 'type': interface_type, 'source': "{'%s': '%s'}" % (interface_type, source_network), 'model': iface_model } if iface_type == 'openvswitch': iface_dict.update({'virtualport_type': 'openvswitch'}) if mtu_size: iface_dict.update({'mtu': "{'size': %s}" % mtu_size}) libvirt.modify_vm_iface(vm_name, 'update_iface', iface_dict) logging.debug(virsh.dumpxml(vm_name).stdout) def get_default_if(): """ Get default interface that is using by vm """ ifaces = utils_net.get_sorted_net_if() logging.debug('Interfaces on host: %s', ifaces) for iface in ifaces[0]: if 'Link detected: yes' in process.run('ethtool %s' % iface).stdout_text: logging.debug('Found host interface "%s"', iface) return iface def create_bridge(): """ Create a bridge on host for test """ cmd_create_br = 'nmcli con add type bridge con-name %s ifname %s' con_name = 'con_' + utils_misc.generate_random_string(3) bridge_name = 'br_' + utils_misc.generate_random_string(3) process.run(cmd_create_br % (con_name, bridge_name), verbose=True) return con_name, bridge_name def create_network_xml(name, network_type, base_if='', **kwargs): """ Create a network xml to be defined """ m_net = NetworkXML(name) m_net.forward = {'mode': 'bridge'} if network_type in ('bridge', 'openvswitch'): m_net.bridge = {'name': kwargs['bridge_name']} elif network_type == 'macvtap': if base_if: m_net.forward_interface = [{'dev': base_if}] if network_type == 'openvswitch': m_net.virtualport_type = 'openvswitch' if 'mtu' in kwargs: m_net.mtu = kwargs['mtu'] logging.debug(m_net) return m_net.xml def create_iface(iface_type, **kwargs): """ Create a interface to be attached to vm """ m_iface = Interface(iface_type) m_iface.mac_address = utils_net.generate_mac_address_simple() if 'base_if' in kwargs: m_iface.source = {'dev': kwargs['base_if'], 'mode': 'vepa'} if 'source_net' in kwargs: m_iface.source = {'network': kwargs['source_net']} if 'mtu' in kwargs: m_iface.mtu = {'size': kwargs['mtu']} if 'model_net' in kwargs: m_iface.model = kwargs['model_net'] logging.debug(m_iface.get_xml()) logging.debug(m_iface) return m_iface def check_mtu(mtu_size, qemu=False): """ Check if mtu meets expectation on host """ error = '' live_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_xml = live_vmxml.get_devices('interface')[0] logging.debug(iface_xml.target) dev = iface_xml.target['dev'] ifconfig_info = process.run('ifconfig|grep mtu|grep %s' % dev, shell=True, verbose=True).stdout_text if 'mtu %s' % mtu_size in ifconfig_info: logging.info('PASS on ifconfig check for vnet.') else: error += 'Fail on ifconfig check for vnet.' if qemu: qemu_mtu_info = process.run('ps aux|grep qemu-kvm', shell=True, verbose=True).stdout_text if 'host_mtu=%s' % mtu_size in qemu_mtu_info: logging.info('PASS on qemu cmd line check.') else: error += 'Fail on qemu cmd line check.' if error: test.fail(error) def check_mtu_in_vm(fn_login, mtu_size): """ Check if mtu meets expectations in vm """ session = fn_login() check_cmd = 'ifconfig' output = session.cmd(check_cmd) session.close() logging.debug(output) if 'mtu %s' % mtu_size not in output: test.fail('MTU check inside vm failed.') else: logging.debug("MTU check inside vm passed.") try: bk_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bk_netxml = NetworkXML.new_from_net_dumpxml(DEFAULT_NET) if add_pkg: add_pkg = add_pkg.split() if 'openvswitch' in add_pkg and shutil.which('ovs-vsctl'): new_pkg = add_pkg.copy() new_pkg.remove('openvswitch') utils_package.package_install(new_pkg) if 'openvswitch' in add_pkg: br = 'ovsbr0' + utils_misc.generate_random_string(3) process.run('systemctl start openvswitch.service', shell=True, verbose=True) process.run('ovs-vsctl add-br %s' % br, shell=True, verbose=True) process.run('ovs-vsctl show', shell=True, verbose=True) if not check or check in ['save', 'managedsave', 'hotplug_save']: # Create bridge or network and set mtu iface_type = 'network' if net_type in ('bridge', 'openvswitch'): if net_type == 'bridge': params['con_name'], br = create_bridge() if mtu_type == 'network': test_net = create_network_xml(bridge_name, net_type, bridge_name=br) virsh.net_create(test_net, debug=True) virsh.net_dumpxml(bridge_name, debug=True) if mtu_type == 'interface': iface_type = net_type bridge_name = br elif net_type == 'network': if mtu_type == 'network': set_network(mtu_size) iface_mtu = 0 if mtu_type == 'interface': iface_mtu = mtu_size if mtu_type == 'network' and with_iface: mtu_size = str(int(mtu_size) // 2) iface_mtu = mtu_size source_net = bridge_name if net_type in ( 'bridge', 'openvswitch') else 'default' # set mtu in vm interface set_interface(iface_mtu, source_network=source_net, iface_type=iface_type, iface_model=model) vm.start() vm_login = vm.wait_for_serial_login if net_type in ( 'bridge', 'openvswitch') else vm.wait_for_login vm_login().close() check_qemu = True if mtu_type == 'interface' else False # Test mtu after save vm if check in ('save', 'hotplug_save'): if check == 'hotplug_save': iface = create_iface('network', source_net='default', mtu=mtu_size, model_net=model) params['mac'] = iface.mac_address virsh.attach_device(vm_name, iface.xml, debug=True) virsh.dumpxml(vm_name, debug=True) dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) if params['mac'] not in str(dom_xml): test.fail('Failed to attach interface with mtu') save_path = os.path.join(data_dir.get_tmp_dir(), vm_name + '.save') virsh.save(vm_name, save_path, debug=True) virsh.restore(save_path, debug=True) if check == 'managedsave': virsh.managedsave(vm_name, debug=True) virsh.start(vm_name, debug=True) # Check in both host and vm check_mtu(mtu_size, check_qemu) if mtu_type == 'interface' or with_iface: check_mtu_in_vm(vm_login, mtu_size) vm_login(timeout=60).close() if check == 'hotplug_save': virsh.detach_interface(vm_name, 'network %s' % params['mac'], debug=True) time.sleep(5) dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) if params['mac'] in str(dom_xml): test.fail( 'Failed to detach interface with mtu after save-restore' ) else: hotplug = 'yes' == params.get('hotplug', 'False') if check == 'net_update': result = virsh.net_update(DEFAULT_NET, 'modify', 'mtu', '''"<mtu size='%s'/>"''' % mtu_size, debug=True) if check in ('macvtap', 'bridge_net', 'ovswitch_net'): base_if = get_default_if() macv_name = 'direct-macvtap' + utils_misc.generate_random_string( 3) # Test mtu in different type of network if mtu_type == 'network': if check == 'macvtap': test_net = create_network_xml(macv_name, 'macvtap', base_if, mtu=mtu_size) if check == 'bridge_net': params['con_name'], br = create_bridge() test_net = create_network_xml(bridge_name, 'bridge', mtu=mtu_size, bridge_name=br) if check == 'ovswitch_net': test_net = create_network_xml(bridge_name, 'openvswitch', mtu=mtu_size, bridge_name=br) if 'net_create' in params['id']: result = virsh.net_create(test_net, debug=True) if 'net_define' in params['id']: result = virsh.net_define(test_net, debug=True) # Test mtu with or without a binding network elif mtu_type == 'interface': vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if with_net: test_net = create_network_xml(macv_name, 'macvtap', base_if) virsh.net_create(test_net, debug=True) iface = create_iface('network', source_net=macv_name, mtu=mtu_size, model_net=model) if hotplug: result = virsh.attach_device(vm_name, iface.xml, debug=True) else: vmxml.add_device(iface) vmxml.sync() result = virsh.start(vm_name) else: iface = create_iface('direct', base_if=base_if, mtu=mtu_size, model_net=model) if hotplug: result = virsh.attach_device(vm_name, iface.xml, debug=True) else: vmxml.add_device(iface) result = virsh.define(vmxml.xml, debug=True) if check == 'invalid_val': iface = create_iface('network', source_net='default', mtu=mtu_size, model_net=model) result = virsh.attach_device(vm_name, iface.xml, debug=True) # Check result libvirt.check_exit_status(result, status_error) libvirt.check_result(result, [error_msg]) finally: bk_xml.sync() bk_netxml.sync() if 'test_net' in locals(): virsh.net_destroy(bridge_name, debug=True) if params.get('con_name'): process.run('nmcli con del %s' % params['con_name'], verbose=True) if add_pkg: process.run("ovs-vsctl del-br %s" % br, verbose=True) utils_package.package_remove(add_pkg)
def run(test, params, env): """ Test virsh interface related commands. (1) If using given exist interface for testing(eg. lo or ethX): 1.1 Dumpxml for the interface(with --inactive option) 1.2 Destroy the interface 1.3 Undefine the interface (2) Define an interface from XML file (3) List interfaces with '--inactive' optioin (4) Start the interface (5) List interfaces with no option (6) Dumpxml for the interface (7) Get interface MAC address by interface name (8) Get interface name by interface MAC address (9) Delete interface if not use the exist interface for testing 9.1 Destroy the interface 9.2 Undefine the interface Caveat, this test may affect the host network, so using the loopback(lo) device by default. You can specify the interface which you want, but be careful. """ iface_name = params.get("iface_name", "ENTER.BRIDGE.NAME") iface_xml = params.get("iface_xml") iface_type = params.get("iface_type", "ethernet") iface_pro = params.get("iface_pro", "") iface_eth = params.get("iface_eth", "") iface_tag = params.get("iface_tag", "0") if iface_type == "vlan": iface_name = iface_eth + "." + iface_tag iface_eth_using = "yes" == params.get("iface_eth_using", "no") ping_ip = params.get("ping_ip", "localhost") use_exist_iface = "yes" == params.get("use_exist_iface", "no") status_error = "yes" == params.get("status_error", "no") net_restart = "yes" == params.get("iface_net_restart", "no") list_dumpxml_acl = "yes" == params.get("list_dumpxml_acl", "no") if ping_ip.count("ENTER"): raise error.TestNAError("Please input a valid ip address") if iface_name.count("ENTER"): raise error.TestNAError("Please input a existing bridge/ethernet name") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user', "EXAMPLE") if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' if not libvirt_version.version_compare(1, 1, 1): if params.get('setup_libvirt_polkit') == 'yes': raise error.TestNAError("API acl test not supported in current" + " libvirt version.") virsh_dargs = {'debug': True} list_dumpxml_dargs = {'debug': True} if params.get('setup_libvirt_polkit') == 'yes': if not list_dumpxml_acl: virsh_dargs['uri'] = uri virsh_dargs['unprivileged_user'] = unprivileged_user else: list_dumpxml_dargs['uri'] = uri list_dumpxml_dargs['unprivileged_user'] = unprivileged_user list_dumpxml_dargs['ignore_status'] = False # acl api negative testing params write_save_status_error = "yes" == params.get("write_save_status_error", "no") start_status_error = "yes" == params.get("start_status_error", "no") stop_status_error = "yes" == params.get("stop_status_error", "no") delete_status_error = "yes" == params.get("delete_status_error", "no") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm: xml_bak = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) iface_script = NETWORK_SCRIPT + iface_name iface_script_bk = os.path.join(test.tmpdir, "iface-%s.bk" % iface_name) net_bridge = utils_net.Bridge() if use_exist_iface: if iface_type == "bridge": if iface_name not in net_bridge.list_br(): raise error.TestError("Bridge '%s' not exists" % iface_name) ifaces = net_bridge.get_structure()[iface_name] if len(ifaces) < 1: # In this situation, dhcp maybe cannot get ip address # Unless you use static, we'd better skip such case raise error.TestNAError("Bridge '%s' has no interface" " bridged, perhaps cannot get" " ipaddress" % iface_name) net_iface = utils_net.Interface(name=iface_name) iface_is_up = True list_option = "--all" if use_exist_iface: if not libvirt.check_iface(iface_name, "exists", "--all"): raise error.TestError("Interface '%s' not exists" % iface_name) iface_xml = os.path.join(test.tmpdir, "iface.xml.tmp") iface_is_up = net_iface.is_up() else: # Note, if not use the interface which already exists, iface_name must # be equal to the value specified in XML file if libvirt.check_iface(iface_name, "exists", "--all"): raise error.TestError("Interface '%s' already exists" % iface_name) if not iface_xml: raise error.TestError("XML file is needed.") iface_xml = os.path.join(test.tmpdir, iface_xml) create_xml_file(iface_xml, params) # Stop NetworkManager as which may conflict with virsh iface commands try: NM = utils_misc.find_command("NetworkManager") except ValueError: logging.debug("No NetworkManager service.") NM = None NM_is_running = False if NM is not None: NM_service = service.Factory.create_service("NetworkManager") NM_is_running = NM_service.status() if NM_is_running: NM_service.stop() # run test cases try: if use_exist_iface: # back up the interface script utils.run("cp %s %s" % (iface_script, iface_script_bk)) # step 1.1 # dumpxml for interface if list_dumpxml_acl: virsh.iface_list(**list_dumpxml_dargs) xml = virsh.iface_dumpxml(iface_name, "--inactive", to_file=iface_xml, **list_dumpxml_dargs) # Step 1.2 # Destroy interface if iface_is_up: result = virsh.iface_destroy(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and stop_status_error): # acl_test negative test libvirt.check_exit_status(result, stop_status_error) virsh.iface_destroy(iface_name, debug=True) else: libvirt.check_exit_status(result, status_error) # Step 1.3 # Undefine interface result = virsh.iface_undefine(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and delete_status_error): # acl_test negative test libvirt.check_exit_status(result, delete_status_error) virsh.iface_undefine(iface_name, debug=True) else: libvirt.check_exit_status(result, status_error) if not status_error: if libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("%s is still present." % iface_name) # Step 2 # Define interface result = virsh.iface_define(iface_xml, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and write_save_status_error): # acl_test negative test libvirt.check_exit_status(result, write_save_status_error) virsh.iface_define(iface_xml, debug=True) elif iface_type == "bond" and not ping_ip: libvirt.check_exit_status(result, True) return else: libvirt.check_exit_status(result, status_error) if net_restart: network = service.Factory.create_service("network") network.restart() # After network restart, (ethernet)interface will be started if (not net_restart and iface_type in ("bridge", "ethernet")) or\ (not use_exist_iface and iface_type in ("vlan", "bond")): # Step 3 # List inactive interfaces list_option = "--inactive" if not status_error: if not libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("Fail to find %s." % iface_name) # Step 4 # Start interface result = virsh.iface_start(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and start_status_error): # acl_test negative test libvirt.check_exit_status(result, start_status_error) virsh.iface_start(iface_name, debug=True) elif (not net_restart and not use_exist_iface and (iface_type == "ethernet" and iface_pro in ["", "dhcp"] or iface_type == "bridge" and iface_pro == "dhcp")): libvirt.check_exit_status(result, True) else: libvirt.check_exit_status(result, status_error) if not status_error: iface_ip = net_iface.get_ip() ping_ip = ping_ip if not iface_ip else iface_ip if ping_ip: if not libvirt.check_iface(iface_name, "ping", ping_ip): raise error.TestFail("Ping %s fail." % ping_ip) # Step 5 # List active interfaces if use_exist_iface or\ (iface_pro != "dhcp" and iface_type == "bridge") or\ (iface_eth_using and iface_type == "vlan"): list_option = "" if not status_error: if not libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("Fail to find %s in active " "interface list" % iface_name) if vm: iface_mac_list = vm_xml.VMXML.get_iface_dev(vm_name) # Before test, detach all interfaces in guest for mac in iface_mac_list: iface_info = vm_xml.VMXML.get_iface_by_mac(vm_name, mac) type = iface_info.get('type') virsh.detach_interface(vm_name, "--type %s --mac %s" " --config" % (type, mac)) virsh.attach_interface(vm_name, "--type %s --source %s" " --config" % (iface_type, iface_name)) vm.start() try: # Test if guest can be login vm.wait_for_login() except remote.LoginError: raise error.TestFail("Cannot login guest with %s" % iface_name) # Step 6 # Dumpxml for interface if list_dumpxml_acl: virsh.iface_list(**list_dumpxml_dargs) xml = virsh.iface_dumpxml(iface_name, "", to_file="", **list_dumpxml_dargs) logging.debug("Interface '%s' XML:\n%s", iface_name, xml) # Step 7 # Get interface MAC address by name result = virsh.iface_mac(iface_name, debug=True) libvirt.check_exit_status(result, status_error) if not status_error and result.stdout.strip(): if not libvirt.check_iface(iface_name, "mac", result.stdout.strip()): raise error.TestFail("Mac address check fail") # Step 8 # Get interface name by MAC address # Bridge's Mac equal to bridged interface's mac if iface_type not in ("bridge", "vlan") and result.stdout.strip(): iface_mac = net_iface.get_mac() result = virsh.iface_name(iface_mac, debug=True) libvirt.check_exit_status(result, status_error) # Step 9 if not use_exist_iface: # Step 9.1 # Destroy interface result = virsh.iface_destroy(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and stop_status_error): # acl_test negative test libvirt.check_exit_status(result, stop_status_error) virsh.iface_destroy(iface_name, debug=True) elif (not net_restart and iface_type == "ethernet" and iface_pro in ["", "dhcp"] or iface_type == "bridge" and iface_pro == "dhcp"): libvirt.check_exit_status(result, True) else: libvirt.check_exit_status(result, status_error) # Step 9.2 # Undefine interface result = virsh.iface_undefine(iface_name, **virsh_dargs) if (params.get('setup_libvirt_polkit') == 'yes' and delete_status_error): # acl_test negative test libvirt.check_exit_status(result, delete_status_error) virsh.iface_undefine(iface_name, debug=True) else: libvirt.check_exit_status(result, status_error) list_option = "--all" if not status_error: if libvirt.check_iface(iface_name, "exists", list_option): raise error.TestFail("%s is still present." % iface_name) finally: if os.path.exists(iface_xml): os.remove(iface_xml) if os.path.exists(iface_script): os.remove(iface_script) if use_exist_iface: if not os.path.exists(iface_script): utils.run("mv %s %s" % (iface_script_bk, iface_script)) if iface_is_up and\ not libvirt.check_iface(iface_name, "exists", ""): # Need reload script utils.run("ifup %s" % iface_name) elif not iface_is_up and libvirt.check_iface(iface_name, "exists", ""): net_iface.down() if vm: xml_bak.sync() else: if libvirt.check_iface(iface_name, "exists", "--all"): # Remove the interface try: utils_net.bring_down_ifname(iface_name) except utils_net.TAPBringDownError: pass if iface_type == "bridge": if iface_name in net_bridge.list_br(): try: net_bridge.del_bridge(iface_name) except IOError: pass if NM_is_running: NM_service.start()
def run(test, params, env): """ Test virsh {at|de}tach-interface command. 1) Prepare test environment and its parameters 2) Attach the required interface 3) According test type(only attach or both attach and detach): a.Go on to test detach(if attaching is correct) b.Return GOOD or raise TestFail(if attaching is wrong) 4) Check if attached interface is correct: a.Try to catch it in vm's XML file b.Try to catch it in vm 5) Detach the attached interface 6) Check result """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) backup_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Test parameters uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) vm_ref = params.get("at_detach_iface_vm_ref", "domname") options_suffix = params.get("at_detach_iface_options_suffix", "") status_error = "yes" == params.get("status_error", "no") start_vm = params.get("start_vm") # Should attach must be pass for detach test. correct_attach = "yes" == params.get("correct_attach", "no") readonly = ("yes" == params.get("readonly", "no")) # Interface specific attributes. iface_type = params.get("at_detach_iface_type", "network") iface_source = params.get("at_detach_iface_source", "default") iface_mode = params.get("at_detach_iface_mode", "vepa") iface_mac = params.get("at_detach_iface_mac", "created") iface_target = params.get("at_detach_iface_target") iface_model = params.get("at_detach_iface_model") iface_inbound = params.get("at_detach_iface_inbound") iface_outbound = params.get("at_detach_iface_outbound") iface_rom = params.get("at_detach_rom_bar") iface_link = params.get("at_detach_link_state") iface_boot = params.get("at_detach_boot_order") iface_driver = params.get("at_detach_iface_driver") iface_driver_host = params.get("at_detach_driver_host") iface_driver_guest = params.get("at_detach_driver_guest") iface_backend = params.get("at_detach_iface_backend") save_restore = params.get("save_restore", "no") restart_libvirtd = params.get("restart_libvirtd", "no") attach_cmd = params.get("attach_cmd", "attach-interface") virsh_dargs = {'ignore_status': True, 'debug': True, 'uri': uri} validate_xml_result = "yes" == params.get("check_xml_result", "no") paused_after_vm_start = "yes" == params.get("paused_after_vm_start", "no") machine_type = params.get("machine_type") # Get iface name if iface_type is direct if iface_type == "direct": iface_source = utils_net.get_net_if(state="UP")[0] # Get a bridge name for test if iface_type is bridge. # If there is no bridge other than virbr0, try to create one # or fail test if iface_type == "bridge": host_bridge = utils_net.Bridge() bridge_list = host_bridge.list_br() try: bridge_list.remove("virbr0") except AttributeError: pass # If no virbr0, just pass is ok logging.debug("Useful bridges:%s", bridge_list) if len(bridge_list): iface_source = bridge_list[0] else: process.run('ip link add name br0 type bridge', ignore_status=False) iface_source = 'br0' logging.debug("Added bridge br0") # Test both detach and attach, So collect info # both of them for result check. # When something wrong with interface, set it to 1 fail_flag = 0 result_info = [] # Get a mac address if iface_mac is 'created'. if iface_mac == "created" or correct_attach: iface_mac = utils_net.generate_mac_address_simple() names = locals() iface_format = get_formatted_iface_dict(names, params.get("vm_arch_name")) # for rtl8139 model, need to add pcie bridge if iface_model == "rtl8139" and machine_type == "q35": add_pcie_controller(vm_name) if start_vm == "yes" and not vm.is_alive(): vm.start() try: # Generate xml file if using attach-device command if attach_cmd == "attach-device": # Change boot order to disk libvirt.change_boot_order(vm_name, "disk", "1") vm.destroy() vm.start() # Generate attached xml new_iface = Interface(type_name=iface_type) xml_file_tmp = libvirt.modify_vm_iface(vm_name, "get_xml", iface_format) new_iface.xml = xml_file_tmp new_iface.del_address() xml_file = new_iface.xml # To confirm vm's state and make sure os fully started if start_vm == "no": if vm.is_alive(): vm.destroy() else: vm.wait_for_login().close() if paused_after_vm_start: vm.pause() # Set attach-interface domain dom_uuid = vm.get_uuid() dom_id = vm.get_id() if vm_ref == "domname": vm_ref = vm_name elif vm_ref == "domid": vm_ref = dom_id elif vm_ref == "domuuid": vm_ref = dom_uuid elif vm_ref == "hexdomid" and dom_id is not None: vm_ref = hex(int(dom_id)) # Set attach-interface options and Start attach-interface test if correct_attach: options = set_options("network", "default", iface_mac, "", "attach", None, iface_model) if readonly: virsh_dargs.update({'readonly': True, 'debug': True}) attach_result = virsh.attach_interface(vm_name, options, **virsh_dargs) else: if attach_cmd == "attach-interface": options = set_options(iface_type, iface_source, iface_mac, options_suffix, "attach", iface_target, iface_model, iface_inbound, iface_outbound) attach_result = virsh.attach_interface(vm_ref, options, **virsh_dargs) elif attach_cmd == "attach-device": attach_result = virsh.attach_device(vm_name, xml_file, ignore_status=True, debug=True) attach_status = attach_result.exit_status logging.debug(attach_result) # If attach interface failed. if attach_status: if not status_error: fail_flag = 1 result_info.append("Attach Failed: %s" % attach_result.stderr) elif status_error: # Here we just use it to exit, do not mean test failed fail_flag = 1 # If attach interface succeeded. else: if status_error and not correct_attach: fail_flag = 1 result_info.append("Attach Success with wrong command.") if fail_flag and start_vm == "yes": vm.destroy() if len(result_info): test.fail(result_info) else: # Exit because it is error_test for attach-interface. return if "print-xml" in options_suffix: iface_obj = Interface(type_name=iface_type) iface_obj.xml = attach_result.stdout.strip() if (iface_obj.type_name == iface_type and iface_obj.source['dev'] == iface_source and iface_obj.target['dev'] == iface_target and iface_obj.model == iface_model and iface_obj.bandwidth.inbound == eval( iface_format['inbound']) and iface_obj.bandwidth.outbound == eval( iface_format['outbound'])): logging.info("Print ml all element check pass") else: test.fail("Print xml do not show as expected") # Check dumpxml file whether the interface is added successfully. status, ret = check_dumpxml_iface(vm_name, iface_format) if "print-xml" not in options_suffix: # Check validate_xml_result flag to determine whether apply check_interface_xml. if validate_xml_result: # If options_suffix contains config, it need dump inactive xml. is_active = True if options_suffix.count("config"): is_active = False # Check dumping VM xml value. if not check_interface_xml(vm_name, iface_type, iface_source, iface_mac, is_active): test.fail( "Failed to find matched interface values in VM interface xml" ) if status: fail_flag = 1 result_info.append(ret) else: if status == 0: test.fail( "Attach interface effect in xml with print-xml option") else: return # Login to domain to check new interface. if not vm.is_alive(): vm.start() elif vm.state() == "paused": vm.resume() vm.wait_for_login().close() status, ret = login_to_check(vm, iface_mac) if status: fail_flag = 1 result_info.append(ret) # Check on host for direct type if iface_type == 'direct': cmd_result = process.run( "ip -d link show test").stdout_text.strip() logging.info("cmd output is %s", cmd_result) check_patten = ( "%s@%s.*\n.*%s.*\n.*macvtap.*mode.*%s" % (iface_target, iface_source, iface_mac, iface_mode)) logging.info("check patten is %s", check_patten) if not re.search(check_patten, cmd_result): logging.error("Can not find %s in ip link" % check_patten) fail_flag = 1 result_info.append(cmd_result) # Do operation and check again if restart_libvirtd == "yes": libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() if save_restore == "yes": check_save_restore(vm_name) status, ret = check_dumpxml_iface(vm_name, iface_format) if status: fail_flag = 1 result_info.append(ret) # Set detach-interface options options = set_options(iface_type, None, iface_mac, options_suffix, "detach") # Start detach-interface test if save_restore == "yes" and vm_ref == dom_id: vm_ref = vm_name detach_result = virsh.detach_interface(vm_ref, options, **virsh_dargs) detach_status = detach_result.exit_status detach_msg = detach_result.stderr.strip() logging.debug(detach_result) if detach_status == 0 and status_error == 0: # If command with --config parameter, ignore below checking. if options_suffix.count("config"): return # Check the xml after detach and clean up if needed. time.sleep(5) status, _ = check_dumpxml_iface(vm_name, iface_format) if status == 0: detach_status = 1 detach_msg = "xml still exist after detach" cleanup_options = "--type %s --mac %s" % (iface_type, iface_mac) virsh.detach_interface(vm_ref, cleanup_options, **virsh_dargs) else: logging.info("After detach, the interface xml disappeared") # Check results. if status_error: if detach_status == 0: test.fail("Detach Success with wrong command.") else: if detach_status != 0: test.fail("Detach Failed: %s" % detach_msg) else: if fail_flag: test.fail("Attach-Detach Success but " "something wrong with its " "functional use:%s" % result_info) finally: if vm.is_alive(): vm.destroy() backup_xml.sync()
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm.is_alive(): vm.wait_for_login() def create_iface_xml(mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) iface.source = iface_source iface.model = iface_model if iface_model else "virtio" if iface_target: iface.target = {'dev': iface_target} iface.mac_address = mac logging.debug("Create new interface xml: %s", iface) return iface status_error = "yes" == params.get("status_error", "no") # Interface specific attributes. iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_source = eval(params.get("iface_source", "{'network':'default'}")) iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_mac = params.get("iface_mac") attach_device = "yes" == params.get("attach_device", "no") attach_iface = "yes" == params.get("attach_iface", "no") attach_option = params.get("attach_option", "") detach_device = "yes" == params.get("detach_device") stress_test = "yes" == params.get("stress_test") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") username = params.get("username") password = params.get("password") poll_timeout = int(params.get("poll_timeout", 10)) # stree_test require detach operation stress_test_detach_device = False stress_test_detach_interface = False if stress_test: if attach_device: stress_test_detach_device = True if attach_iface: stress_test_detach_interface = True # The following detach-device step also using attach option detach_option = attach_option # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) #iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) libvirtd = utils_libvirtd.Libvirtd() # Check virsh command option check_cmds = [] if not status_error: if attach_device and attach_option: check_cmds.append(('attach-device', attach_option)) if attach_iface and attach_option: check_cmds.append(('attach-interface', attach_option)) if (detach_device or stress_test_detach_device) and detach_option: check_cmds.append(('detach-device', detach_option)) if stress_test_detach_interface and detach_option: check_cmds.append(('detach-device', detach_option)) for cmd, option in check_cmds: libvirt.virsh_cmd_has_option(cmd, option) try: try: # Attach an interface when vm is running iface_list = [] err_msgs = ("No more available PCI slots", "No more available PCI addresses") if attach_device: for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) if iface_mac: mac = iface_mac else: mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't" " attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): raise error.TestNAError(ret.stderr) elif status_error: continue else: logging.error("Command output %s" % ret.stdout.strip()) raise error.TestFail("Failed to attach-device") elif stress_test: # Detach the device immediately for stress test ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr=detach_option, ignore_status=True) libvirt.check_exit_status(ret) else: iface_list.append({'mac': mac, 'iface_xml': iface_xml_obj}) # Need sleep here for attachment take effect time.sleep(5) elif attach_iface: for i in range(int(iface_num)): logging.info("Try to attach interface loop %s" % i) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug("No more pci slots, can't" " attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): raise error.TestNAError(ret.stderr) elif status_error: continue else: logging.error("Command output %s" % ret.stdout.strip()) raise error.TestFail("Failed to attach-interface") elif stress_test: # Detach the device immediately for stress test options = ("--type %s --mac %s %s" % (iface_type, mac, detach_option)) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) else: iface_list.append({'mac': mac}) # Need sleep here for attachment take effect time.sleep(5) # Restart libvirtd service if restart_libvirtd: libvirtd.restart() vm.cleanup_serial_console() # Start the domain if needed if vm.is_dead(): vm.start() session = vm.wait_for_serial_login(username=username, password=password) # Check if interface was attached for iface in iface_list: if iface.has_key('mac'): # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']) if not if_attr: raise error.TestFail("Can't see interface " " in dumpxml") if (if_attr['type'] != iface_type or if_attr['source'] != iface_source['network']): raise error.TestFail("Interface attribute doesn't" " match attachment opitons") # Check interface on guest if not utils_net.get_linux_ifname(session, iface['mac']): raise error.TestFail("Can't see interface" " on guest") # Detach hot/cold-plugged interface at last if detach_device: for iface in iface_list: if iface.has_key('iface_xml'): ret = virsh.detach_device(vm_name, iface['iface_xml'].xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) else: options = ("%s --mac %s" % (iface_type, iface['mac'])) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) # Check if interface was detached for iface in iface_list: if iface.has_key('mac'): polltime = time.time() + poll_timeout while True: # Check interface in dumpxml output if not vm_xml.VMXML.get_iface_by_mac(vm_name, iface['mac']): break else: time.sleep(2) if time.time() > polltime: test.fail("Interface still " "exists after detachment") session.close() except virt_vm.VMStartError as e: logging.info(str(e)) raise error.TestFail('VM failed to start:\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ convert specific kvm guest to rhev """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') vm_name = params.get('main_vm', 'EXAMPLE') target = params.get('target') remote_host = params.get('remote_host', 'EXAMPLE') output_mode = params.get('output_mode') output_format = params.get('output_format') output_storage = params.get('output_storage', 'default') bridge = params.get('bridge') network = params.get('network') ntp_server = params.get('ntp_server') address_cache = env.get('address_cache') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = utlv.PoolVolumeTest(test, params) v2v_timeout = int(params.get('v2v_timeout', 1200)) skip_check = 'yes' == params.get('skip_check', 'no') status_error = 'yes' == params.get('status_error', 'no') checkpoint = params.get('checkpoint', '') debug_kernel = 'debug_kernel' == checkpoint multi_kernel_list = ['multi_kernel', 'debug_kernel'] backup_list = [ 'virtio_on', 'virtio_off', 'floppy', 'floppy_devmap', 'fstab_cdrom', 'fstab_virtio', 'multi_disks', 'sata_disk', 'network_virtio', 'network_rtl8139', 'network_e1000', 'multi_netcards', 'spice', 'spice_encrypt', 'spice_qxl', 'spice_cirrus', 'vnc_qxl', 'vnc_cirrus', 'blank_2nd_disk', 'listen_none', 'listen_socket', 'only_net', 'only_br' ] error_list = [] def log_fail(msg): """ Log error and update error list """ logging.error(msg) error_list.append(msg) def vm_shell(func): """ Decorator of shell session to vm """ def wrapper(*args, **kwargs): vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_dead(): logging.info('VM is down. Starting it now.') vm.start() session = vm.wait_for_login() kwargs['session'] = session kwargs['vm'] = vm func(*args, **kwargs) if session: session.close() vm.shutdown() return wrapper def check_disks(vmcheck): """ Check disk counts inside the VM """ # Initialize windows boot up os_type = params.get("os_type", "linux") expected_disks = int(params.get("ori_disks", "1")) logging.debug("Expect %s disks im VM after convert", expected_disks) # Get disk counts if os_type == "linux": cmd = "lsblk |grep disk |wc -l" disks = int(vmcheck.session.cmd(cmd).strip()) else: cmd = r"echo list disk > C:\list_disk.txt" vmcheck.session.cmd(cmd) cmd = r"diskpart /s C:\list_disk.txt" output = vmcheck.session.cmd(cmd).strip() logging.debug("Disks in VM: %s", output) disks = len(re.findall('Disk\s\d', output)) logging.debug("Find %s disks in VM after convert", disks) if disks == expected_disks: logging.info("Disk counts is expected") else: log_fail("Disk counts is wrong") @vm_shell def check_vmlinuz_initramfs(v2v_result): """ Check if vmlinuz matches initramfs on multi-kernel case """ logging.info('Checking if vmlinuz matches initramfs') kernels = re.search( 'kernel packages in this guest:.*?(\(kernel.*?\).*?){2,}', v2v_result, re.DOTALL) try: lines = kernels.group(0) kernel_list = re.findall('\((.*?)\)', lines) for kernel in kernel_list: vmlinuz = re.search(r'/boot/vmlinuz-(.*?),', kernel).group(1) initramfs = \ re.search(r'/boot/initramfs-(.*?)\.img', kernel).group(1) logging.debug('vmlinuz version is: %s' % vmlinuz) logging.debug('initramfs version is: %s' % initramfs) if vmlinuz != initramfs: log_fail('vmlinuz not match with initramfs') except Exception as e: test.error('Error on find kernel info \n %s' % str(e)) def check_boot_kernel(vmcheck): """ Check if converted vm use the latest kernel """ current_kernel = vmcheck.session.cmd('uname -r').strip() logging.debug('Current kernel: %s' % current_kernel) if current_kernel == '3.10.0-799.el7.x86_64': logging.debug('The kernel is the latest kernel') else: log_fail('VM should choose lastest kernel not %s' % current_kernel) def check_floppy_exist(vmcheck): """ Check if floppy exists after convertion """ blk = vmcheck.session.cmd('lsblk') logging.info(blk) if not re.search('fd0', blk): log_fail('Floppy not found') def attach_removable_media(type, source, dev): bus = {'cdrom': 'ide', 'floppy': 'fdc', 'disk': 'virtio'} args = { 'driver': 'qemu', 'subdriver': 'raw', 'sourcetype': 'file', 'type': type, 'targetbus': bus[type] } if type == 'cdrom': args.update({'mode': 'readonly'}) config = '' # Join all options together to get command line for key in list(args.keys()): config += ' --%s %s' % (key, args[key]) config += ' --current' virsh.attach_disk(vm_name, source, dev, extra=config) def change_disk_bus(dest): """ Change all disks' bus type to $dest """ bus_list = ['ide', 'sata', 'virtio'] if dest not in bus_list: test.error('Bus type not support') dev_prefix = ['h', 's', 'v'] dev_table = dict(list(zip(bus_list, dev_prefix))) logging.info('Change disk bus to %s' % dest) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.get_disk_all() index = 0 for disk in list(disks.values()): if disk.get('device') != 'disk': continue target = disk.find('target') target.set('bus', dest) target.set('dev', dev_table[dest] + 'd' + string.ascii_lowercase[index]) disk.remove(disk.find('address')) index += 1 vmxml.sync() def change_network_model(model): """ Change network model to $model """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) network_list = vmxml.get_iface_all() for node in list(network_list.values()): if node.get('type') == 'network': node.find('model').set('type', model) vmxml.sync() def attach_network_card(model): """ Attach network card based on model """ if model not in ('e1000', 'virtio', 'rtl8139'): test.error('Network model not support') options = {'type': 'network', 'source': 'default', 'model': model} line = '' for key in options: line += ' --' + key + ' ' + options[key] line += ' --current' logging.debug(virsh.attach_interface(vm_name, option=line)) def check_multi_netcards(mac_list, virsh_instance): """ Check if number and type of network cards meet expectation """ vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=virsh_instance) iflist = vmxml.get_iface_all() logging.debug('MAC list before v2v: %s' % mac_list) logging.debug('MAC list after v2v: %s' % list(iflist.keys())) if set(mac_list).difference(list(iflist.keys())): log_fail('Missing network interface') for mac in iflist: if iflist[mac].find('model').get('type') != 'virtio': log_fail('Network not convert to virtio') @vm_shell def insert_floppy_devicemap(**kwargs): """ Add an entry of floppy to device.map """ session = kwargs['session'] line = '(fd0) /dev/fd0' devmap = '/boot/grub/device.map' if session.cmd_status('ls %s' % devmap): devmap = '/boot/grub2/device.map' cmd_exist = 'grep \'(fd0)\' %s' % devmap cmd_set = 'sed -i \'2i%s\' %s' % (line, devmap) if session.cmd_status(cmd_exist): session.cmd(cmd_set) def make_label(session): """ Label a volume, swap or root volume """ # swaplabel for rhel7 with xfs, e2label for rhel6 or ext* cmd_map = { 'root': 'e2label %s ROOT', 'swap': 'swaplabel -L SWAPPER %s' } if not session.cmd_status('swaplabel --help'): blk = 'swap' elif not session.cmd_status('which e2label'): blk = 'root' else: test.error('No tool to make label') entry = session.cmd('blkid|grep %s' % blk).strip() path = entry.split()[0].strip(':') cmd_label = cmd_map[blk] % path if 'LABEL' not in entry: session.cmd(cmd_label) return blk @vm_shell def specify_fstab_entry(type, **kwargs): """ Specify entry in fstab file """ type_list = ['cdrom', 'uuid', 'label', 'virtio', 'sr0', 'invalid'] if type not in type_list: test.error('Not support %s in fstab' % type) session = kwargs['session'] # Specify cdrom device if type == 'cdrom': line = '/dev/cdrom /media/CDROM auto exec' if 'grub2' in utils_misc.get_bootloader_cfg(session): line += ',nofail' line += ' 0 0' logging.debug('fstab entry is "%s"', line) cmd = [ 'mkdir -p /media/CDROM', 'mount /dev/cdrom /media/CDROM', 'echo "%s" >> /etc/fstab' % line ] for i in range(len(cmd)): session.cmd(cmd[i]) elif type == 'sr0': line = params.get('fstab_content') session.cmd('echo "%s" >> /etc/fstab' % line) elif type == 'invalid': line = utils_misc.generate_random_string(6) session.cmd('echo "%s" >> /etc/fstab' % line) else: map = {'uuid': 'UUID', 'label': 'LABEL', 'virtio': '/vd'} logging.info(type) if session.cmd_status('cat /etc/fstab|grep %s' % map[type]): # Specify device by UUID if type == 'uuid': entry = session.cmd( 'blkid -s UUID|grep swap').strip().split() # Replace path for UUID origin = entry[0].strip(':') replace = entry[1].replace('"', '') # Specify virtio device elif type == 'virtio': entry = session.cmd('cat /etc/fstab|grep /boot').strip() # Get the ID (no matter what, usually UUID) origin = entry.split()[0] key = origin.split('=')[1] blkinfo = session.cmd('blkid|grep %s' % key).strip() # Replace with virtio disk path replace = blkinfo.split()[0].strip(':') # Specify device by label elif type == 'label': blk = make_label(session) entry = session.cmd('blkid|grep %s' % blk).strip() # Remove " from LABEL="****" replace = entry.split()[1].strip().replace('"', '') # Replace the original id/path with label origin = entry.split()[0].strip(':') cmd_fstab = "sed -i 's|%s|%s|' /etc/fstab" % (origin, replace) session.cmd(cmd_fstab) fstab = session.cmd_output('cat /etc/fstab') logging.debug('Content of /etc/fstab:\n%s', fstab) def create_large_file(session, left_space): """ Create a large file to make left space of root less than $left_space MB """ cmd_df = "df -m / --output=avail" df_output = session.cmd(cmd_df).strip() logging.debug('Command output: %s', df_output) avail = int(df_output.strip().split('\n')[-1]) logging.info('Available space: %dM' % avail) if avail > left_space - 1: tmp_dir = data_dir.get_tmp_dir() if session.cmd_status('ls %s' % tmp_dir) != 0: session.cmd('mkdir %s' % tmp_dir) large_file = os.path.join(tmp_dir, 'file.large') cmd_create = 'dd if=/dev/zero of=%s bs=1M count=%d' % \ (large_file, avail - left_space + 2) session.cmd(cmd_create, timeout=v2v_timeout) logging.info('Available space: %sM' % session.cmd(cmd_df).strip()) @vm_shell def corrupt_rpmdb(**kwargs): """ Corrupt rpm db """ session = kwargs['session'] # If __db.* exist, remove them, then touch _db.001 to corrupt db. if not session.cmd_status('ls /var/lib/rpm/__db.001'): session.cmd('rm -f /var/lib/rpm/__db.*') session.cmd('touch /var/lib/rpm/__db.001') if not session.cmd_status('yum update'): test.error('Corrupt rpmdb failed') @vm_shell def grub_serial_terminal(**kwargs): """ Edit the serial and terminal lines of grub.conf """ session = kwargs['session'] vm = kwargs['vm'] grub_file = utils_misc.get_bootloader_cfg(session) if 'grub2' in grub_file: test.cancel('Skip this case on grub2') cmd = "sed -i '1iserial -unit=0 -speed=115200\\n" cmd += "terminal -timeout=10 serial console' %s" % grub_file session.cmd(cmd) @vm_shell def set_selinux(value, **kwargs): """ Set selinux stat of guest """ session = kwargs['session'] current_stat = session.cmd_output('getenforce').strip() logging.debug('Current selinux status: %s', current_stat) if current_stat != value: cmd = "sed -E -i 's/(^SELINUX=).*?/\\1%s/' /etc/selinux/config" % value logging.info('Set selinux stat with command %s', cmd) session.cmd(cmd) @vm_shell def get_firewalld_status(**kwargs): """ Return firewalld service status of vm """ session = kwargs['session'] firewalld_status = session.cmd( 'systemctl status firewalld.service|grep Active:', ok_status=[0, 3]).strip() logging.info('Status of firewalld: %s', firewalld_status) params[checkpoint] = firewalld_status def check_firewalld_status(vmcheck, expect_status): """ Check if status of firewalld meets expectation """ firewalld_status = vmcheck.session.cmd( 'systemctl status ' 'firewalld.service|grep Active:', ok_status=[0, 3]).strip() logging.info('Status of firewalld after v2v: %s', firewalld_status) if firewalld_status != expect_status: log_fail('Status of firewalld changed after conversion') @vm_shell def vm_cmd(cmd_list, **kwargs): """ Excecute a list of commands on guest. """ session = kwargs['session'] for cmd in cmd_list: logging.info('Send command "%s"', cmd) status, output = session.cmd_status_output(cmd) logging.debug('Command output:\n%s', output) if status != 0: test.error('Command "%s" failed' % cmd) logging.info('All commands executed') def check_time_keep(vmcheck): """ Check time drift after convertion. """ logging.info('Check time drift') output = vmcheck.session.cmd('ntpdate -q %s' % ntp_server) logging.debug(output) drift = abs(float(output.split()[-2])) logging.debug('Time drift is: %f', drift) if drift > 3: log_fail('Time drift exceeds 3 sec') def check_boot(): """ Check if guest can boot up after configuration """ try: vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_alive(): vm.shutdown() logging.info('Booting up %s' % vm_name) vm.start() vm.wait_for_login() vm.shutdown() logging.info('%s is down' % vm_name) except Exception as e: test.error('Bootup guest and login failed: %s', str(e)) def check_result(result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout + result.stderr if skip_check: logging.info('Skip checking vm after conversion') elif not status_error: if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt( params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') if output_mode == 'libvirt': try: virsh.start(vm_name, debug=True, ignore_status=False) except Exception as e: test.fail('Start vm failed: %s' % str(e)) # Check guest following the checkpoint document after convertion vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if params.get('skip_check') != 'yes': ret = vmchecker.run() if len(ret) == 0: logging.info("All common checkpoints passed") vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=vmchecker.virsh_instance) logging.debug(vmxml) if checkpoint == 'multi_kernel': check_boot_kernel(vmchecker.checker) if checkpoint == 'floppy': check_floppy_exist(vmchecker.checker) if checkpoint == 'multi_disks': check_disks(vmchecker.checker) if checkpoint == 'multi_netcards': check_multi_netcards(params['mac_address'], vmchecker.virsh_instance) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': vmchecker.check_graphics(params[checkpoint]) else: graph_type = checkpoint.split('_')[0] vmchecker.check_graphics({'type': graph_type}) video_type = vmxml.get_devices('video')[0].model_type if video_type.lower() != 'qxl': log_fail('Video expect QXL, actual %s' % video_type) if checkpoint.startswith('listen'): listen_type = vmxml.get_devices('graphics')[0].listen_type logging.info('listen type is: %s', listen_type) if listen_type != checkpoint.split('_')[-1]: log_fail('listen type changed after conversion') if checkpoint.startswith('selinux'): status = vmchecker.checker.session.cmd( 'getenforce').strip().lower() logging.info('Selinux status after v2v:%s', status) if status != checkpoint[8:]: log_fail('Selinux status not match') if checkpoint == 'guest_firewalld_status': check_firewalld_status(vmchecker.checker, params[checkpoint]) if checkpoint in ['ntpd_on', 'sync_ntp']: check_time_keep(vmchecker.checker) # Merge 2 error lists error_list.extend(vmchecker.errors) log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: v2v_params = { 'hostname': remote_host, 'hypervisor': 'kvm', 'v2v_opts': '-v -x', 'storage': output_storage, 'network': network, 'bridge': bridge, 'target': target, 'main_vm': vm_name, 'input_mode': 'libvirt', 'new_name': vm_name + '_' + utils_misc.generate_random_string(3) } if output_format: v2v_params.update({'output_format': output_format}) # Build rhev related options if output_mode == 'rhev': # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) if output_mode == 'local': v2v_params['storage'] = data_dir.get_tmp_dir() if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') # Set libguestfs environment variable os.environ['LIBGUESTFS_BACKEND'] = 'direct' backup_xml = None if checkpoint in backup_list: backup_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if checkpoint == 'multi_disks': attach_disk_path = os.path.join(data_dir.get_tmp_dir(), 'attach_disks') utlv.attach_disks(env.get_vm(vm_name), attach_disk_path, None, params) new_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) disk_count = 0 for disk in list(new_xml.get_disk_all().values()): if disk.get('device') == 'disk': disk_count += 1 params['ori_disks'] = disk_count if checkpoint == 'virtio_on': change_disk_bus('virtio') if checkpoint == 'virtio_off': change_disk_bus('ide') if checkpoint == 'sata_disk': change_disk_bus('sata') if checkpoint.startswith('floppy'): img_path = data_dir.get_tmp_dir() + '/floppy.img' utlv.create_local_disk('floppy', img_path) attach_removable_media('floppy', img_path, 'fda') if checkpoint == 'floppy_devmap': insert_floppy_devicemap() if checkpoint.startswith('fstab'): if checkpoint == 'fstab_cdrom': img_path = data_dir.get_tmp_dir() + '/cdrom.iso' utlv.create_local_disk('iso', img_path) attach_removable_media('cdrom', img_path, 'hdc') if checkpoint == 'fstab_virtio': change_disk_bus('virtio') specify_fstab_entry(checkpoint[6:]) if checkpoint == 'running': virsh.start(vm_name) logging.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'paused': virsh.start(vm_name, '--paused') logging.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'serial_terminal': grub_serial_terminal() check_boot() if checkpoint == 'no_space': @vm_shell def take_space(**kwargs): create_large_file(kwargs['session'], 20) take_space() if checkpoint.startswith('host_no_space'): session = aexpect.ShellSession('sh') create_large_file(session, 1000) if checkpoint == 'host_no_space_setcache': logging.info('Set LIBGUESTFS_CACHEDIR=/home') os.environ['LIBGUESTFS_CACHEDIR'] = '/home' if checkpoint == 'corrupt_rpmdb': corrupt_rpmdb() if checkpoint.startswith('network'): change_network_model(checkpoint[8:]) if checkpoint == 'multi_netcards': attach_network_card('virtio') attach_network_card('e1000') params['mac_address'] = [] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) network_list = vmxml.get_iface_all() for mac in network_list: if network_list[mac].get('type') == 'network': params['mac_address'].append(mac) if len(params['mac_address']) < 2: test.error('Not enough network interface') logging.debug('MAC address: %s' % params['mac_address']) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': spice_passwd = { 'type': 'spice', 'passwd': params.get('spice_passwd', 'redhat') } vm_xml.VMXML.set_graphics_attr(vm_name, spice_passwd) params[checkpoint] = { 'type': 'spice', 'passwdValidTo': '1970-01-01T00:00:01' } else: graphic_video = checkpoint.split('_') graphic = graphic_video[0] logging.info('Set graphic type to %s', graphic) vm_xml.VMXML.set_graphics_attr(vm_name, {'type': graphic}) if len(graphic_video) > 1: video_type = graphic_video[1] logging.info('Set video type to %s', video_type) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) video = vmxml.xmltreefile.find('devices').find( 'video').find('model') video.set('type', video_type) vmxml.sync() if checkpoint.startswith('listen'): listen_type = checkpoint.split('_')[-1] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) listen = vmxml.xmltreefile.find('devices').find('graphics').find( 'listen') listen.set('type', listen_type) vmxml.sync() if checkpoint == 'host_selinux_on': params['selinux_stat'] = utils_selinux.get_status() utils_selinux.set_status('enforcing') if checkpoint.startswith('selinux'): set_selinux(checkpoint[8:]) if checkpoint.startswith('host_firewalld'): service_mgr = service.ServiceManager() logging.info('Backing up firewall services status') params['bk_firewalld_status'] = service_mgr.status('firewalld') if 'start' in checkpoint: service_mgr.start('firewalld') if 'stop' in checkpoint: service_mgr.stop('firewalld') if checkpoint == 'guest_firewalld_status': get_firewalld_status() if checkpoint == 'remove_securetty': logging.info('Remove /etc/securetty file from guest') cmd = ['rm -f /etc/securetty'] vm_cmd(cmd) if checkpoint == 'ntpd_on': logging.info('Set service ntpd on') cmd = ['yum -y install ntp', 'systemctl start ntpd'] vm_cmd(cmd) if checkpoint == 'sync_ntp': logging.info('Sync time with %s', ntp_server) cmd = ['yum -y install ntpdate', 'ntpdate %s' % ntp_server] vm_cmd(cmd) if checkpoint == 'blank_2nd_disk': disk_path = os.path.join(data_dir.get_tmp_dir(), 'blank.img') logging.info('Create blank disk %s', disk_path) process.run('truncate -s 1G %s' % disk_path) logging.info('Attach blank disk to vm') attach_removable_media('disk', disk_path, 'vdc') logging.debug(virsh.dumpxml(vm_name)) if checkpoint in ['only_net', 'only_br']: logging.info('Detatch all networks') virsh.detach_interface(vm_name, 'network --current', debug=True) logging.info('Detatch all bridges') virsh.detach_interface(vm_name, 'bridge --current', debug=True) if checkpoint == 'only_net': logging.info('Attach network') virsh.attach_interface(vm_name, 'network default --current', debug=True) v2v_params.pop('bridge') if checkpoint == 'only_br': logging.info('Attatch bridge') virsh.attach_interface(vm_name, 'bridge virbr0 --current', debug=True) v2v_params.pop('network') if checkpoint == 'no_libguestfs_backend': os.environ.pop('LIBGUESTFS_BACKEND') if checkpoint == 'file_image': vm = env.get_vm(vm_name) disk = vm.get_first_disk_devices() logging.info('Disk type is %s', disk['type']) if disk['type'] != 'file': test.error('Guest is not with file image') virsh.dumpxml(vm_name, debug=True) v2v_result = utils_v2v.v2v_cmd(v2v_params) if v2v_params.get('new_name'): vm_name = params['main_vm'] = v2v_params['new_name'] check_result(v2v_result, status_error) finally: if params.get('vmchecker'): params['vmchecker'].cleanup() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '') if backup_xml: backup_xml.sync() if params.get('selinux_stat') and params['selinux_stat'] != 'disabled': utils_selinux.set_status(params['selinux_stat']) if 'bk_firewalld_status' in params: service_mgr = service.ServiceManager() if service_mgr.status( 'firewalld') != params['bk_firewalld_status']: if params['bk_firewalld_status']: service_mgr.start('firewalld') else: service_mgr.stop('firewalld') if checkpoint.startswith('host_no_space'): large_file = os.path.join(data_dir.get_tmp_dir(), 'file.large') if os.path.isfile(large_file): os.remove(large_file)
cmd = ['yum -y install ntp', 'systemctl start ntpd'] vm_cmd(cmd) if checkpoint == 'sync_ntp': logging.info('Sync time with %s', ntp_server) cmd = ['yum -y install ntpdate', 'ntpdate %s' % ntp_server] vm_cmd(cmd) if checkpoint == 'blank_2nd_disk': disk_path = os.path.join(data_dir.get_tmp_dir(), 'blank.img') logging.info('Create blank disk %s', disk_path) process.run('truncate -s 1G %s' % disk_path) logging.info('Attach blank disk to vm') attach_removable_media('disk', disk_path, 'vdc') logging.debug(virsh.dumpxml(vm_name)) if checkpoint in ['only_net', 'only_br']: logging.info('Detatch all networks') virsh.detach_interface(vm_name, 'network --current', debug=True) logging.info('Detatch all bridges') virsh.detach_interface(vm_name, 'bridge --current', debug=True) if checkpoint == 'only_net': logging.info('Attach network') virsh.attach_interface(vm_name, 'network default --current', debug=True) v2v_params.pop('bridge') if checkpoint == 'only_br': logging.info('Attatch bridge') virsh.attach_interface(vm_name, 'bridge virbr0 --current', debug=True) v2v_params.pop('network') if checkpoint == 'no_libguestfs_backend':
def vm_stress_events(self, event, vm): """ Stress events :param event: event name :param vm: vm object """ dargs = {'ignore_status': True, 'debug': True} for itr in range(self.iterations): if "vcpupin" in event: for vcpu in range(int(self.current_vcpu)): result = virsh.vcpupin(vm.name, vcpu, random.choice(self.host_cpu_list), **dargs) if not self.ignore_status: libvirt.check_exit_status(result) elif "emulatorpin" in event: for vcpu in range(int(self.current_vcpu)): result = virsh.emulatorpin(vm.name, random.choice( self.host_cpu_list), **dargs) if not self.ignore_status: libvirt.check_exit_status(result) elif "suspend" in event: result = virsh.suspend(vm.name, **dargs) if not self.ignore_status: libvirt.check_exit_status(result) time.sleep(self.event_sleep_time) result = virsh.resume(vm.name, **dargs) if not self.ignore_status: libvirt.check_exit_status(result) elif "cpuhotplug" in event: result = virsh.setvcpus(vm.name, self.max_vcpu, "--live", **dargs) if not self.ignore_status: libvirt.check_exit_status(result) exp_vcpu = {'max_config': self.max_vcpu, 'max_live': self.max_vcpu, 'cur_config': self.current_vcpu, 'cur_live': self.max_vcpu, 'guest_live': self.max_vcpu} utils_hotplug.check_vcpu_value( vm, exp_vcpu, option="--live") time.sleep(self.event_sleep_time) result = virsh.setvcpus(vm.name, self.current_vcpu, "--live", **dargs) if not self.ignore_status: libvirt.check_exit_status(result) exp_vcpu = {'max_config': self.max_vcpu, 'max_live': self.max_vcpu, 'cur_config': self.current_vcpu, 'cur_live': self.current_vcpu, 'guest_live': self.current_vcpu} utils_hotplug.check_vcpu_value( vm, exp_vcpu, option="--live") elif "reboot" in event: vm.reboot() elif "nethotplug" in event: for iface_num in range(int(self.iface_num)): logging.debug("Try to attach interface %d" % iface_num) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (self.iface_type, self.iface_source['network'], self.iface_model, mac, self.attach_option)) logging.debug("VM name: %s , Options for Network attach: %s", vm.name, options) ret = virsh.attach_interface(vm.name, options, ignore_status=True) time.sleep(self.event_sleep_time) if not self.ignore_status: libvirt.check_exit_status(ret) if self.detach_option: options = ("--type %s --mac %s %s" % (self.iface_type, mac, self.detach_option)) logging.debug("VM name: %s , Options for Network detach: %s", vm.name, options) ret = virsh.detach_interface(vm.name, options, ignore_status=True) if not self.ignore_status: libvirt.check_exit_status(ret) elif "diskhotplug" in event: for disk_num in range(len(self.device_source_names)): disk = {} disk_attach_error = False disk_name = os.path.join(self.path, vm.name, self.device_source_names[disk_num]) device_source = libvirt.create_local_disk( self.disk_type, disk_name, self.disk_size, disk_format=self.disk_format) disk.update({"format": self.disk_format, "source": device_source}) disk_xml = Disk(self.disk_type) disk_xml.device = self.disk_device disk_xml.driver = {"name": self.disk_driver, "type": self.disk_format} ret = virsh.attach_disk(vm.name, disk["source"], self.device_target[disk_num], self.attach_option, debug=True) if not self.ignore_status: libvirt.check_exit_status(ret, disk_attach_error) if self.detach_option: ret = virsh.detach_disk(vm.name, self.device_target[disk_num], extra=self.detach_option) if not self.ignore_status: libvirt.check_exit_status(ret) libvirt.delete_local_disk(self.disk_type, disk_name) else: raise NotImplementedError
def run(test, params, env): global flag_list, flag_list_abs, update_sec, without_sec global check_sec, check_without_sec, newxml # Basic network params net_name = params.get("net_update_net_name", "updatenet") net_section = params.get("network_section") update_command = params.get("update_command", "add-last") options = params.get("cmd_options", "") net_state = params.get("net_state") use_in_guest = params.get("use_in_guest") iface_type = params.get("iface_type", "network") ip_version = params.get("ip_version", "ipv4") new_start_ip = params.get("start_ip") new_end_ip = params.get("end_ip") parent_index = params.get("parent_index") status_error = params.get("status_error", "no") # dhcp host test new_dhcp_host_ip = params.get("new_dhcp_host_ip") new_dhcp_host_id = params.get("new_dhcp_host_id") new_dhcp_host_name = params.get("new_dhcp_host_name") new_dhcp_host_mac = params.get("new_dhcp_host_mac") # ipv4 range/host test ipv4_range_start = params.get("ori_ipv4_range_start") ipv4_range_end = params.get("ori_ipv4_range_end") ipv4_host_mac = params.get("ori_ipv4_host_mac") ipv4_host_ip = params.get("ori_ipv4_host_ip") ipv4_host_name = params.get("ori_ipv4_host_name") # ipv6 range/host test ipv6_range_start = params.get("ori_ipv6_range_start") ipv6_range_end = params.get("ori_ipv6_range_end") ipv6_host_id = params.get("ori_ipv6_host_id") ipv6_host_name = params.get("ori_ipv6_host_name") ipv6_host_ip = params.get("ori_ipv6_host_ip") # dns test dns_name = params.get("ori_dns_name") dns_value = params.get("ori_dns_value") new_dns_name = params.get("new_dns_name") new_dns_value = params.get("new_dns_value") # srv test srv_service = params.get("ori_srv_service") srv_protocol = params.get("ori_srv_protocol") srv_domain = params.get("ori_srv_domain") srv_target = params.get("ori_srv_target") srv_port = params.get("ori_srv_port") srv_priority = params.get("ori_srv_priority") srv_weight = params.get("ori_srv_weight") new_srv_service = params.get("new_srv_service") new_srv_protocol = params.get("new_srv_protocol") new_srv_domain = params.get("new_srv_domain") new_srv_target = params.get("new_srv_target") new_srv_port = params.get("new_srv_port") new_srv_priority = params.get("new_srv_priority") new_srv_weight = params.get("new_srv_weight") # dns host test dns_hostip = params.get("ori_dns_hostip") dns_hostname = params.get("ori_dns_hostname") dns_hostname2 = params.get("ori_dns_hostname2") # setting for without part without_ip_dhcp = params.get("without_ip_dhcp", "no") without_dns = params.get("without_dns", "no") without_dns_host = params.get("without_dns_host", "no") without_dns_txt = params.get("without_dns_txt", "no") without_dns_srv = params.get("without_dns_srv", "no") # setting for update/check/without section update_sec = params.get("update_sec") check_sec = params.get("check_sec") without_sec = params.get("without_sec") check_without_sec = params.get("check_without_sec") # forward test forward_mode = params.get("forward_mode") forward_iface = params.get("forward_iface", "eth2") # other params error_type = params.get("error_type", "") vm_name = params.get("main_vm") loop_time = int(params.get("loop_time", 1)) check_config_round = params.get("check_config_round", -1) ipv4_host_id = ipv6_host_mac = "" dns_enable = params.get("dns_enable", "yes") guest_iface_num = int(params.get("guest_iface_num", 1)) newxml = "" def get_hostfile(): """ Get the content of hostfile """ logging.info("Checking network hostfile...") hostfile = "/var/lib/libvirt/dnsmasq/%s.hostsfile" % net_name with open(hostfile) as hostfile_d: hostfile = hostfile_d.readlines() return hostfile def find_config(check_file, need_find): """ Find configure in check_file :param check_file: The file that will check :param need_find: If need to find the item in check_file, Boolean """ def _find_config(check_func): def __find_config(*args, **kwargs): logging.info("Checking content of %s", check_file) ret = False item = None with open(check_file) as checkfile_d: while True: check_line = checkfile_d.readline() if not check_line: break (ret, item) = check_func(check_line, *args, **kwargs) if ret: break if not ret: if need_find: test.fail("Fail to find %s in %s" % (item, check_file)) else: logging.info("Can not find %s in %s as expected" % (item, check_file)) return __find_config return _find_config conf_file = "/var/lib/libvirt/dnsmasq/%s.conf" % net_name @find_config(conf_file, True) def check_item(check_line, item): """ Check if the item in config file """ if item in check_line: logging.info("Find %s in %s", item, conf_file) return (True, item) else: return (False, item) host_file = "/var/lib/libvirt/dnsmasq/%s.addnhosts" % net_name @find_config(host_file, True) def check_host(check_line, item): """ Check if the item in host_file """ if re.search(item, check_line): logging.info("Find %s in %s", item, host_file) return (True, item) else: return (False, item) @find_config(conf_file, False) def check_item_absent(check_line, item): """ Check if the item not in config file """ if item in check_line: test.fail("Find %s in %s" % (item, conf_file)) else: return (False, item) @find_config(host_file, False) def check_host_absent(check_line, item): """ Check if the item not in host_file """ if re.search(item, check_line): test.fail("Find %s in %s" % (item, host_file)) else: return (False, item) def section_update(ori_pre, new_pre): """ Deal with update section and without section in func :param ori_pre: prefix of original section parameter name :param new_pre: prefix of new section parameter name """ global flag_list, flag_list_abs, update_sec, without_sec global check_sec, check_without_sec, newxml if update_sec: for sec in update_sec.split(","): newxml = newxml.replace(names[ori_pre+sec], names[new_pre+sec]) if update_command != "delete": check_sec = update_sec if without_sec: for sec_no in without_sec.split(","): newxml = re.sub(sec_no+"=\".*?\"", "", newxml) if update_command == "modify": check_without_sec = without_sec if check_sec: for c_sec in check_sec.split(","): flag_list.append(names[new_pre+c_sec]) if check_without_sec: for c_sec_no in check_without_sec.split(","): flag_list_abs.append(names[ori_pre+c_sec_no]) dns_host_xml = """ <host ip='%s'> <hostname>%s</hostname> <hostname>%s</hostname> </host> """ % (dns_hostip, dns_hostname, dns_hostname2) virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <dns enable='%s'> <txt name='%s' value='%s'/> <srv service='%s' protocol='%s' domain='%s' target='%s' port='%s' priority='%s' weight='%s'/> %s </dns> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='%s' end='%s' /> <host mac='%s' ip='%s' name='%s' /> </dhcp> </ip> <ip family='ipv6' address='2001:db8:ca2:2::1' prefix='64'> <dhcp> <range start='%s' end='%s'/> <host id='%s' name='%s' ip='%s'/> </dhcp> </ip> <route family='ipv6' address='2001:db8:ca2:2::' prefix='64' gateway='2001:db8:ca2:2::4'/> <ip address='192.168.101.1' netmask='255.255.255.0'/> <ip family='ipv6' address='2001:db8:ca2:3::1' prefix='64' /> </network> """ % (net_name, net_name, dns_enable, dns_name, dns_value, srv_service, srv_protocol, srv_domain, srv_target, srv_port, srv_priority, srv_weight, dns_host_xml, ipv4_range_start, ipv4_range_end, ipv4_host_mac, ipv4_host_ip, ipv4_host_name, ipv6_range_start, ipv6_range_end, ipv6_host_id, ipv6_host_name, ipv6_host_ip) port_group = """ <portgroup name='engineering' default='no'> <virtualport type='802.1Qbh'> <parameters profileid='test'/> </virtualport> <bandwidth> <inbound average='1000' peak='5000' burst='5120'/> <outbound average='1000' peak='5000' burst='5120'/> </bandwidth> </portgroup> """ if use_in_guest == "yes": vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) vmxml_backup = vmxml.copy() backup_files = [] try: for loop in range(loop_time): if loop_time > 1: logging.info("Round %s:", loop+1) update_command = params.get("update_command").split(",")[loop] if net_section == "ip-dhcp-host": new_dhcp_host_ip = params.get("new_dhcp_host_ip").split(",")[loop] new_dhcp_host_name = params.get("new_dhcp_host_name").split(",")[loop] new_dhcp_host_mac = params.get("new_dhcp_host_mac").split(",")[loop] status_error = params.get("status_error").split(",")[loop] elif net_section == "dns-txt": net_state = params.get("net_state").split(",")[loop] # Get a tmp_dir. tmp_dir = data_dir.get_tmp_dir() # Write new xml into a tempfile tmp_file = tempfile.NamedTemporaryFile(prefix=("new_xml_"), dir=tmp_dir) xmlfile = tmp_file.name tmp_file.close() # Generate testxml test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net names = locals() if net_section == "portgroup": portgroup_xml = network_xml.PortgroupXML() portgroup_xml.xml = port_group test_xml.portgroup = portgroup_xml elif net_section == "forward-interface": if forward_mode == "bridge": forward_iface = utils_net.get_net_if(state="UP")[0] test_xml.forward = {'mode': forward_mode} test_xml.forward_interface = [{'dev': forward_iface}] del test_xml.bridge del test_xml.mac for ip_num in range(4): del test_xml.ip del test_xml.routes del test_xml.dns section_index = 0 if ip_version == "ipv6": section_index = 1 element = "/%s" % net_section.replace('-', '/') try: section_xml = test_xml.get_section_string(xpath=element, index=section_index) except xcepts.LibvirtXMLNotFoundError: newxml = section_xml = test_xml.get_section_string(xpath="/ip/dhcp/range") newxml = section_xml logging.debug("section xml is %s", newxml) flag_list = [] flag_list_abs = [] if (update_command == "delete" and error_type not in ["host-mismatch", "range-mismatch"] and not without_sec and not update_sec): logging.info("The delete xml is %s", newxml) else: if net_section == "bridge": new_bridge_name = net_name + "_new" flag_list.append(new_bridge_name) newxml = section_xml.replace(net_name, new_bridge_name) logging.info("The new bridge xml is %s", newxml) elif net_section == "forward": new_mode = "route" flag_list.append(new_mode) newxml = section_xml.replace("nat", new_mode) logging.info("The new forward xml is %s", newxml) elif net_section == "ip": new_netmask = "255.255.0.0" flag_list.append(new_netmask) newxml = section_xml.replace("255.255.255.0", new_netmask) elif net_section == "ip-dhcp-range": newxml = section_xml.replace(names[ip_version+"_range_start"], new_start_ip) newxml = newxml.replace(names[ip_version+"_range_end"], new_end_ip) for location in ["end", "start"]: if names["new_"+location+"_ip"] == "": newxml = newxml.replace(location+"=\"\"", "") else: flag_list.append(names["new_"+location+"_ip"]) elif net_section == "portgroup": new_inbound_average = "2000" flag_list.append(new_inbound_average) newxml = section_xml.replace("1000", new_inbound_average) newxml = newxml.replace("default=\"no\"", "default=\"yes\"") flag_list.append("default=('|\")yes") if update_command in ['add-first', 'add-last', 'add']: newxml = newxml.replace("engineering", "sales") flag_list.append("sales") elif net_section == "forward-interface": new_forward_iface = params.get("new_forward_iface") if error_type != "interface-duplicate": find_iface = 0 if not new_forward_iface and forward_mode == "bridge": new_iface_list = utils_net.get_net_if(qdisc="(mq|pfifo_fast)", state="(UP|DOWN)", optional="MULTICAST,UP") logging.info("new_iface_list is %s", new_iface_list) for iface in new_iface_list: if iface[0] != forward_iface: new_forward_iface = iface[0] find_iface = 1 break if not find_iface: test.cancel("Can not find another physical interface to attach") else: new_forward_iface = forward_iface flag_list.append(new_forward_iface) newxml = section_xml.replace(forward_iface, new_forward_iface) elif net_section == "ip-dhcp-host": if (update_sec is None and update_command not in ['modify', 'delete']): if ip_version == "ipv4": update_sec = "ip,mac,name" elif ip_version == "ipv6": update_sec = "ip,id,name" section_update(ip_version+"_host_", "new_dhcp_host_") elif net_section == "dns-txt": section_update("dns_", "new_dns_") elif net_section == "dns-srv": section_update("srv_", "new_srv_") elif net_section == "dns-host": if without_sec == "hostname": newxml = re.sub("<hostname>.*</hostname>\n", "", newxml) flag_list.append("ip=.*?"+dns_hostip) flag_list.append(dns_hostname) flag_list.append(dns_hostname2) # for negative test may have net_section do not match issues elif status_error == "no": test.fail("Unknown network section") logging.info("The new xml of %s is %s", net_section, newxml) with open(xmlfile, 'w') as xmlfile_d: xmlfile_d.write(newxml) if without_ip_dhcp == "yes": test_xml.del_element(element="/ip/dhcp") test_xml.del_element(element="/ip/dhcp") if without_dns == "yes": test_xml.del_element(element='/dns') if without_dns_host == "yes": test_xml.del_element(element='/dns/host') if without_dns_txt == "yes": test_xml.del_element(element='/dns/txt') if without_dns_srv == "yes": test_xml.del_element(element='/dns/srv') # Only do net define/start in first loop if (net_section == "ip-dhcp-range" and use_in_guest == "yes" and without_ip_dhcp == "no"): test_xml.del_element(element="/ip/dhcp", index=section_index) if loop == 0: try: # Define and start network test_xml.debug_xml() test_xml.define() ori_net_xml = virsh.net_dumpxml(net_name).stdout.strip() if "ipv6" in ori_net_xml: host_ifaces = utils_net.get_net_if(state="UP") backup_files.append( remote.RemoteFile(address='127.0.0.1', client='scp', username=params.get('username'), password=params.get('password'), port='22', remote_path='/proc/sys/net/ipv6/' 'conf/all/accept_ra')) process.run("echo 2 > /proc/sys/net/ipv6/conf/all/accept_ra", shell=True) for host_iface in host_ifaces: backup_files.append( remote.RemoteFile(address='127.0.0.1', client='scp', username=params.get('username'), password=params.get('password'), port='22', remote_path='/proc/sys/net/ipv6/' 'conf/%s/accept_ra' % host_iface)) process.run("echo 2 > /proc/sys/net/ipv6/conf/%s/accept_ra" % host_iface, shell=True) process.run("cat /proc/sys/net/ipv6/conf/%s/accept_ra" % host_iface) if net_state == "active" or net_state == "transient": test_xml.start() if net_state == "transient": test_xml.del_defined() list_result = virsh.net_list("--all --name").stdout.strip() if net_name not in list_result: test.fail("Can not find %s in net-list" % net_name) except xcepts.LibvirtXMLError as detail: test.error("Failed to define a test network.\n" "Detail: %s." % detail) else: # setting net status for following loops if net_state == "active": test_xml.set_active(True) elif net_state == "inactive": test_xml.set_active(False) # get hostfile before update if without_ip_dhcp == "yes" and net_state == "active": hostfile_before = get_hostfile() if hostfile_before != []: test.fail("hostfile is not empty before update: %s" % hostfile_before) logging.info("hostfile is empty before update") # Get dnsmasq pid before update check_dnsmasq = ((update_command == "add" or update_command == "delete") and net_section == "ip-dhcp-range" and status_error == "no" and net_state == "active" and options != "--config") if check_dnsmasq: cmd = "ps aux|grep dnsmasq|grep -v grep|grep %s|awk '{print $2}'" % net_name pid_list_bef = results_stdout_52lts(process.run(cmd, shell=True)).strip().split('\n') if parent_index: options += " --parent-index %s" % parent_index # Check config before update if net_state == "active": dns_txt = dns_srv = dns_host_str = None try: dns_txt = test_xml.get_section_string(xpath="/dns/txt") dns_srv = test_xml.get_section_string(xpath="/dns/srv") dns_host_str = test_xml.get_section_string(xpath="/dns/host") except xcepts.LibvirtXMLNotFoundError: pass txt_record = "txt-record=%s,%s" % (dns_name, dns_value) srv_host = "srv-host=_%s._%s.%s,%s,%s,%s,%s" % (srv_service, srv_protocol, srv_domain, srv_target, srv_port, srv_priority, srv_weight) hostline = "%s.*%s.*%s" % (dns_hostip, dns_hostname, dns_hostname2) if dns_txt: check_item(txt_record) if dns_srv: check_item(srv_host) if dns_host_str: check_host(hostline) # Do net-update operation cmd_result = virsh.net_update(net_name, update_command, net_section, xmlfile, options, debug=True) if cmd_result.exit_status: err = cmd_result.stderr.strip() if re.search("not supported", err): test.cancel("Skip the test: %s" % err) elif status_error == "yes": # index-mismatch error info and judgement index_err1 = "the address family of a host entry IP must match the" + \ " address family of the dhcp element's parent" index_err2 = "XML error: Invalid to specify MAC address.* in network" + \ ".* IPv6 static host definition" index_err3 = "mismatch of address family in range.* for network" mismatch_expect = (error_type == "index-mismatch" and (re.search(index_err1, err) or re.search(index_err2, err) or re.search(index_err3, err))) err_dic = {} # multi-host error info err_dic["multi-hosts"] = "dhcp is supported only for a single.*" + \ " address on each network" # range-mismatch error info err_dic["range-mismatch"] = "couldn't locate a matching dhcp " + \ "range entry in network " # host-mismatch error info err_dic["host-mismatch"] = "couldn't locate a matching dhcp " + \ "host entry in network " # dns-mismatch error info err_dic["dns-mismatch"] = "couldn't locate a matching DNS TXT " + \ "record in network " # range-duplicate error info err_dic["range-duplicate"] = "there is an existing dhcp range" + \ " entry in network.* that matches" # host-duplicate error info err_dic["host-duplicate"] = "there is an existing dhcp host" + \ " entry in network.* that matches" # out_of_range error info err_dic["out-of-range"] = "range.* is not entirely within network" # no end for range error err_dic["range-no-end"] = "Missing 'end' attribute in dhcp " + \ "range for network" # no match item for host modify err err_dic["no-match-item"] = "couldn't locate an existing dhcp" + \ " host entry with.* in network" # no host name and mac for modify err err_dic["host-no-name-mac"] = "Static host definition in IPv4 network" + \ ".* must have mac or name attribute" # no host ip for modify err err_dic["host-no-ip"] = "Missing IP address in static host " + \ "definition for network" # wrong command name err_dic["wrong-command-name"] = "unrecognized command name" # wrong section name err_dic["wrong-section-name"] = "unrecognized section name" # delete with only id err_dic["only-id"] = "At least one of name, mac, or ip attribute must be" + \ " specified for static host definition in network" # options exclusive err_dic["opt-exclusive"] = "Options --current and.* are mutually exclusive" # range_reverse error info if ip_version == "ipv4": err_dic["range-reverse"] = "range.* is reversed" elif ip_version == "ipv6": err_dic["range-reverse"] = "range.*start larger than end" # --live with inactive net err_dic["invalid-state"] = "network is not running" err_dic["transient"] = "cannot change persistent config of a transient network" err_dic["dns-disable"] = "Extra data in disabled network" err_dic["interface-duplicate"] = "there is an existing interface entry " + \ "in network.* that matches" if (error_type in list(err_dic.keys()) and re.search(err_dic[error_type], err) or mismatch_expect): logging.info("Get expect error: %s", err) else: test.fail("Do not get expect err msg: %s, %s" % (error_type, err_dic)) else: test.fail("Failed to execute net-update command") elif status_error == "yes": test.fail("Expect fail, but succeed") # Get dnsmasq pid after update if check_dnsmasq: pid_list_aft = results_stdout_52lts(process.run(cmd, shell=True)).strip().split('\n') for pid in pid_list_aft: if pid in pid_list_bef: test.fail("dnsmasq do not updated") # Check the actual xml cmd_result = virsh.net_dumpxml(net_name) actual_net_xml = cmd_result.stdout.strip() new_xml_obj = network_xml.NetworkXML.new_from_net_dumpxml(net_name) logging.info("After net-update, the actual net xml is %s", actual_net_xml) if "ip-dhcp" in net_section: if ip_version == "ipv6": new_xml_obj.del_element(element="/ip", index=0) if ip_version == "ipv4": new_xml_obj.del_element(element="/ip", index=1) config_not_work = ("--config" in options and net_state == "active" and "--live" not in options) if config_not_work: if update_command != "delete": flag_list_abs = flag_list flag_list = [] else: flag_list = flag_list_abs flag_list_abs = [] logging.info("The check list is %s, absent list is %s", flag_list, flag_list_abs) if (update_command == "delete" and status_error == "no" and not config_not_work and loop_time == 1): try: section_str = new_xml_obj.get_section_string(xpath=element) except xcepts.LibvirtXMLNotFoundError: section_str = None logging.info("Can not find section %s in xml after delete", element) if section_str is not None: test.fail("The actual net xml is not expected," "element still exists") elif ("duplicate" not in error_type and error_type != "range-mismatch" and error_type != "host-mismatch"): # check xml should exists for flag_string in flag_list: logging.info("checking %s should in xml in positive test," "and absent in negative test", flag_string) if not re.search(flag_string, actual_net_xml): if ((status_error == "no" and update_command != "delete") or (update_command == "delete" and status_error == "yes")): test.fail("The actual net xml failed to update," "or expect delete fail but xml missing" ":%s" % flag_string) else: if ((status_error == "yes" and update_command != "delete") or (status_error == "no" and update_command == "delete" and not config_not_work)): test.fail("Expect test fail, but find xml %s" " actual, or expect delete succeed," "but fail in fact" % flag_string) # check xml should not exists for flag_string_abs in flag_list_abs: logging.info("checking %s should NOT in xml in positive test," "and exist in negative test", flag_string_abs) if re.search(flag_string_abs, actual_net_xml): if status_error == "no": test.fail("Expect absent in net xml, but exists" "in fact: %s" % flag_string_abs) else: if status_error == "yes": test.fail("Should exists in net xml, but it " "disappeared: %s" % flag_string_abs) # Check if add-last, add-fist works well if (status_error == "no" and not config_not_work and update_command in ["add-last", "add", "add-first"]): if update_command == "add-first": find_index = 0 else: find_index = -1 section_str_aft = new_xml_obj.get_section_string(xpath=element, index=find_index) logging.info("xpath is %s, find_index is %s, section_str_aft is %s", element, find_index, section_str_aft) for flag_string in flag_list: logging.info("flag_string is %s", flag_string) if not re.search(flag_string, section_str_aft): test.fail("Can not find %s in %s" % (flag_string, section_str_aft)) logging.info("%s %s in right place", update_command, section_str_aft) # Check the positive test result if status_error == "no": # Check the network conf file # live update if ("--live" in options or "--config" not in options) and net_state == "active": if net_section == "ip-dhcp-range" and update_command == "add-first": ip_range = "%s,%s" % (new_start_ip, new_end_ip) if ip_version == "ipv6": ip_range = ip_range + ",64" check_item(ip_range) if "dns" in net_section: if update_command == "delete" and loop == 0: if net_section == "dns-srv": check_item_absent(srv_host) if net_section == "dns-txt": check_item_absent(txt_record) if net_section == "dns-host": check_host_absent(dns_host_str) elif "add" in update_command: if net_section == "dns-srv": for sec in update_sec.split(","): srv_host = srv_host.replace(names["srv_"+sec], names["new_srv_"+sec]) check_item(srv_host) if net_section == "dns-txt": for sec in update_sec.split(","): txt_record = txt_record.replace(names["dns_"+sec], names["new_dns_"+sec]) check_item(txt_record) if net_section == "dns-host": check_host(hostline) # Check the hostfile if (net_section == "ip-dhcp-host" and update_command != "modify" and update_command != "delete"): dic_hostfile = {} for sec in ["ip", "mac", "name", "id"]: if update_sec is not None and sec in update_sec.split(","): dic_hostfile[sec] = names["new_dhcp_host_"+sec]+"," else: dic_hostfile[sec] = names[ip_version+"_host_"+sec]+"," if sec == "ip" and ip_version == "ipv6": dic_hostfile[sec] = "[" + dic_hostfile[sec].strip(",") + "]" if without_sec is not None and sec in without_sec.split(","): dic_hostfile[sec] = "" if ip_version == "ipv4": host_info = (dic_hostfile["mac"] + dic_hostfile["ip"] + dic_hostfile["name"]) if dic_hostfile["mac"] == "": host_info = dic_hostfile["name"] + dic_hostfile["ip"] if ip_version == "ipv6": host_info = ("id:" + dic_hostfile["id"] + dic_hostfile["name"] + dic_hostfile["ip"]) hostfile = get_hostfile() host_info_patten = host_info.strip(",") + "\n" if host_info_patten in hostfile: logging.info("host info %s is in hostfile %s", host_info, hostfile) else: test.fail("Can not find %s in host file: %s" % (host_info, hostfile)) # Check the net in guest if use_in_guest == "yes" and loop == 0: # Detach all interfaces of vm first iface_index = 0 mac_list = vm_xml.VMXML.get_iface_dev(vm_name) for mac in mac_list: iface_dict = vm_xml.VMXML.get_iface_by_mac(vm_name, mac) virsh.detach_interface(vm_name, "--type %s --mac %s --config" % (iface_dict.get('type'), mac)) vm.free_mac_address(iface_index) iface_index += 1 # attach new interface to guest for j in range(guest_iface_num): if net_section == "ip-dhcp-host" and new_dhcp_host_mac: mac = new_dhcp_host_mac else: mac = utils_net.generate_mac_address_simple() ret = virsh.attach_interface(vm_name, "--type %s --source %s --mac %s --config" % (iface_type, net_name, mac)) if ret.exit_status: test.fail("Fail to attach new interface to guest: %s" % ret.stderr.strip()) # The sleep here is to make sure the update make effect time.sleep(2) # Start guest and check ip/mac/hostname... vm.start() logging.debug("vm xml is %s", vm.get_xml()) session = vm.wait_for_serial_login() if "ip-dhcp" in net_section: dhclient_cmd = "(if pgrep dhclient;" \ "then pkill dhclient; sleep 3; fi) " \ "&& dhclient -%s" % ip_version[-1] session.cmd(dhclient_cmd) iface_ip = utils_net.get_guest_ip_addr(session, mac, ip_version=ip_version, timeout=10) if net_section == "ip-dhcp-range": if new_start_ip <= iface_ip <= new_end_ip: logging.info("getting ip %s is in range [%s ~ %s]", iface_ip, new_start_ip, new_end_ip) else: test.fail("getting ip %s not in range [%s ~ %s]" % (iface_ip, new_start_ip, new_end_ip)) if net_section == "ip-dhcp-host": if iface_ip == new_dhcp_host_ip: logging.info("getting ip is same with set: %s", iface_ip) else: test.fail("getting ip %s is not same with setting %s" % (iface_ip, new_dhcp_host_ip)) hostname = session.cmd_output("hostname").strip('\n') if hostname == new_dhcp_host_name.split('.')[0]: logging.info("getting hostname same with setting: %s", hostname) else: test.fail("getting hostname %s is not same with " "setting: %s" % (hostname, new_dhcp_host_name)) session.close() # Check network connection for macvtap if (use_in_guest == "yes" and net_section == "forward-interface" and forward_mode == "bridge"): xml_obj_use = network_xml.NetworkXML.new_from_net_dumpxml(net_name) net_conn = int(xml_obj_use.connection) iface_conn = xml_obj_use.get_interface_connection() conn_count = 0 for k in iface_conn: conn_count = conn_count + int(k) logging.info("net_conn=%s, conn_count=%s, guest_iface_num=%s" % (net_conn, conn_count, guest_iface_num)) if (net_conn != conn_count or (loop == 1 and guest_iface_num != net_conn)): test.fail("Can not get expected connection num: " "net_conn = %s, iface_conn = %s" % (net_conn, conn_count)) #Check --config option after net destroyed if (int(check_config_round) == loop or (loop_time == 1 and "--current" in options and net_state == "active")): test_xml.set_active(False) logging.info("Checking xml after net destroyed") cmd_result = virsh.net_dumpxml(net_name) inactive_xml = cmd_result.stdout.strip() logging.info("inactive_xml is %s", inactive_xml) #Check the inactive xml for check_str in flag_list: if update_command != "delete": if "--config" in options: if not re.search(check_str, inactive_xml): test.fail("Can not find xml after net destroyed") if "--current" in options: if re.search(check_str, inactive_xml): test.fail("XML still exists after net destroyed") else: if "--config" in options: if re.search(check_str, inactive_xml): test.fail("XML still exists after net destroyed") if "--current" in options: if not re.search(check_str, inactive_xml): test.fail("Can not find xml after net destroyed") logging.info("Check for net inactive PASS") finally: if test_xml.get_active(): test_xml.del_active() if test_xml.get_defined(): test_xml.del_defined() if os.path.exists(xmlfile): os.remove(xmlfile) if use_in_guest == "yes": vm = env.get_vm(vm_name) if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync() for config_file in backup_files: config_file._reset_file()
def run(test, params, env): """ Test interface xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm.is_alive(): vm.wait_for_login() def create_iface_xml(mac=None): """ Create interface xml file """ iface = Interface(type_name=iface_type) iface.source = iface_source iface.model = iface_model if iface_model else "virtio" if iface_target: iface.target = {'dev': iface_target} if mac: iface.mac_address = mac if iface_rom: iface.rom = eval(iface_rom) logging.debug("Create new interface xml: %s", iface) return iface def get_all_mac_in_vm(): """ get the mac address list of all the interfaces from a running vm os return: a list of the mac addresses """ mac_list = [] interface_list = vm.get_interfaces() for iface_ in interface_list: mac_ = vm.get_interface_mac(iface_) mac_list.append(mac_) return mac_list # Interface specific attributes. iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_source = eval(params.get("iface_source", "{'network':'default'}")) iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_mac = params.get("iface_mac") iface_rom = params.get("iface_rom") attach_device = "yes" == params.get("attach_device", "no") attach_iface = "yes" == params.get("attach_iface", "no") attach_option = params.get("attach_option", "") detach_device = "yes" == params.get("detach_device") stress_test = "yes" == params.get("stress_test") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") start_vm = "yes" == params.get("start_vm", "yes") options_test = "yes" == params.get("options_test", "no") username = params.get("username") password = params.get("password") poll_timeout = int(params.get("poll_timeout", 10)) err_msgs1 = params.get("err_msgs1") err_msgs2 = params.get("err_msgs2") err_msg_rom = params.get("err_msg_rom") del_pci = "yes" == params.get("del_pci", "no") del_mac = "yes" == params.get("del_mac", "no") del_alias = "yes" == params.get("del_alias", "no") set_pci = "yes" == params.get("set_pci", "no") set_mac = "yes" == params.get("set_mac", "no") set_alias = "yes" == params.get("set_alias", "no") status_error = "yes" == params.get("status_error", "no") pci_addr = params.get("pci") check_mac = "yes" == params.get("check_mac", "no") vnet_mac = params.get("vnet_mac", None) customer_alias = "yes" == params.get("customer_alias", "no") detach_error = params.get("detach_error", None) libvirt_version.is_libvirt_feature_supported(params) # stree_test require detach operation stress_test_detach_device = False stress_test_detach_interface = False if stress_test: if attach_device: stress_test_detach_device = True if attach_iface: stress_test_detach_interface = True # The following detach-device step also using attach option detach_option = attach_option # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) #iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) libvirtd = utils_libvirtd.Libvirtd() # Check virsh command option check_cmds = [] sep_options = attach_option.split() logging.debug("sep_options: %s" % sep_options) for sep_option in sep_options: if attach_device and sep_option: check_cmds.append(('attach-device', sep_option)) if attach_iface and sep_option: check_cmds.append(('attach-interface', sep_option)) if (detach_device or stress_test_detach_device) and sep_option: check_cmds.append(('detach-device', sep_option)) if stress_test_detach_interface and sep_option: check_cmds.append(('detach-device', sep_option)) for cmd, option in check_cmds: libvirt.virsh_cmd_has_option(cmd, option) try: try: # Attach an interface when vm is running iface_list = [] err_msgs = ("No more available PCI slots", "No more available PCI addresses") if not start_vm: virsh.destroy(vm_name) for i in range(int(iface_num)): if attach_device: logging.info("Try to attach device loop %s" % i) if iface_mac: mac = iface_mac iface_xml_obj = create_iface_xml(mac) elif check_mac: iface_xml_obj = create_iface_xml() else: mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(mac) if customer_alias: random_id = process.run( "uuidgen", ignore_status=True, shell=True).stdout_text.strip() alias_str = "ua-" + random_id iface_xml_obj.alias = {"name": alias_str} logging.debug("Update number %s interface xml: %s", i, iface_xml_obj) iface_xml_obj.xmltreefile.write() if check_mac: mac_bef = get_all_mac_in_vm() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True, debug=True) elif attach_iface: logging.info("Try to attach interface loop %s" % i) if iface_mac: mac = iface_mac else: mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug( "No more pci slots, can't attach more devices") break elif ret.stderr.count("doesn't support option %s" % attach_option): test.cancel(ret.stderr) elif err_msgs1 in ret.stderr: logging.debug( "option %s is not supported when domain running is %s" % (attach_option, vm.is_alive())) if start_vm or ("--live" not in sep_options and attach_option): test.fail( "return not supported, but it is unexpected") elif err_msgs2 in ret.stderr: logging.debug("options %s are mutually exclusive" % attach_option) if not ("--current" in sep_options and len(sep_options) > 1): test.fail( "return mutualy exclusive, but it is unexpected" ) elif err_msg_rom and err_msg_rom in ret.stderr: logging.debug("Attach failed with expect err msg: %s" % err_msg_rom) else: test.fail("Failed to attach-interface: %s" % ret.stderr.strip()) elif stress_test: if attach_device: # Detach the device immediately for stress test ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr=detach_option, ignore_status=True) elif attach_iface: # Detach the device immediately for stress test options = ("--type %s --mac %s %s" % (iface_type, mac, detach_option)) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) else: if attach_device: if check_mac: mac_aft = get_all_mac_in_vm() add_mac = list( set(mac_aft).difference(set(mac_bef))) try: mac = add_mac[0] logging.debug( "The mac address of the attached interface is %s" % mac) except IndexError: test.fail( "Can not find the new added interface in the guest os!" ) iface_list.append({ 'mac': mac, 'iface_xml': iface_xml_obj }) elif attach_iface: iface_list.append({'mac': mac}) # Restart libvirtd service if restart_libvirtd: libvirtd.restart() # After restart libvirtd, the old console was invalidated, # so we need create a new serial console vm.cleanup_serial_console() vm.create_serial_console() # in options test, check if the interface is attached # in current state when attach return true def check_iface_exist(): try: session = vm.wait_for_serial_login(username=username, password=password) if utils_net.get_linux_ifname(session, iface['mac']): return True else: logging.debug("can not find interface in vm") except Exception: return False if options_test: for iface in iface_list: if 'mac' in iface: # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']) if vm.is_alive() and attach_option == "--config": if if_attr: test.fail("interface should not exists " "in current live vm while " "attached by --config") else: if if_attr: logging.debug("interface %s found current " "state in xml" % if_attr['mac']) else: test.fail("no interface found in " "current state in xml") if if_attr: if if_attr['type'] != iface_type or \ if_attr['source'] != \ iface_source['network']: test.fail("Interface attribute doesn't " "match attachment options") # check interface in vm only when vm is active if vm.is_alive(): logging.debug("check interface in current state " "in vm") if not utils_misc.wait_for(check_iface_exist, timeout=20): if not attach_option == "--config": test.fail("Can't see interface " "in current state in vm") else: logging.debug("find interface in " "current state in vm") else: logging.debug("find interface in " "current state in vm") # in options test, if the attach is performed # when the vm is running # need to destroy and start to check again vm.destroy() # Start the domain if needed if vm.is_dead(): vm.start() session = vm.wait_for_serial_login(username=username, password=password) # check if interface is attached for iface in iface_list: if 'mac' in iface: logging.debug("check interface in xml") # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']) logging.debug(if_attr) if if_attr: logging.debug("interface {} is found in xml".format( if_attr['mac'])) if (if_attr['type'] != iface_type or if_attr['source'] != iface_source['network']): test.fail("Interface attribute doesn't " "match attachment options") if options_test and start_vm and attach_option \ in ("--current", "--live", ""): test.fail("interface should not exists when " "restart vm in options_test") else: logging.debug("no interface found in xml") if options_test and start_vm and attach_option in \ ("--current", "--live", ""): logging.debug("interface not exists next state " "in xml with %s" % attach_option) else: test.fail("Can't see interface in dumpxml") # Check interface on guest if not utils_misc.wait_for(check_iface_exist, timeout=20): logging.debug("can't see interface next state in vm") if start_vm and attach_option in \ ("--current", "--live", ""): logging.debug("it is expected") else: test.fail("should find interface " "but no seen in next state in vm") if vnet_mac: # get the name of the backend tap device iface_params = vm_xml.VMXML.get_iface_by_mac( vm_name, mac) target_name = iface_params['target']['dev'] # check the tap device mac on host tap_info = process.run("ip l show %s" % target_name, shell=True, ignore_status=True).stdout_text logging.debug("vnet_mac should be %s" % vnet_mac) logging.debug( "check on host for the details of tap device %s: %s" % (target_name, tap_info)) if vnet_mac not in tap_info: test.fail( "The mac address of the tap device do not match!" ) # Detach hot/cold-plugged interface at last if detach_device: logging.debug("detach interface here:") if attach_device: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_xml_ls = vmxml.get_devices("interface") iface_xml_ls_det = iface_xml_ls[1:] for iface_xml_det in iface_xml_ls_det: if del_mac: iface_xml_det.del_mac_address() if del_pci: iface_xml_det.del_address() if del_alias: iface_xml_det.del_alias() if set_mac: mac = utils_net.generate_mac_address_simple() iface_xml_det.set_mac_address(mac) if set_pci: pci_dict = ast.literal_eval(pci_addr) addr = iface_xml_det.new_iface_address( **{"attrs": pci_dict}) iface_xml_det.set_address(addr) if set_alias: random_id = process.run( "uuidgen", ignore_status=True, shell=True).stdout_text.strip() alias_str = "ua-" + random_id iface_xml_det.set_alias({"name": alias_str}) ori_pid_libvirtd = process.getoutput("pidof libvirtd") logging.debug( "The xml of the interface to detach is %s", iface_xml_det) ret = virsh.detach_device(vm_name, iface_xml_det.xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret, status_error) if detach_device and status_error and detach_error: if not ret.stderr.count(detach_error): test.error( "Detach fail as expected, but the error msg %s can not match!" % ret.stderr) aft_pid_libvirtd = process.getoutput("pidof libvirtd") if not utils_libvirtd.Libvirtd.is_running or ori_pid_libvirtd != aft_pid_libvirtd: test.fail( "Libvirtd crash after detach non-exists interface" ) else: for iface in iface_list: options = ("%s --mac %s" % (iface_type, iface['mac'])) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) # Check if interface was detached if not status_error: for iface in iface_list: if 'mac' in iface: polltime = time.time() + poll_timeout while True: # Check interface in dumpxml output if not vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']): break else: time.sleep(2) if time.time() > polltime: test.fail("Interface still " "exists after detachment") session.close() except virt_vm.VMStartError as e: logging.info(str(e)) test.fail('VM failed to start:\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): """ convert specific kvm guest to rhev """ for v in list(params.values()): if "V2V_EXAMPLE" in v: test.cancel("Please set real value for %s" % v) if utils_v2v.V2V_EXEC is None: raise ValueError('Missing command: virt-v2v') enable_legacy_policy = params_get(params, "enable_legacy_policy") == 'yes' hypervisor = params.get("hypervisor") vm_name = params.get('main_vm', 'EXAMPLE') target = params.get('target') remote_host = params.get('remote_host', 'EXAMPLE') input_mode = params.get("input_mode") output_mode = params.get('output_mode') output_format = params.get('output_format') source_user = params.get("username", "root") os_pool = storage = params.get('output_storage') bridge = params.get('bridge') network = params.get('network') ntp_server = params.get('ntp_server') vpx_dc = params.get("vpx_dc") esx_ip = params.get("esx_hostname") address_cache = env.get('address_cache') pool_name = params.get('pool_name', 'v2v_test') pool_type = params.get('pool_type', 'dir') pool_target = params.get('pool_target_path', 'v2v_pool') pvt = utlv.PoolVolumeTest(test, params) v2v_opts = '-v -x' if params.get('v2v_debug', 'on') in ['on', 'force_on' ] else '' if params.get("v2v_opts"): # Add a blank by force v2v_opts += ' ' + params.get("v2v_opts") v2v_timeout = int(params.get('v2v_timeout', 3600)) skip_vm_check = params.get('skip_vm_check', 'no') status_error = 'yes' == params.get('status_error', 'no') checkpoint = params.get('checkpoint', '') debug_kernel = 'debug_kernel' == checkpoint backup_list = [ 'floppy', 'floppy_devmap', 'fstab_cdrom', 'sata_disk', 'network_rtl8139', 'network_e1000', 'spice', 'spice_encrypt', 'spice_qxl', 'spice_cirrus', 'vnc_qxl', 'vnc_cirrus', 'blank_2nd_disk', 'listen_none', 'listen_socket', 'only_net', 'only_br' ] error_list = [] # For construct rhv-upload option in v2v cmd output_method = params.get("output_method") rhv_upload_opts = params.get("rhv_upload_opts") storage_name = params.get('storage_name') # for get ca.crt file from ovirt engine rhv_passwd = params.get("rhv_upload_passwd") rhv_passwd_file = params.get("rhv_upload_passwd_file") ovirt_engine_passwd = params.get("ovirt_engine_password") ovirt_hostname = params.get("ovirt_engine_url").split( '/')[2] if params.get("ovirt_engine_url") else None ovirt_ca_file_path = params.get("ovirt_ca_file_path") local_ca_file_path = params.get("local_ca_file_path") # For VDDK input_transport = params.get("input_transport") vddk_libdir = params.get('vddk_libdir') # nfs mount source vddk_libdir_src = params.get('vddk_libdir_src') vddk_thumbprint = params.get('vddk_thumbprint') # Prepare step for different hypervisor if enable_legacy_policy: update_crypto_policy("LEGACY") if hypervisor == "esx": source_ip = params.get("vpx_hostname") source_pwd = params.get("vpx_password") vpx_passwd_file = params.get("vpx_passwd_file") # Create password file to access ESX hypervisor with open(vpx_passwd_file, 'w') as f: f.write(source_pwd) elif hypervisor == "xen": source_ip = params.get("xen_hostname") source_pwd = params.get("xen_host_passwd") # Set up ssh access using ssh-agent and authorized_keys xen_pubkey, xen_session = utils_v2v.v2v_setup_ssh_key(source_ip, source_user, source_pwd, auto_close=False) try: utils_misc.add_identities_into_ssh_agent() except Exception as e: process.run("ssh-agent -k") test.error("Fail to setup ssh-agent \n %s" % str(e)) elif hypervisor == "kvm": source_ip = None source_pwd = None else: test.cancel("Unsupported hypervisor: %s" % hypervisor) # Create libvirt URI v2v_uri = utils_v2v.Uri(hypervisor) remote_uri = v2v_uri.get_uri(source_ip, vpx_dc, esx_ip) LOG.debug("libvirt URI for converting: %s", remote_uri) # Make sure the VM exist before convert v2v_virsh = None close_virsh = False if hypervisor == 'kvm': v2v_virsh = virsh else: virsh_dargs = { 'uri': remote_uri, 'remote_ip': source_ip, 'remote_user': source_user, 'remote_pwd': source_pwd, 'auto_close': True, 'debug': True } v2v_virsh = virsh.VirshPersistent(**virsh_dargs) LOG.debug('a new virsh session %s was created', v2v_virsh) close_virsh = True if not v2v_virsh.domain_exists(vm_name): test.error("VM '%s' not exist" % vm_name) def log_fail(msg): """ Log error and update error list """ LOG.error(msg) error_list.append(msg) def vm_shell(func): """ Decorator of shell session to vm """ def wrapper(*args, **kwargs): vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_dead(): LOG.info('VM is down. Starting it now.') vm.start() session = vm.wait_for_login() kwargs['session'] = session kwargs['vm'] = vm func(*args, **kwargs) if session: session.close() vm.shutdown() return wrapper def check_disks(vmcheck): """ Check disk counts inside the VM """ # Initialize windows boot up os_type = params.get("os_type", "linux") expected_disks = int(params.get("ori_disks", "1")) LOG.debug("Expect %s disks im VM after convert", expected_disks) # Get disk counts if os_type == "linux": cmd = "lsblk |grep disk |wc -l" disks = int(vmcheck.session.cmd(cmd).strip()) else: cmd = r"echo list disk > C:\list_disk.txt" vmcheck.session.cmd(cmd) cmd = r"diskpart /s C:\list_disk.txt" output = vmcheck.session.cmd(cmd).strip() LOG.debug("Disks in VM: %s", output) disks = len(re.findall(r'Disk\s\d', output)) LOG.debug("Find %s disks in VM after convert", disks) if disks == expected_disks: LOG.info("Disk counts is expected") else: log_fail("Disk counts is wrong") def check_vmlinuz_initramfs(v2v_output): """ Check if vmlinuz matches initramfs on multi-kernel case """ LOG.debug('Checking if vmlinuz matches initramfs') kernel_strs = re.findall(r'(\* kernel.*?\/boot\/config){1,}', v2v_output, re.DOTALL) if len(kernel_strs) == 0: test.error("Not find kernel information") # Remove duplicate items by set LOG.debug('Boots and kernel info: %s' % set(kernel_strs)) for str_i in set(kernel_strs): # Fine all versions kernel_vers = re.findall(r'((?:\d+\.){1,}\d+-(?:\d+\.){1,}\w+)', str_i) LOG.debug('kernel related versions: %s' % kernel_vers) # kernel_vers = [kernel, vmlinuz, initramfs] and they should be # same if len(kernel_vers) < 3 or len(set(kernel_vers)) != 1: log_fail("kernel versions does not match: %s" % kernel_vers) def check_boot_kernel(vmcheck): """ Check if converted vm use the latest kernel """ _, current_kernel = vmcheck.run_cmd('uname -r') if 'debug' in current_kernel: log_fail('Current kernel is a debug kernel: %s' % current_kernel) # 'sort -V' can satisfy our testing, even though it's not strictly perfect. # The last one is always the latest kernel version kernel_normal_list = vmcheck.run_cmd( 'rpm -q kernel | sort -V')[1].strip().splitlines() status, kernel_debug = vmcheck.run_cmd('rpm -q kernel-debug') if status != 0: test.error('Not found kernel-debug package') all_kernel_list = kernel_normal_list + kernel_debug.strip().splitlines( ) LOG.debug('All kernels: %s' % all_kernel_list) if len(all_kernel_list) < 3: test.error( 'Needs at least 2 normal kernels and 1 debug kernel in VM') # The latest non-debug kernel must be kernel_normal_list[-1] if current_kernel.strip() != kernel_normal_list[-1].lstrip('kernel-'): log_fail('Check boot kernel failed') def check_floppy_exist(vmcheck): """ Check if floppy exists after conversion """ blk = vmcheck.session.cmd('lsblk') LOG.info(blk) if not re.search('fd0', blk): log_fail('Floppy not found') def attach_removable_media(type, source, dev): bus = {'cdrom': 'ide', 'floppy': 'fdc', 'disk': 'virtio'} args = { 'driver': 'qemu', 'subdriver': 'raw', 'sourcetype': 'file', 'type': type, 'targetbus': bus[type] } if type == 'cdrom': args.update({'mode': 'readonly'}) config = '' # Join all options together to get command line for key in list(args.keys()): config += ' --%s %s' % (key, args[key]) config += ' --current' virsh.attach_disk(vm_name, source, dev, extra=config) def change_disk_bus(dest): """ Change all disks' bus type to $dest """ bus_list = ['ide', 'sata', 'virtio'] if dest not in bus_list: test.error('Bus type not support') dev_prefix = ['h', 's', 'v'] dev_table = dict(list(zip(bus_list, dev_prefix))) LOG.info('Change disk bus to %s' % dest) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) disks = vmxml.get_disk_all_by_expr('device==disk') index = 0 for disk in list(disks.values()): if disk.get('device') != 'disk': continue target = disk.find('target') target.set('bus', dest) target.set('dev', dev_table[dest] + 'd' + string.ascii_lowercase[index]) disk.remove(disk.find('address')) index += 1 vmxml.sync() def change_network_model(model): """ Change network model to $model """ vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) network_list = vmxml.get_iface_all() for node in list(network_list.values()): if node.get('type') == 'network': node.find('model').set('type', model) vmxml.sync() def attach_network_card(model): """ Attach network card based on model """ if model not in ('e1000', 'virtio', 'rtl8139'): test.error('Network model not support') options = {'type': 'network', 'source': 'default', 'model': model} line = '' for key in options: line += ' --' + key + ' ' + options[key] line += ' --current' LOG.debug(virsh.attach_interface(vm_name, option=line)) def check_multi_netcards(mac_list, vmxml): """ Check if number and type of network cards meet expectation """ xmltree = xml_utils.XMLTreeFile(vmxml) iface_nodes = xmltree.find('devices').findall('interface') iflist = {} for node in iface_nodes: mac_addr = node.find('mac').get('address') iflist[mac_addr] = node LOG.debug('MAC list before v2v: %s' % mac_list) LOG.debug('MAC list after v2v: %s' % list(iflist.keys())) if set(mac_list).difference(list(iflist.keys())): log_fail('Missing network interface') for mac in iflist: if iflist[mac].find('model').get('type') != 'virtio': log_fail('Network not convert to virtio') @vm_shell def insert_floppy_devicemap(**kwargs): """ Add an entry of floppy to device.map """ session = kwargs['session'] line = '(fd0) /dev/fd0' devmap = '/boot/grub/device.map' if session.cmd_status('ls %s' % devmap): devmap = '/boot/grub2/device.map' cmd_exist = 'grep \'(fd0)\' %s' % devmap cmd_set = 'sed -i \'2i%s\' %s' % (line, devmap) if session.cmd_status(cmd_exist): session.cmd(cmd_set) def make_label(session): """ Label a volume, swap or root volume """ # swaplabel for rhel7 with xfs, e2label for rhel6 or ext* cmd_map = { 'root': 'e2label %s ROOT', 'swap': 'swaplabel -L SWAPPER %s' } if not session.cmd_status('swaplabel --help'): blk = 'swap' elif not session.cmd_status('which e2label'): blk = 'root' else: test.error('No tool to make label') entry = session.cmd('blkid|grep %s' % blk).strip() path = entry.split()[0].strip(':') cmd_label = cmd_map[blk] % path if 'LABEL' not in entry: session.cmd(cmd_label) return blk @vm_shell def specify_fstab_entry(type, **kwargs): """ Specify entry in fstab file """ type_list = ['cdrom', 'uuid', 'label', 'sr0', 'invalid'] if type not in type_list: test.error('Not support %s in fstab' % type) session = kwargs['session'] # Specify cdrom device if type == 'cdrom': line = '/dev/cdrom /media/CDROM auto exec' if 'grub2' in utils_misc.get_bootloader_cfg(session): line += ',nofail' line += ' 0 0' LOG.debug('fstab entry is "%s"', line) cmd = [ 'mkdir -p /media/CDROM', 'mount /dev/cdrom /media/CDROM', 'echo "%s" >> /etc/fstab' % line ] for i in range(len(cmd)): session.cmd(cmd[i]) elif type == 'sr0': line = params.get('fstab_content') session.cmd('echo "%s" >> /etc/fstab' % line) elif type == 'invalid': line = utils_misc.generate_random_string(6) session.cmd('echo "%s" >> /etc/fstab' % line) else: map = {'uuid': 'UUID', 'label': 'LABEL'} LOG.info(type) if session.cmd_status('cat /etc/fstab|grep %s' % map[type]): # Specify device by UUID if type == 'uuid': entry = session.cmd( 'blkid -s UUID|grep swap').strip().split() # Replace path for UUID origin = entry[0].strip(':') replace = entry[1].replace('"', '') # Specify device by label elif type == 'label': blk = make_label(session) entry = session.cmd('blkid|grep %s' % blk).strip() # Remove " from LABEL="****" replace = entry.split()[1].strip().replace('"', '') # Replace the original id/path with label origin = entry.split()[0].strip(':') cmd_fstab = "sed -i 's|%s|%s|' /etc/fstab" % (origin, replace) session.cmd(cmd_fstab) fstab = session.cmd_output('cat /etc/fstab') LOG.debug('Content of /etc/fstab:\n%s', fstab) def create_large_file(session, left_space): """ Create a large file to make left space of root less than $left_space MB """ cmd_guestfish = "guestfish get-cachedir" tmp_dir = session.cmd_output(cmd_guestfish).split()[-1] LOG.debug('Command output of tmp_dir: %s', tmp_dir) cmd_df = "df -m %s --output=avail" % tmp_dir df_output = session.cmd(cmd_df).strip() LOG.debug('Command output: %s', df_output) avail = int(df_output.strip().split('\n')[-1]) LOG.info('Available space: %dM' % avail) if avail <= left_space - 1: return None if not os.path.exists(tmp_dir): os.mkdir(tmp_dir) large_file = os.path.join(tmp_dir, 'file.large') cmd_create = 'dd if=/dev/zero of=%s bs=1M count=%d' % \ (large_file, avail - left_space + 2) session.cmd(cmd_create, timeout=v2v_timeout) newAvail = int(session.cmd(cmd_df).strip().split('\n')[-1]) LOG.info('New Available space: %sM' % newAvail) return large_file @vm_shell def corrupt_rpmdb(**kwargs): """ Corrupt rpm db """ session = kwargs['session'] # If __db.* exist, remove them, then touch _db.001 to corrupt db. if not session.cmd_status('ls /var/lib/rpm/__db.001'): session.cmd('rm -f /var/lib/rpm/__db.*') session.cmd('touch /var/lib/rpm/__db.001') if not session.cmd_status('yum update'): test.error('Corrupt rpmdb failed') @vm_shell def grub_serial_terminal(**kwargs): """ Edit the serial and terminal lines of grub.conf """ session = kwargs['session'] vm = kwargs['vm'] grub_file = utils_misc.get_bootloader_cfg(session) if 'grub2' in grub_file: test.cancel('Skip this case on grub2') cmd = "sed -i '1iserial -unit=0 -speed=115200\\n" cmd += "terminal -timeout=10 serial console' %s" % grub_file session.cmd(cmd) @vm_shell def set_selinux(value, **kwargs): """ Set selinux stat of guest """ session = kwargs['session'] current_stat = session.cmd_output('getenforce').strip() LOG.debug('Current selinux status: %s', current_stat) if current_stat != value: cmd = "sed -E -i 's/(^SELINUX=).*?/\\1%s/' /etc/selinux/config" % value LOG.info('Set selinux stat with command %s', cmd) session.cmd(cmd) @vm_shell def get_firewalld_status(**kwargs): """ Return firewalld service status of vm """ session = kwargs['session'] # Example: Active: active (running) since Fri 2019-03-15 01:03:39 CST; # 3min 48s ago firewalld_status = session.cmd( 'systemctl status firewalld.service|grep Active:', ok_status=[0, 3]).strip() # Exclude the time string because time changes if vm restarts firewalld_status = re.search(r'Active:\s\w*\s\(\w*\)', firewalld_status).group() LOG.info('Status of firewalld: %s', firewalld_status) params[checkpoint] = firewalld_status def check_firewalld_status(vmcheck, expect_status): """ Check if status of firewalld meets expectation """ firewalld_status = vmcheck.session.cmd( 'systemctl status ' 'firewalld.service|grep Active:', ok_status=[0, 3]).strip() # Exclude the time string because time changes if vm restarts firewalld_status = re.search(r'Active:\s\w*\s\(\w*\)', firewalld_status).group() LOG.info('Status of firewalld after v2v: %s', firewalld_status) if firewalld_status != expect_status: log_fail('Status of firewalld changed after conversion') @vm_shell def vm_cmd(cmd_list, **kwargs): """ Execute a list of commands on guest. """ session = kwargs['session'] for cmd in cmd_list: LOG.info('Send command "%s"', cmd) # 'chronyc waitsync' needs more than 2mins to sync clock, # We set timeout to 300s will not have side-effects for other # commands. status, output = session.cmd_status_output(cmd, timeout=300) LOG.debug('Command output:\n%s', output) if status != 0: test.error('Command "%s" failed' % cmd) LOG.info('All commands executed') def check_time_keep(vmcheck): """ Check time drift after conversion. """ LOG.info('Check time drift') output = vmcheck.session.cmd('chronyc tracking') LOG.debug(output) if 'Not synchronised' in output: log_fail('Time not synchronised') lst_offset = re.search('Last offset *?: *(.*) ', output).group(1) drift = abs(float(lst_offset)) LOG.debug('Time drift is: %f', drift) if drift > 3: log_fail('Time drift exceeds 3 sec') def check_boot(): """ Check if guest can boot up after configuration """ try: vm = libvirt_vm.VM(vm_name, params, test.bindir, env.get('address_cache')) if vm.is_alive(): vm.shutdown() LOG.info('Booting up %s' % vm_name) vm.start() vm.wait_for_login() vm.shutdown() LOG.info('%s is down' % vm_name) except Exception as e: test.error('Bootup guest and login failed: %s' % str(e)) def check_result(result, status_error): """ Check virt-v2v command result """ utlv.check_exit_status(result, status_error) output = result.stdout_text + result.stderr_text if not status_error: if output_mode == 'json' and not check_json_output(params): test.fail('check json output failed') if output_mode == 'local' and not check_local_output(params): test.fail('check local output failed') if output_mode in ['null', 'json', 'local']: return vmchecker = VMChecker(test, params, env) params['vmchecker'] = vmchecker if output_mode == 'rhev': if not utils_v2v.import_vm_to_ovirt( params, address_cache, timeout=v2v_timeout): test.fail('Import VM failed') if output_mode == 'libvirt': try: virsh.start(vm_name, debug=True, ignore_status=False) except Exception as e: test.fail('Start vm failed: %s' % str(e)) # Check guest following the checkpoint document after conversion if params.get('skip_vm_check') != 'yes': ret = vmchecker.run() if len(ret) == 0: LOG.info("All common checkpoints passed") LOG.debug(vmchecker.vmxml) if checkpoint == 'multi_kernel': check_boot_kernel(vmchecker.checker) check_vmlinuz_initramfs(output) if checkpoint == 'floppy': # Convert to rhv will remove all removable devices(floppy, # cdrom) if output_mode in ['local', 'libvirt']: check_floppy_exist(vmchecker.checker) if checkpoint == 'multi_disks': check_disks(vmchecker.checker) if checkpoint == 'multi_netcards': check_multi_netcards(params['mac_address'], vmchecker.vmxml) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': vmchecker.check_graphics(params[checkpoint]) else: graph_type = checkpoint.split('_')[0] vmchecker.check_graphics({'type': graph_type}) video_type = vmchecker.xmltree.find( './devices/video/model').get('type') if utils_v2v.multiple_versions_compare( V2V_ADAPTE_SPICE_REMOVAL_VER): expect_video_type = 'vga' else: expect_video_type = 'qxl' if video_type.lower() != expect_video_type: log_fail('Video expect %s, actual %s' % (expect_video_type, video_type)) if checkpoint.startswith('listen'): listen_type = vmchecker.xmltree.find( './devices/graphics/listen').get('type') LOG.info('listen type is: %s', listen_type) if listen_type != checkpoint.split('_')[-1]: log_fail('listen type changed after conversion') if checkpoint.startswith('selinux'): status = vmchecker.checker.session.cmd( 'getenforce').strip().lower() LOG.info('Selinux status after v2v:%s', status) if status != checkpoint[8:]: log_fail('Selinux status not match') if checkpoint == 'check_selinuxtype': expect_output = vmchecker.checker.session.cmd( 'cat /etc/selinux/config') expect_selinuxtype = re.search(r'^SELINUXTYPE=\s*(\S+)$', expect_output, re.MULTILINE).group(1) actual_output = vmchecker.checker.session.cmd('sestatus') actual_selinuxtype = re.search( r'^Loaded policy name:\s*(\S+)$', actual_output, re.MULTILINE).group(1) if actual_selinuxtype != expect_selinuxtype: log_fail('Seliunx type not match') if checkpoint == 'guest_firewalld_status': check_firewalld_status(vmchecker.checker, params[checkpoint]) if checkpoint in ['ntpd_on', 'sync_ntp']: check_time_keep(vmchecker.checker) # Merge 2 error lists error_list.extend(vmchecker.errors) log_check = utils_v2v.check_log(params, output) if log_check: log_fail(log_check) if len(error_list): test.fail('%d checkpoints failed: %s' % (len(error_list), error_list)) try: v2v_sasl = None v2v_params = { 'target': target, 'hypervisor': hypervisor, 'main_vm': vm_name, 'input_mode': input_mode, 'network': network, 'bridge': bridge, 'os_storage': storage, 'os_pool': os_pool, 'hostname': source_ip, 'password': source_pwd, 'v2v_opts': v2v_opts, 'new_name': vm_name + utils_misc.generate_random_string(3), 'output_method': output_method, 'os_storage_name': storage_name, 'rhv_upload_opts': rhv_upload_opts, 'input_transport': input_transport, 'vcenter_host': source_ip, 'vcenter_password': source_pwd, 'vddk_thumbprint': vddk_thumbprint, 'vddk_libdir': vddk_libdir, 'vddk_libdir_src': vddk_libdir_src, 'params': params, } if vpx_dc: v2v_params.update({"vpx_dc": vpx_dc}) if esx_ip: v2v_params.update({"esx_ip": esx_ip}) output_format = params.get('output_format') if output_format: v2v_params.update({'of_format': output_format}) # Build rhev related options if output_mode == 'rhev': # Create different sasl_user name for different job params.update({ 'sasl_user': params.get("sasl_user") + utils_misc.generate_random_string(3) }) LOG.info('sals user name is %s' % params.get("sasl_user")) # Create SASL user on the ovirt host user_pwd = "[['%s', '%s']]" % (params.get("sasl_user"), params.get("sasl_pwd")) v2v_sasl = utils_sasl.SASL(sasl_user_pwd=user_pwd) v2v_sasl.server_ip = params.get("remote_ip") v2v_sasl.server_user = params.get('remote_user') v2v_sasl.server_pwd = params.get('remote_pwd') v2v_sasl.setup(remote=True) LOG.debug('A SASL session %s was created', v2v_sasl) if output_method == 'rhv_upload': # Create password file for '-o rhv_upload' to connect to ovirt with open(rhv_passwd_file, 'w') as f: f.write(rhv_passwd) # Copy ca file from ovirt to local remote.scp_from_remote(ovirt_hostname, 22, 'root', ovirt_engine_passwd, ovirt_ca_file_path, local_ca_file_path) if output_mode == 'local': v2v_params['os_directory'] = data_dir.get_tmp_dir() if output_mode == 'libvirt': pvt.pre_pool(pool_name, pool_type, pool_target, '') # Set libguestfs environment variable utils_v2v.set_libguestfs_backend(params) # Save origin graphic type for result checking if source is KVM if hypervisor == 'kvm': ori_vm_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) params['ori_graphic'] = ori_vm_xml.xmltreefile.find( 'devices').find('graphics').get('type') params['vm_machine'] = ori_vm_xml.xmltreefile.find( './os/type').get('machine') backup_xml = None # Only kvm guest's xml needs to be backup currently if checkpoint in backup_list and hypervisor == 'kvm': backup_xml = ori_vm_xml if checkpoint == 'multi_disks': new_xml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) disk_count = len(new_xml.get_disk_all_by_expr('device==disk')) if disk_count <= 1: test.error('Not enough disk devices') params['ori_disks'] = disk_count if checkpoint == 'sata_disk': change_disk_bus('sata') if checkpoint.startswith('floppy'): if params['vm_machine'] and 'q35' in params['vm_machine'] and int( re.search(r'pc-q35-rhel(\d+)\.', params['vm_machine']).group(1)) >= 8: test.cancel( 'Device isa-fdc is not supported with machine type %s' % params['vm_machine']) img_path = data_dir.get_tmp_dir() + '/floppy.img' utlv.create_local_disk('floppy', img_path) attach_removable_media('floppy', img_path, 'fda') if checkpoint == 'floppy_devmap': insert_floppy_devicemap() if checkpoint.startswith('fstab'): if checkpoint == 'fstab_cdrom': img_path = data_dir.get_tmp_dir() + '/cdrom.iso' utlv.create_local_disk('iso', img_path) attach_removable_media('cdrom', img_path, 'hdc') specify_fstab_entry(checkpoint[6:]) if checkpoint == 'running': virsh.start(vm_name) LOG.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'paused': virsh.start(vm_name, '--paused') LOG.info('VM state: %s' % virsh.domstate(vm_name).stdout.strip()) if checkpoint == 'serial_terminal': grub_serial_terminal() check_boot() if checkpoint.startswith('host_no_space'): session = aexpect.ShellSession('sh') large_file = create_large_file(session, 800) if checkpoint == 'host_no_space_setcache': LOG.info('Set LIBGUESTFS_CACHEDIR=/home') os.environ['LIBGUESTFS_CACHEDIR'] = '/home' if checkpoint == 'corrupt_rpmdb': corrupt_rpmdb() if checkpoint.startswith('network'): change_network_model(checkpoint[8:]) if checkpoint == 'multi_netcards': params['mac_address'] = [] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml( vm_name, virsh_instance=v2v_virsh) network_list = vmxml.get_iface_all() for mac in network_list: if network_list[mac].get('type') in ['bridge', 'network']: params['mac_address'].append(mac) if len(params['mac_address']) < 2: test.error('Not enough network interface') LOG.debug('MAC address: %s' % params['mac_address']) if checkpoint.startswith(('spice', 'vnc')): if checkpoint == 'spice_encrypt': spice_passwd = { 'type': 'spice', 'passwd': params.get('spice_passwd', 'redhat') } vm_xml.VMXML.set_graphics_attr(vm_name, spice_passwd) params[checkpoint] = { 'type': 'spice', 'passwdValidTo': '1970-01-01T00:00:01' } else: graphic_video = checkpoint.split('_') graphic = graphic_video[0] LOG.info('Set graphic type to %s', graphic) vm_xml.VMXML.set_graphics_attr(vm_name, {'type': graphic}) if len(graphic_video) > 1: video_type = graphic_video[1] LOG.info('Set video type to %s', video_type) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) video = vmxml.xmltreefile.find('devices').find( 'video').find('model') video.set('type', video_type) # cirrus doesn't support 'ram' and 'vgamem' attribute if video_type == 'cirrus': [ video.attrib.pop(attr_i) for attr_i in ['ram', 'vgamem'] if attr_i in video.attrib ] vmxml.sync() if checkpoint.startswith('listen'): listen_type = checkpoint.split('_')[-1] vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) listen = vmxml.xmltreefile.find('devices').find('graphics').find( 'listen') listen.set('type', listen_type) vmxml.sync() if checkpoint == 'host_selinux_on': params['selinux_stat'] = utils_selinux.get_status() utils_selinux.set_status('enforcing') if checkpoint.startswith('selinux'): set_selinux(checkpoint[8:]) if checkpoint.startswith('host_firewalld'): service_mgr = service.ServiceManager() LOG.info('Backing up firewall services status') params['bk_firewalld_status'] = service_mgr.status('firewalld') if 'start' in checkpoint: service_mgr.start('firewalld') if 'stop' in checkpoint: service_mgr.stop('firewalld') if checkpoint == 'guest_firewalld_status': get_firewalld_status() if checkpoint == 'remove_securetty': LOG.info('Remove /etc/securetty file from guest') cmd = ['rm -f /etc/securetty'] vm_cmd(cmd) if checkpoint == 'ntpd_on': LOG.info('Set service chronyd on') cmd = [ 'yum -y install chrony', 'systemctl start chronyd', 'chronyc add server %s' % ntp_server ] vm_cmd(cmd) if checkpoint == 'sync_ntp': LOG.info('Sync time with %s', ntp_server) cmd = [ 'yum -y install chrony', 'systemctl start chronyd', 'chronyc add server %s' % ntp_server, 'chronyc waitsync' ] vm_cmd(cmd) if checkpoint == 'blank_2nd_disk': disk_path = os.path.join(data_dir.get_tmp_dir(), 'blank.img') LOG.info('Create blank disk %s', disk_path) process.run('truncate -s 1G %s' % disk_path) LOG.info('Attach blank disk to vm') attach_removable_media('disk', disk_path, 'vdc') LOG.debug(virsh.dumpxml(vm_name)) if checkpoint in ['only_net', 'only_br']: LOG.info('Detatch all networks') virsh.detach_interface(vm_name, 'network --current', debug=True) LOG.info('Detatch all bridges') virsh.detach_interface(vm_name, 'bridge --current', debug=True) if checkpoint == 'only_net': LOG.info('Attach network') virsh.attach_interface(vm_name, 'network default --current', debug=True) if checkpoint == 'only_br': LOG.info('Attatch bridge') virsh.attach_interface(vm_name, 'bridge virbr0 --current', debug=True) if checkpoint == 'no_libguestfs_backend': os.environ.pop('LIBGUESTFS_BACKEND') if checkpoint == 'file_image': vm = env.get_vm(vm_name) disk = vm.get_first_disk_devices() LOG.info('Disk type is %s', disk['type']) if disk['type'] != 'file': test.error('Guest is not with file image') v2v_result = utils_v2v.v2v_cmd(v2v_params) if v2v_params.get('new_name'): vm_name = params['main_vm'] = v2v_params['new_name'] check_result(v2v_result, status_error) finally: if close_virsh and v2v_virsh: LOG.debug('virsh session %s is closing', v2v_virsh) v2v_virsh.close_session() if params.get('vmchecker'): params['vmchecker'].cleanup() if enable_legacy_policy: update_crypto_policy() if hypervisor == "xen": utils_v2v.v2v_setup_ssh_key_cleanup(xen_session, xen_pubkey) process.run('ssh-agent -k') if output_mode == 'rhev' and v2v_sasl: v2v_sasl.cleanup() LOG.debug('SASL session %s is closing', v2v_sasl) v2v_sasl.close_session() if output_mode == 'libvirt': pvt.cleanup_pool(pool_name, pool_type, pool_target, '') if backup_xml: backup_xml.sync() if params.get('selinux_stat') and params['selinux_stat'] != 'disabled': utils_selinux.set_status(params['selinux_stat']) if 'bk_firewalld_status' in params: service_mgr = service.ServiceManager() if service_mgr.status( 'firewalld') != params['bk_firewalld_status']: if params['bk_firewalld_status']: service_mgr.start('firewalld') else: service_mgr.stop('firewalld') if checkpoint.startswith('host_no_space'): if large_file and os.path.isfile(large_file): os.remove(large_file) # Cleanup constant files utils_v2v.cleanup_constant_files(params)
def attach_nic(): # pylint: disable=W0611 """ Attach interface, by xml or cmd, for both hot and cold plug """ def create_iface_xml(mac): """ Create interface xml file :param mac: The mac address of nic device """ iface = Interface(type_name='network') iface.source = iface_source iface.model = iface_model iface.mac_address = mac logging.debug("Create new interface xml: %s", iface) return iface plug_method = params.get('plug_method', 'interface') cold_plug = params.get('cold_plug', 'no') mac = utils_net.generate_mac_address_simple() iface_source = {'network': 'default'} iface_model = params["virtio_model"] options = ("network %s --model %s --mac %s" % (iface_source['network'], iface_model, mac)) nic_params = { 'mac': mac, 'nettype': params['nettype'], 'ip_version': 'ipv4' } if cold_plug == "yes": options += ' --config' if plug_method == 'interface': # Hotplug nic vir attach-interface ret = virsh.attach_interface(vm_name, options, ignore_status=True) else: # Hotplug nic via attach-device nic_xml = create_iface_xml(mac) nic_xml.xmltreefile.write() xml_file = nic_xml.xml with open(xml_file) as nic_file: logging.debug("Attach device by XML: %s", nic_file.read()) ret = virsh.attach_device(domainarg=vm_name, filearg=xml_file, debug=True) libvirt.check_exit_status(ret) if cold_plug == "yes": reboot() # Reboot guest if it is cold plug test detect_new_nic(mac) if plug_method == 'interface' and cold_plug == 'no': check_plug_to_pci_bridge(vm_name, mac) session = vm.wait_for_login(serial=True) # Add nic to VM object for further check nic_name = vm.add_nic(**nic_params)["nic_name"] nic = vm.virtnet[nic_name] # Config ip inside guest for new added nic if not utils_misc.wait_for( lambda: get_hotplug_nic_ip(vm, nic, session, guest_os_type), timeout=30): test.fail("Does not find plugged nic %s in guest" % mac) options = ("network %s" % mac) if cold_plug == "yes": options += ' --config' # Detach nic device if plug_method == 'interface': ret = virsh.detach_interface(vm_name, options, ignore_status=True) else: with open(xml_file) as nic_file: logging.debug("Detach device by XML: %s", nic_file.read()) ret = virsh.detach_device(domainarg=vm_name, filearg=xml_file, debug=True) libvirt.check_exit_status(ret) if cold_plug == "yes": session = reboot() # Reboot guest if it is cold plug test # Check if nic is removed from guest if not utils_misc.wait_for(lambda: check_nic_removed(mac, session), timeout=30): test.fail("The nic %s still exist in guest after being unplugged" % nic_name)
def run(test, params, env): """ Test virsh {at|de}tach-interface command. 1) Prepare test environment and its parameters 2) Attach the required interface 3) According test type(only attach or both attach and detach): a.Go on to test detach(if attaching is correct) b.Return GOOD or raise TestFail(if attaching is wrong) 4) Check if attached interface is correct: a.Try to catch it in vm's XML file b.Try to catch it in vm 5) Detach the attached interface 6) Check result """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) backup_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Test parameters uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) vm_ref = params.get("at_detach_iface_vm_ref", "domname") options_suffix = params.get("at_detach_iface_options_suffix", "") status_error = "yes" == params.get("status_error", "no") start_vm = params.get("start_vm") # Should attach must be pass for detach test. correct_attach = "yes" == params.get("correct_attach", "no") readonly = ("yes" == params.get("readonly", "no")) # Interface specific attributes. iface_type = params.get("at_detach_iface_type", "network") if iface_type == "bridge": try: utils_path.find_command("brctl") except utils_path.CmdNotFoundError: test.cancel("Command 'brctl' is missing. You must " "install it.") iface_source = params.get("at_detach_iface_source", "default") iface_mode = params.get("at_detach_iface_mode", "vepa") iface_mac = params.get("at_detach_iface_mac", "created") iface_target = params.get("at_detach_iface_target") iface_model = params.get("at_detach_iface_model") iface_inbound = params.get("at_detach_iface_inbound") iface_outbound = params.get("at_detach_iface_outbound") iface_rom = params.get("at_detach_rom_bar") iface_link = params.get("at_detach_link_state") iface_boot = params.get("at_detach_boot_order") iface_driver = params.get("at_detach_iface_driver") iface_driver_host = params.get("at_detach_driver_host") iface_driver_guest = params.get("at_detach_driver_guest") iface_backend = params.get("at_detach_iface_backend") save_restore = params.get("save_restore", "no") restart_libvirtd = params.get("restart_libvirtd", "no") attach_cmd = params.get("attach_cmd", "attach-interface") virsh_dargs = {'ignore_status': True, 'debug': True, 'uri': uri} # Get iface name if iface_type is direct if iface_type == "direct": iface_source = utils_net.get_net_if(state="UP")[0] # Get a bridge name for test if iface_type is bridge. # If there is no bridge other than virbr0, raise TestCancel if iface_type == "bridge": host_bridge = utils_net.Bridge() bridge_list = host_bridge.list_br() try: bridge_list.remove("virbr0") except AttributeError: pass # If no virbr0, just pass is ok logging.debug("Useful bridges:%s", bridge_list) # just choosing one bridge on host. if len(bridge_list): iface_source = bridge_list[0] else: test.cancel("No useful bridge on host " "other than 'virbr0'.") # Test both detach and attach, So collect info # both of them for result check. # When something wrong with interface, set it to 1 fail_flag = 0 result_info = [] # Get a mac address if iface_mac is 'created'. if iface_mac == "created" or correct_attach: iface_mac = utils_net.generate_mac_address_simple() # Record all iface parameters in iface_dict iface_dict = {} update_list = [ "driver", "driver_host", "driver_guest", "model", "rom", "inbound", "outbound", "link", "target", "mac", "source", "boot", "backend", "type", "mode" ] names = locals() for update_item in update_list: if names["iface_"+update_item]: iface_dict.update({update_item: names["iface_"+update_item]}) else: iface_dict.update({update_item: None}) logging.info("iface_dict is %s", iface_dict) # Format the params iface_format = format_param(iface_dict) logging.info("iface_format is %s", iface_format) try: # Generate xml file if using attach-device command if attach_cmd == "attach-device": # Change boot order to disk libvirt.change_boot_order(vm_name, "disk", "1") vm.destroy() vm.start() # Generate attached xml xml_file_tmp = libvirt.modify_vm_iface(vm_name, "get_xml", iface_format) new_iface = Interface(type_name=iface_type) new_iface.xml = xml_file_tmp new_iface.del_address() xml_file = new_iface.xml # To confirm vm's state and make sure os fully started if start_vm == "no": if vm.is_alive(): vm.destroy() else: vm.wait_for_login().close() # Set attach-interface domain dom_uuid = vm.get_uuid() dom_id = vm.get_id() if vm_ref == "domname": vm_ref = vm_name elif vm_ref == "domid": vm_ref = dom_id elif vm_ref == "domuuid": vm_ref = dom_uuid elif vm_ref == "hexdomid" and dom_id is not None: vm_ref = hex(int(dom_id)) # Set attach-interface options and Start attach-interface test if correct_attach: options = set_options("network", "default", iface_mac, "", "attach") if readonly: virsh_dargs.update({'readonly': True, 'debug': True}) attach_result = virsh.attach_interface(vm_name, options, **virsh_dargs) else: if attach_cmd == "attach-interface": options = set_options(iface_type, iface_source, iface_mac, options_suffix, "attach", iface_target, iface_model, iface_inbound, iface_outbound) attach_result = virsh.attach_interface(vm_ref, options, **virsh_dargs) elif attach_cmd == "attach-device": attach_result = virsh.attach_device(vm_name, xml_file, ignore_status=True, debug=True) attach_status = attach_result.exit_status logging.debug(attach_result) # If attach interface failed. if attach_status: if not status_error: fail_flag = 1 result_info.append("Attach Failed: %s" % attach_result.stderr) elif status_error: # Here we just use it to exit, do not mean test failed fail_flag = 1 # If attach interface succeeded. else: if status_error and not correct_attach: fail_flag = 1 result_info.append("Attach Success with wrong command.") if fail_flag and start_vm == "yes": vm.destroy() if len(result_info): test.fail(result_info) else: # Exit because it is error_test for attach-interface. return if "print-xml" in options_suffix: iface_obj = Interface(type_name=iface_type) iface_obj.xml = attach_result.stdout.strip() if (iface_obj.type_name == iface_type and iface_obj.source['dev'] == iface_source and iface_obj.target['dev'] == iface_target and iface_obj.model == iface_model and iface_obj.bandwidth.inbound == eval(iface_format['inbound']) and iface_obj.bandwidth.outbound == eval(iface_format['outbound'])): logging.info("Print ml all element check pass") else: test.fail("Print xml do not show as expected") # Check dumpxml file whether the interface is added successfully. status, ret = check_dumpxml_iface(vm_name, iface_format) if "print-xml" not in options_suffix: if status: fail_flag = 1 result_info.append(ret) else: if status == 0: test.fail("Attach interface effect in xml with print-xml option") else: return # Login to domain to check new interface. if not vm.is_alive(): vm.start() elif vm.state() == "paused": vm.resume() status, ret = login_to_check(vm, iface_mac) if status: fail_flag = 1 result_info.append(ret) # Check on host for direct type if iface_type == 'direct': cmd_result = process.run("ip -d link show test").stdout_text.strip() logging.info("cmd output is %s", cmd_result) check_patten = ("%s@%s.*\n.*%s.*\n.*macvtap.*mode.*%s" % (iface_target, iface_source, iface_mac, iface_mode)) logging.info("check patten is %s", check_patten) if not re.search(check_patten, cmd_result): logging.error("Can not find %s in ip link" % check_patten) fail_flag = 1 result_info.append(cmd_result) # Do operation and check again if restart_libvirtd == "yes": libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() if save_restore == "yes": check_save_restore(vm_name) status, ret = check_dumpxml_iface(vm_name, iface_format) if status: fail_flag = 1 result_info.append(ret) # Set detach-interface options options = set_options(iface_type, None, iface_mac, options_suffix, "detach") # Start detach-interface test if save_restore == "yes" and vm_ref == dom_id: vm_ref = vm_name detach_result = virsh.detach_interface(vm_ref, options, **virsh_dargs) detach_status = detach_result.exit_status detach_msg = detach_result.stderr.strip() logging.debug(detach_result) if detach_status == 0 and status_error == 0: # Check the xml after detach and clean up if needed. time.sleep(5) status, _ = check_dumpxml_iface(vm_name, iface_format) if status == 0: detach_status = 1 detach_msg = "xml still exist after detach" cleanup_options = "--type %s --mac %s" % (iface_type, iface_mac) virsh.detach_interface(vm_ref, cleanup_options, **virsh_dargs) else: logging.info("After detach, the interface xml disappeared") # Check results. if status_error: if detach_status == 0: test.fail("Detach Success with wrong command.") else: if detach_status != 0: test.fail("Detach Failed: %s" % detach_msg) else: if fail_flag: test.fail("Attach-Detach Success but " "something wrong with its " "functional use:%s" % result_info) finally: if vm.is_alive(): vm.destroy() backup_xml.sync()
def run(test, params, env): """ Test virsh {at|de}tach-interface command. 1) Prepare test environment and its parameters 2) Attach the required interface 3) Perform attach and detach operation 4) Check if attached interface is correct 5) Detach the attached interface """ def is_attached(vmxml_devices, iface_type, iface_source, iface_mac): """ Check attached interface exist or not. :param vmxml_devices: VMXMLDevices instance :param iface_type: interface device type :param iface_source : interface source :param iface_mac : interface MAC address :return: True/False if backing file and interface found """ ifaces = vmxml_devices.by_device_tag('interface') for iface in ifaces: if iface.type_name != iface_type: continue if iface.mac_address != iface_mac: continue if iface_source is not None: if iface.xmltreefile.find('source') is not None: if iface.source['network'] != iface_source: continue else: continue # All three conditions met logging.debug("Find %s in given iface XML", iface_mac) return True logging.debug("Not find %s in given iface XML", iface_mac) return False def check_result(vm_name, iface_source, iface_type, iface_mac, flags, vm_state, attach=True): """ Check the test result of attach/detach-device command. """ active_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) if not attach: utils_misc.wait_for(lambda: not is_attached(active_vmxml.devices, iface_type, iface_source, iface_mac), 20) active_attached = is_attached(active_vmxml.devices, iface_type, iface_source, iface_mac) if vm_state != "transient": inactive_vmxml = vm_xml.VMXML.new_from_dumpxml( vm_name, options="--inactive") inactive_attached = is_attached(inactive_vmxml.devices, iface_type, iface_source, iface_mac) if flags.count("config"): if vm_state != "transient": if attach: if not inactive_attached: raise exceptions.TestFail("Inactive domain XML not" " updated when --config " "options used for attachment") else: if inactive_attached: raise exceptions.TestFail("Inactive domain XML not" " updated when --config " "options used for detachment") if flags.count("live"): if attach: if vm_state in ["paused", "running", "transient"]: if not active_attached: raise exceptions.TestFail("Active domain XML not updated" " when --live options used for" " attachment") else: if vm_state in ["paused", "running", "transient"]: if active_attached: raise exceptions.TestFail("Active domain XML not updated" " when --live options used for" " detachment") if flags.count("current") or flags == "": if attach: if vm_state in ["paused", "running", "transient"]: if not active_attached: raise exceptions.TestFail("Active domain XML not updated" " when --current options used " "for attachment") elif vm_state == "shutoff" and not inactive_attached: raise exceptions.TestFail("Inactive domain XML not updated" " when --current options used for" " attachment") else: if vm_state in ["paused", "running", "transient"]: if active_attached: raise exceptions.TestFail("Active domain XML not updated" " when --current options used " "for detachment") elif vm_state == "shutoff" and inactive_attached: raise exceptions.TestFail("Inactive domain XML not updated " "when --current options used for " "detachment") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) # Test parameters uri = libvirt_vm.normalize_connect_uri(params.get("connect_uri", "default")) vm_ref = params.get("at_detach_iface_vm_ref", "domname") at_options_suffix = params.get("at_dt_iface_at_options", "") dt_options_suffix = params.get("at_dt_iface_dt_options", "") at_status_error = "yes" == params.get("at_status_error", "no") dt_status_error = "yes" == params.get("dt_status_error", "no") pre_vm_state = params.get("at_dt_iface_pre_vm_state") # Skip if libvirt doesn't support --live/--current. if (at_options_suffix.count("--live") or dt_options_suffix.count("--live")): if not libvirt_version.version_compare(1, 0, 5): raise exceptions.TestSkipError("update-device doesn't" " support --live") if (at_options_suffix.count("--current") or dt_options_suffix.count("--current")): if not libvirt_version.version_compare(1, 0, 5): raise exceptions.TestSkipError("virsh update-device " "doesn't support --current") # Interface specific attributes. iface_type = params.get("at_detach_iface_type", "network") if iface_type == "bridge": try: utils_misc.find_command("brctl") except ValueError: raise exceptions.TestSkipError("Command 'brctl' is missing." " You must install it.") iface_source = params.get("at_detach_iface_source", "default") iface_mac = params.get("at_detach_iface_mac", "created") virsh_dargs = {'ignore_status': True, 'uri': uri, 'debug': True} # Check host version. rhel6_host = False if not process.run("grep 'Red Hat Enterprise Linux Server " "release 6' /etc/redhat-release", ignore_status=True, shell=True).exit_status: rhel6_host = True # Back up xml file. if vm.is_alive(): vm.destroy(gracefully=False) backup_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Get a bridge name for test if iface_type is bridge. # If there is no bridge other than virbr0, raise TestSkipError if iface_type == "bridge": host_bridge = utils_net.Bridge() bridge_list = host_bridge.list_br() try: bridge_list.remove("virbr0") except AttributeError: pass # If no virbr0, just pass is ok logging.debug("Useful bridges:%s", bridge_list) # just choosing one bridge on host. if len(bridge_list): iface_source = bridge_list[0] else: raise exceptions.TestSkipError("No useful bridge on host " "other than 'virbr0'.") # Turn VM into certain state. if pre_vm_state == "running": if (rhel6_host and at_options_suffix == "--config" and dt_options_suffix == ""): raise exceptions.TestSkipError("For bug921407, " "won't fix on rhel6 host") logging.info("Starting %s..." % vm_name) if vm.is_dead(): vm.start() vm.wait_for_login().close() elif pre_vm_state == "shutoff": logging.info("Shuting down %s..." % vm_name) if vm.is_alive(): vm.destroy(gracefully=False) elif pre_vm_state == "paused": if (rhel6_host and at_options_suffix == "--config" and dt_options_suffix == ""): raise exceptions.TestSkipError("For bug921407, " "won't fix on rhel6 host") logging.info("Pausing %s..." % vm_name) if vm.is_dead(): vm.start() vm.wait_for_login().close() if not vm.pause(): raise exceptions.TestSkipError("Cann't pause the domain") elif pre_vm_state == "transient": logging.info("Creating %s..." % vm_name) vm.undefine() if virsh.create(backup_xml.xml, **virsh_dargs).exit_status: backup_xml.define() raise exceptions.TestSkipError("Cann't create the domain") dom_uuid = vm.get_uuid() dom_id = vm.get_id() # Set attach-interface domain if vm_ref == "domname": vm_ref = vm_name elif vm_ref == "domid": vm_ref = dom_id elif vm_ref == "domuuid": vm_ref = dom_uuid elif vm_ref == "hexdomid" and dom_id is not None: vm_ref = hex(int(dom_id)) # Get a mac address if iface_mac is 'created'. if iface_mac == "created": iface_mac = utils_net.generate_mac_address_simple() try: # Set attach-interface options and # start attach-interface test options = set_options(iface_type, iface_source, iface_mac, at_options_suffix, "attach") ret = virsh.attach_interface(vm_name, options, **virsh_dargs) libvirt.check_exit_status(ret, at_status_error) # Check if the command take effect in vm # or config file. if vm.is_paused(): vm.resume() vm.wait_for_login().close() #Sleep a while for vm is stable time.sleep(3) if not ret.exit_status: check_result(vm_name, iface_source, iface_type, iface_mac, at_options_suffix, pre_vm_state) # Set detach-interface options options = set_options(iface_type, None, iface_mac, dt_options_suffix, "detach") # Sleep for a while time.sleep(10) # Start detach-interface test if pre_vm_state == "paused": if not vm.pause(): raise exceptions.TestFail("Cann't pause the domain") ret = virsh.detach_interface(vm_ref, options, **virsh_dargs) if rhel6_host and pre_vm_state in ['paused', 'running']: if (at_options_suffix == "--config" and dt_options_suffix == "--config"): dt_status_error = True libvirt.check_exit_status(ret, dt_status_error) # Check if the command take effect # in vm or config file. if vm.is_paused(): vm.resume() vm.wait_for_login().close() #Sleep a while for vm is stable time.sleep(10) if not ret.exit_status: check_result(vm_name, iface_source, iface_type, iface_mac, dt_options_suffix, pre_vm_state, False) finally: # Restore the vm if vm.is_alive(): vm.destroy(gracefully=False, free_mac_addresses=False) backup_xml.sync()
def network_hook(): """ Check network hooks. """ # Set interface to use default network net_name = params.get("net_name", "default") edit_iface(net_name) prepare_hook_file(hook_script % (net_name, hook_log)) try: # destroy the network ret = virsh.net_destroy(net_name, **virsh_dargs) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " stopped end -" assert check_hooks(hook_str) # start network ret = virsh.net_start(net_name, **virsh_dargs) libvirt.check_exit_status(ret) hook_str = hook_file + " " + net_name + " start begin -" assert check_hooks(hook_str) hook_str = hook_file + " " + net_name + " started begin -" assert check_hooks(hook_str) if vm.is_alive(): vm.destroy(gracefully=False) # Remove all controllers, interfaces and addresses in vm dumpxml vm_inactive_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vm_inactive_xml.remove_all_device_by_type('controller') type_dict = {'address': '/devices/*/address'} try: for elem in vm_inactive_xml.xmltreefile.findall( type_dict['address']): vm_inactive_xml.xmltreefile.remove(elem) except (AttributeError, TypeError) as details: test.fail("Fail to remove address.") vm_inactive_xml.xmltreefile.write() machine_list = vm_inactive_xml.os.machine.split("-") # Modify machine type according to the requirements and Add controllers to VM according to machine type def generate_controller(controller_dict): controller_xml = Controller("controller") controller_xml.model = controller_dict['model'] controller_xml.type = controller_dict['type'] controller_xml.index = controller_dict['index'] return controller_xml if machine_type == 'pc': vm_inactive_xml.set_os_attrs( **{ "machine": machine_list[0] + "-i440fx-" + machine_list[2] }) pc_Dict0 = {'model': 'pci-root', 'type': 'pci', 'index': 0} pc_Dict1 = {'model': 'pci-bridge', 'type': 'pci', 'index': 1} vm_inactive_xml.add_device(generate_controller(pc_Dict0)) vm_inactive_xml.add_device(generate_controller(pc_Dict1)) elif machine_type == 'q35': vm_inactive_xml.set_os_attrs( **{"machine": machine_list[0] + "-q35-" + machine_list[2]}) q35_Dict0 = {'model': 'pcie-root', 'type': 'pci', 'index': 0} q35_Dict1 = { 'model': 'pcie-root-port', 'type': 'pci', 'index': 1 } q35_Dict2 = { 'model': 'pcie-to-pci-bridge', 'type': 'pci', 'index': 2 } vm_inactive_xml.add_device(generate_controller(q35_Dict0)) vm_inactive_xml.add_device(generate_controller(q35_Dict1)) vm_inactive_xml.add_device(generate_controller(q35_Dict2)) vm_inactive_xml.sync() # Plug a interface and Unplug the interface vm.start() vm.wait_for_login().close() interface_num = len( vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( "interface")) mac_addr = "52:54:00:9a:53:a9" logging.debug(vm_xml.VMXML.new_from_dumpxml(vm_name)) def is_attached_interface(): return len( vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( "interface")) == interface_num + 1 ret = virsh.attach_interface(vm_name, ("network %s --mac %s" % (net_name, mac_addr))) libvirt.check_exit_status(ret) if utils_misc.wait_for(is_attached_interface, timeout=20) is not True: test.fail("Attaching interface failed.") if libvirt_version.version_compare(6, 0, 0): hook_str = hook_file + " " + net_name + " port-created begin -" else: hook_str = hook_file + " " + net_name + " plugged begin -" assert check_hooks(hook_str) def is_detached_interface(): return len( vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( "interface")) == interface_num ret = virsh.detach_interface(vm_name, "network --mac %s" % mac_addr) libvirt.check_exit_status(ret) utils_misc.wait_for(is_detached_interface, timeout=50) # Wait for timeout and if not succeeded, detach again (during testing, detaching interface failed from q35 VM for the first time when using this function) if len( vm_xml.VMXML.new_from_dumpxml(vm_name).get_devices( "interface")) != interface_num: ret = virsh.detach_interface(vm_name, "network --mac %s" % mac_addr) libvirt.check_exit_status(ret) if utils_misc.wait_for(is_detached_interface, timeout=50) is not True: test.fail("Detaching interface failed.") if libvirt_version.version_compare(6, 0, 0): hook_str = hook_file + " " + net_name + " port-deleted begin -" else: hook_str = hook_file + " " + net_name + " unplugged begin -" assert check_hooks(hook_str) # remove the log file if os.path.exists(hook_log): os.remove(hook_log) # destroy the domain vm.destroy() if libvirt_version.version_compare(6, 0, 0): hook_str = hook_file + " " + net_name + " port-deleted begin -" else: hook_str = hook_file + " " + net_name + " unplugged begin -" assert check_hooks(hook_str) except AssertionError: utils_misc.log_last_traceback() test.fail("Failed to check network hooks")
def run(test, params, env): """ Test mtu feature from virtual network """ vm_name = params.get('main_vm') vm = env.get_vm(vm_name) mtu_type = params.get('mtu_type') mtu_size = params.get('mtu_size', '') net = params.get('net', DEFAULT_NET) net_type = params.get('net_type', '') with_iface = 'yes' == params.get('with_iface', 'no') with_net = 'yes' == params.get('with_net', 'no') status_error = 'yes' == params.get('status_error', 'no') check = params.get('check', '') error_msg = params.get('error_msg', '') bridge_name = 'br_mtu' + utils_misc.generate_random_string(3) add_pkg = params.get('add_pkg', '') model = params.get('model', 'virtio') def set_network(size, net='default'): """ Set mtu size to a certain network """ logging.info('Set mtu size of network "%s" to %s', net, size) default_xml = NetworkXML.new_from_net_dumpxml(net) default_xml.mtu = size default_xml.sync() logging.debug(virsh.net_dumpxml(net)) def set_interface(mtu_size='', source_network='default', iface_type='network', iface_model='virtio'): """ Set mtu size to a certain interface """ interface_type = 'bridge' if iface_type in ('bridge', 'openvswitch') else iface_type iface_dict = { 'type': interface_type, 'source': "{'%s': '%s'}" % (interface_type, source_network), 'model': iface_model } if iface_type == 'openvswitch': iface_dict.update({'virtualport_type': 'openvswitch'}) if mtu_size: iface_dict.update({'mtu': "{'size': %s}" % mtu_size}) libvirt.modify_vm_iface(vm_name, 'update_iface', iface_dict) logging.debug(virsh.dumpxml(vm_name).stdout) def get_default_if(): """ Get default interface that is using by vm """ ifaces = utils_net.get_sorted_net_if() logging.debug('Interfaces on host: %s', ifaces) for iface in ifaces[0]: if 'Link detected: yes' in process.run('ethtool %s' % iface).stdout_text: logging.debug('Found host interface "%s"', iface) return iface def create_bridge(): """ Create a bridge on host for test """ cmd_create_br = 'nmcli con add type bridge con-name %s ifname %s' con_name = 'con_' + utils_misc.generate_random_string(3) bridge_name = 'br_' + utils_misc.generate_random_string(3) process.run(cmd_create_br % (con_name, bridge_name), verbose=True) return con_name, bridge_name def create_network_xml(name, network_type, base_if='', **kwargs): """ Create a network xml to be defined """ m_net = NetworkXML(name) m_net.forward = {'mode': 'bridge'} if network_type in ('bridge', 'openvswitch'): m_net.bridge = {'name': kwargs['bridge_name']} elif network_type == 'macvtap': if base_if: m_net.forward_interface = [{'dev': base_if}] if network_type == 'openvswitch': m_net.virtualport_type = 'openvswitch' if 'mtu' in kwargs: m_net.mtu = kwargs['mtu'] logging.debug(m_net) return m_net.xml def create_iface(iface_type, **kwargs): """ Create a interface to be attached to vm """ m_iface = Interface(iface_type) m_iface.mac_address = utils_net.generate_mac_address_simple() if 'base_if' in kwargs: m_iface.source = {'dev': kwargs['base_if'], 'mode': 'vepa'} if 'source_net' in kwargs: m_iface.source = {'network': kwargs['source_net']} if 'mtu' in kwargs: m_iface.mtu = {'size': kwargs['mtu']} if 'model_net' in kwargs: m_iface.model = kwargs['model_net'] logging.debug(m_iface.get_xml()) logging.debug(m_iface) return m_iface def check_mtu(mtu_size, qemu=False): """ Check if mtu meets expectation on host """ error = '' live_vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) iface_xml = live_vmxml.get_devices('interface')[0] logging.debug(iface_xml.target) dev = iface_xml.target['dev'] ifconfig_info = process.run('ifconfig|grep mtu|grep %s' % dev, shell=True, verbose=True).stdout_text if 'mtu %s' % mtu_size in ifconfig_info: logging.info('PASS on ifconfig check for vnet.') else: error += 'Fail on ifconfig check for vnet.' if qemu: qemu_mtu_info = process.run('ps aux|grep qemu-kvm', shell=True, verbose=True).stdout_text if 'host_mtu=%s' % mtu_size in qemu_mtu_info: logging.info('PASS on qemu cmd line check.') else: error += 'Fail on qemu cmd line check.' if error: test.fail(error) def check_mtu_in_vm(fn_login, mtu_size): """ Check if mtu meets expectations in vm """ session = fn_login() check_cmd = 'ifconfig' output = session.cmd(check_cmd) session.close() logging.debug(output) if 'mtu %s' % mtu_size not in output: test.fail('MTU check inside vm failed.') else: logging.debug("MTU check inside vm passed.") try: bk_xml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) bk_netxml = NetworkXML.new_from_net_dumpxml(DEFAULT_NET) if add_pkg: add_pkg = add_pkg.split() utils_package.package_install(add_pkg) if 'openvswitch' in add_pkg: br = 'ovsbr0' + utils_misc.generate_random_string(3) process.run('systemctl start openvswitch.service', shell=True, verbose=True) process.run('ovs-vsctl add-br %s' % br, shell=True, verbose=True) process.run('ovs-vsctl show', shell=True, verbose=True) if not check or check in ['save', 'managedsave', 'hotplug_save']: # Create bridge or network and set mtu iface_type = 'network' if net_type in ('bridge', 'openvswitch'): if net_type == 'bridge': params['con_name'], br = create_bridge() if mtu_type == 'network': test_net = create_network_xml( bridge_name, net_type, bridge_name=br ) virsh.net_create(test_net, debug=True) virsh.net_dumpxml(bridge_name, debug=True) if mtu_type == 'interface': iface_type = net_type bridge_name = br elif net_type == 'network': if mtu_type == 'network': set_network(mtu_size) iface_mtu = 0 if mtu_type == 'interface': iface_mtu = mtu_size if mtu_type == 'network' and with_iface: mtu_size = str(int(mtu_size)//2) iface_mtu = mtu_size source_net = bridge_name if net_type in ('bridge', 'openvswitch') else 'default' # set mtu in vm interface set_interface(iface_mtu, source_network=source_net, iface_type=iface_type, iface_model=model) vm.start() vm_login = vm.wait_for_serial_login if net_type in ('bridge', 'openvswitch') else vm.wait_for_login vm_login().close() check_qemu = True if mtu_type == 'interface' else False # Test mtu after save vm if check in ('save', 'hotplug_save'): if check == 'hotplug_save': iface = create_iface('network', source_net='default', mtu=mtu_size, model_net=model) params['mac'] = iface.mac_address virsh.attach_device(vm_name, iface.xml, debug=True) virsh.dumpxml(vm_name, debug=True) dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) if params['mac'] not in str(dom_xml): test.fail('Failed to attach interface with mtu') save_path = os.path.join(data_dir.get_tmp_dir(), vm_name + '.save') virsh.save(vm_name, save_path, debug=True) virsh.restore(save_path, debug=True) if check == 'managedsave': virsh.managedsave(vm_name, debug=True) virsh.start(vm_name, debug=True) # Check in both host and vm check_mtu(mtu_size, check_qemu) check_mtu_in_vm(vm_login, mtu_size) vm_login(timeout=60).close() if check == 'hotplug_save': virsh.detach_interface(vm_name, 'network %s' % params['mac'], debug=True) time.sleep(5) dom_xml = vm_xml.VMXML.new_from_dumpxml(vm_name) if params['mac'] in str(dom_xml): test.fail('Failed to detach interface with mtu after save-restore') else: hotplug = 'yes' == params.get('hotplug', 'False') if check == 'net_update': result = virsh.net_update( DEFAULT_NET, 'modify', 'mtu', '''"<mtu size='%s'/>"''' % mtu_size, debug=True ) if check in ('macvtap', 'bridge_net', 'ovswitch_net'): base_if = get_default_if() macv_name = 'direct-macvtap' + utils_misc.generate_random_string(3) # Test mtu in different type of network if mtu_type == 'network': if check == 'macvtap': test_net = create_network_xml(macv_name, 'macvtap', base_if, mtu=mtu_size) if check == 'bridge_net': params['con_name'], br = create_bridge() test_net = create_network_xml( bridge_name, 'bridge', mtu=mtu_size, bridge_name=br ) if check == 'ovswitch_net': test_net = create_network_xml( bridge_name, 'openvswitch', mtu=mtu_size, bridge_name=br ) if 'net_create' in params['id']: result = virsh.net_create(test_net, debug=True) if 'net_define' in params['id']: result = virsh.net_define(test_net, debug=True) # Test mtu with or without a binding network elif mtu_type == 'interface': vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) if with_net: test_net = create_network_xml(macv_name, 'macvtap', base_if) virsh.net_create(test_net, debug=True) iface = create_iface('network', source_net=macv_name, mtu=mtu_size) if hotplug: result = virsh.attach_device(vm_name, iface.xml, debug=True) else: vmxml.add_device(iface) vmxml.sync() result = virsh.start(vm_name) else: iface = create_iface('direct', base_if=base_if, mtu=mtu_size) if hotplug: result = virsh.attach_device(vm_name, iface.xml, debug=True) else: vmxml.add_device(iface) result = virsh.define(vmxml.xml, debug=True) if check == 'invalid_val': iface = create_iface('network', source_net='default', mtu=mtu_size) result = virsh.attach_device(vm_name, iface.xml, debug=True) # Check result libvirt.check_exit_status(result, status_error) libvirt.check_result(result, [error_msg]) finally: bk_xml.sync() bk_netxml.sync() if 'test_net' in locals(): virsh.net_destroy(bridge_name, debug=True) if params.get('con_name'): process.run('nmcli con del %s' % params['con_name'], verbose=True) if add_pkg: process.run("ovs-vsctl del-br %s" % br, verbose=True) utils_package.package_remove(add_pkg)
def run(test, params, env): """ Test interafce xml options. 1.Prepare test environment,destroy or suspend a VM. 2.Edit xml and start the domain. 3.Perform test operation. 4.Recover test environment. 5.Confirm the test result. """ vm_name = params.get("main_vm") vm = env.get_vm(vm_name) if vm.is_alive(): vm.wait_for_login() def create_iface_xml(mac): """ Create interface xml file """ iface = Interface(type_name=iface_type) iface.source = iface_source iface.model = iface_model if iface_model else "virtio" if iface_target: iface.target = {'dev': iface_target} iface.mac_address = mac logging.debug("Create new interface xml: %s", iface) return iface # Interface specific attributes. iface_num = params.get("iface_num", '1') iface_type = params.get("iface_type", "network") iface_source = eval(params.get("iface_source", "{'network':'default'}")) iface_model = params.get("iface_model") iface_target = params.get("iface_target") iface_mac = params.get("iface_mac") attach_device = "yes" == params.get("attach_device", "no") attach_iface = "yes" == params.get("attach_iface", "no") attach_option = params.get("attach_option", "") detach_device = "yes" == params.get("detach_device") stress_test = "yes" == params.get("stress_test") restart_libvirtd = "yes" == params.get("restart_libvirtd", "no") start_vm = "yes" == params.get("start_vm", "yes") options_test = "yes" == params.get("options_test", "no") username = params.get("username") password = params.get("password") poll_timeout = int(params.get("poll_timeout", 10)) err_msgs1 = params.get("err_msgs1") err_msgs2 = params.get("err_msgs2") # stree_test require detach operation stress_test_detach_device = False stress_test_detach_interface = False if stress_test: if attach_device: stress_test_detach_device = True if attach_iface: stress_test_detach_interface = True # The following detach-device step also using attach option detach_option = attach_option # Back up xml file. vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) #iface_mac = vm_xml.VMXML.get_first_mac_by_name(vm_name) libvirtd = utils_libvirtd.Libvirtd() # Check virsh command option check_cmds = [] sep_options = attach_option.split() logging.debug("sep_options: %s" % sep_options) for sep_option in sep_options: if attach_device and sep_option: check_cmds.append(('attach-device', sep_option)) if attach_iface and sep_option: check_cmds.append(('attach-interface', sep_option)) if (detach_device or stress_test_detach_device) and sep_option: check_cmds.append(('detach-device', sep_option)) if stress_test_detach_interface and sep_option: check_cmds.append(('detach-device', sep_option)) for cmd, option in check_cmds: libvirt.virsh_cmd_has_option(cmd, option) try: try: # Attach an interface when vm is running iface_list = [] err_msgs = ("No more available PCI slots", "No more available PCI addresses") if not start_vm: virsh.destroy(vm_name) for i in range(int(iface_num)): if attach_device: logging.info("Try to attach device loop %s" % i) if iface_mac: mac = iface_mac else: mac = utils_net.generate_mac_address_simple() iface_xml_obj = create_iface_xml(mac) iface_xml_obj.xmltreefile.write() ret = virsh.attach_device(vm_name, iface_xml_obj.xml, flagstr=attach_option, ignore_status=True) elif attach_iface: logging.info("Try to attach interface loop %s" % i) mac = utils_net.generate_mac_address_simple() options = ("%s %s --model %s --mac %s %s" % (iface_type, iface_source['network'], iface_model, mac, attach_option)) ret = virsh.attach_interface(vm_name, options, ignore_status=True) if ret.exit_status: if any([msg in ret.stderr for msg in err_msgs]): logging.debug( "No more pci slots, can't attach more devices") break elif (ret.stderr.count("doesn't support option %s" % attach_option)): test.cancel(ret.stderr) elif err_msgs1 in ret.stderr: logging.debug( "option %s is not supported when domain running is %s" % (attach_option, vm.is_alive())) if start_vm or ("--live" not in sep_options and attach_option): test.fail( "return not supported, but it is unexpected") elif err_msgs2 in ret.stderr: logging.debug("options %s are mutually exclusive" % attach_option) if not ("--current" in sep_options and len(sep_options) > 1): test.fail( "return mutualy exclusive, but it is unexpected" ) else: logging.error("Command output %s" % ret.stdout.strip()) test.fail("Failed to attach-interface") elif stress_test: if attach_device: # Detach the device immediately for stress test ret = virsh.detach_device(vm_name, iface_xml_obj.xml, flagstr=detach_option, ignore_status=True) elif attach_iface: # Detach the device immediately for stress test options = ("--type %s --mac %s %s" % (iface_type, mac, detach_option)) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) else: if attach_device: iface_list.append({ 'mac': mac, 'iface_xml': iface_xml_obj }) elif attach_iface: iface_list.append({'mac': mac}) # Restart libvirtd service if restart_libvirtd: libvirtd.restart() # After restart libvirtd, the old console was invalidated, # so we need create a new serial console vm.cleanup_serial_console() vm.create_serial_console() # in options test, check if the interface is attached # in current state when attach return true def check_iface_exist(): try: session = vm.wait_for_serial_login(username=username, password=password) if utils_net.get_linux_ifname(session, iface['mac']): return True else: logging.debug("can not find interface in vm") except Exception: return False if options_test: for iface in iface_list: if 'mac' in iface: # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']) if vm.is_alive() and attach_option == "--config": if if_attr: test.fail("interface should not exists " "in current live vm while " "attached by --config") else: if if_attr: logging.debug("interface %s found current " "state in xml" % if_attr['mac']) else: test.fail("no interface found in " "current state in xml") if if_attr: if if_attr['type'] != iface_type or \ if_attr['source'] != \ iface_source['network']: test.fail("Interface attribute doesn't " "match attachment options") # check interface in vm only when vm is active if vm.is_alive(): logging.debug("check interface in current state " "in vm") if not utils_misc.wait_for(check_iface_exist, timeout=20): if not attach_option == "--config": test.fail("Can't see interface " "in current state in vm") else: logging.debug("find interface in " "current state in vm") else: logging.debug("find interface in " "current state in vm") # in options test, if the attach is performed # when the vm is running # need to destroy and start to check again vm.destroy() # Start the domain if needed if vm.is_dead(): vm.start() session = vm.wait_for_serial_login(username=username, password=password) # check if interface is attached for iface in iface_list: if 'mac' in iface: logging.debug("check interface in xml") # Check interface in dumpxml output if_attr = vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']) logging.debug(if_attr) if if_attr: logging.debug("interface {} is found in xml".format( if_attr['mac'])) if (if_attr['type'] != iface_type or if_attr['source'] != iface_source['network']): test.fail("Interface attribute doesn't " "match attachment options") if options_test and start_vm and attach_option \ in ("--current", "--live", ""): test.fail("interface should not exists when " "restart vm in options_test") else: logging.debug("no interface found in xml") if options_test and start_vm and attach_option in \ ("--current", "--live", ""): logging.debug("interface not exists next state " "in xml with %s" % attach_option) else: test.fail("Can't see interface in dumpxml") # Check interface on guest if not utils_misc.wait_for(check_iface_exist, timeout=20): logging.debug("can't see interface next state in vm") if start_vm and attach_option in \ ("--current", "--live", ""): logging.debug("it is expected") else: test.fail("should find interface " "but no seen in next state in vm") # Detach hot/cold-plugged interface at last if detach_device: for iface in iface_list: if 'iface_xml' in iface: ret = virsh.detach_device(vm_name, iface['iface_xml'].xml, flagstr="", ignore_status=True) libvirt.check_exit_status(ret) else: options = ("%s --mac %s" % (iface_type, iface['mac'])) ret = virsh.detach_interface(vm_name, options, ignore_status=True) libvirt.check_exit_status(ret) # Check if interface was detached for iface in iface_list: if 'mac' in iface: polltime = time.time() + poll_timeout while True: # Check interface in dumpxml output if not vm_xml.VMXML.get_iface_by_mac( vm_name, iface['mac']): break else: time.sleep(2) if time.time() > polltime: test.fail("Interface still " "exists after detachment") session.close() except virt_vm.VMStartError as e: logging.info(str(e)) test.fail('VM failed to start:\n%s' % e) finally: # Recover VM. logging.info("Restoring vm...") if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync()
def run(test, params, env): global flag_list, flag_list_abs, update_sec, without_sec global check_sec, check_without_sec, newxml # Basic network params net_name = params.get("net_update_net_name", "updatenet") net_section = params.get("network_section") update_command = params.get("update_command", "add-last") options = params.get("cmd_options", "") net_state = params.get("net_state") use_in_guest = params.get("use_in_guest") iface_type = params.get("iface_type", "network") ip_version = params.get("ip_version", "ipv4") new_start_ip = params.get("start_ip") new_end_ip = params.get("end_ip") parent_index = params.get("parent_index") status_error = params.get("status_error", "no") # dhcp host test new_dhcp_host_ip = params.get("new_dhcp_host_ip") new_dhcp_host_id = params.get("new_dhcp_host_id") new_dhcp_host_name = params.get("new_dhcp_host_name") new_dhcp_host_mac = params.get("new_dhcp_host_mac") # ipv4 range/host test ipv4_range_start = params.get("ori_ipv4_range_start") ipv4_range_end = params.get("ori_ipv4_range_end") ipv4_host_mac = params.get("ori_ipv4_host_mac") ipv4_host_ip = params.get("ori_ipv4_host_ip") ipv4_host_name = params.get("ori_ipv4_host_name") # ipv6 range/host test ipv6_range_start = params.get("ori_ipv6_range_start") ipv6_range_end = params.get("ori_ipv6_range_end") ipv6_host_id = params.get("ori_ipv6_host_id") ipv6_host_name = params.get("ori_ipv6_host_name") ipv6_host_ip = params.get("ori_ipv6_host_ip") # dns test dns_name = params.get("ori_dns_name") dns_value = params.get("ori_dns_value") new_dns_name = params.get("new_dns_name") new_dns_value = params.get("new_dns_value") # srv test srv_service = params.get("ori_srv_service") srv_protocol = params.get("ori_srv_protocol") srv_domain = params.get("ori_srv_domain") srv_target = params.get("ori_srv_target") srv_port = params.get("ori_srv_port") srv_priority = params.get("ori_srv_priority") srv_weight = params.get("ori_srv_weight") new_srv_service = params.get("new_srv_service") new_srv_protocol = params.get("new_srv_protocol") new_srv_domain = params.get("new_srv_domain") new_srv_target = params.get("new_srv_target") new_srv_port = params.get("new_srv_port") new_srv_priority = params.get("new_srv_priority") new_srv_weight = params.get("new_srv_weight") # dns host test dns_hostip = params.get("ori_dns_hostip") dns_hostname = params.get("ori_dns_hostname") dns_hostname2 = params.get("ori_dns_hostname2") # setting for without part without_ip_dhcp = params.get("without_ip_dhcp", "no") without_dns = params.get("without_dns", "no") without_dns_host = params.get("without_dns_host", "no") without_dns_txt = params.get("without_dns_txt", "no") without_dns_srv = params.get("without_dns_srv", "no") without_dns_forwarder = params.get("without_dns_forwarder", "no") # setting for update/check/without section update_sec = params.get("update_sec") check_sec = params.get("check_sec") without_sec = params.get("without_sec") check_without_sec = params.get("check_without_sec") # forward test forward_mode = params.get("forward_mode") forward_iface = params.get("forward_iface", "eth2") # other params error_type = params.get("error_type", "") vm_name = params.get("main_vm") loop_time = int(params.get("loop_time", 1)) check_config_round = params.get("check_config_round", -1) ipv4_host_id = ipv6_host_mac = "" dns_enable = params.get("dns_enable", "yes") guest_iface_num = int(params.get("guest_iface_num", 1)) newxml = "" def get_hostfile(): """ Get the content of hostfile """ logging.info("Checking network hostfile...") hostfile = "/var/lib/libvirt/dnsmasq/%s.hostsfile" % net_name with open(hostfile) as hostfile_d: hostfile = hostfile_d.readlines() return hostfile def find_config(check_file, need_find): """ Find configure in check_file :param check_file: The file that will check :param need_find: If need to find the item in check_file, Boolean """ def _find_config(check_func): def __find_config(*args, **kwargs): logging.info("Checking content of %s", check_file) ret = False item = None with open(check_file) as checkfile_d: while True: check_line = checkfile_d.readline() if not check_line: break (ret, item) = check_func(check_line, *args, **kwargs) if ret: break if not ret: if need_find: test.fail("Fail to find %s in %s" % (item, check_file)) else: logging.info("Can not find %s in %s as expected" % (item, check_file)) return __find_config return _find_config conf_file = "/var/lib/libvirt/dnsmasq/%s.conf" % net_name @find_config(conf_file, True) def check_item(check_line, item): """ Check if the item in config file """ if item in check_line: logging.info("Find %s in %s", item, conf_file) return (True, item) else: return (False, item) host_file = "/var/lib/libvirt/dnsmasq/%s.addnhosts" % net_name @find_config(host_file, True) def check_host(check_line, item): """ Check if the item in host_file """ if re.search(item, check_line): logging.info("Find %s in %s", item, host_file) return (True, item) else: return (False, item) @find_config(conf_file, False) def check_item_absent(check_line, item): """ Check if the item not in config file """ if item in check_line: test.fail("Find %s in %s" % (item, conf_file)) else: return (False, item) @find_config(host_file, False) def check_host_absent(check_line, item): """ Check if the item not in host_file """ if re.search(item, check_line): test.fail("Find %s in %s" % (item, host_file)) else: return (False, item) def section_update(ori_pre, new_pre): """ Deal with update section and without section in func :param ori_pre: prefix of original section parameter name :param new_pre: prefix of new section parameter name """ global flag_list, flag_list_abs, update_sec, without_sec global check_sec, check_without_sec, newxml if update_sec: for sec in update_sec.split(","): newxml = newxml.replace(names[ori_pre + sec], names[new_pre + sec]) if update_command != "delete": check_sec = update_sec if without_sec: for sec_no in without_sec.split(","): newxml = re.sub(sec_no + "=\".*?\"", "", newxml) if update_command == "modify": check_without_sec = without_sec if check_sec: for c_sec in check_sec.split(","): flag_list.append(names[new_pre + c_sec]) if check_without_sec: for c_sec_no in check_without_sec.split(","): flag_list_abs.append(names[ori_pre + c_sec_no]) dns_host_xml = """ <host ip='%s'> <hostname>%s</hostname> <hostname>%s</hostname> </host> """ % (dns_hostip, dns_hostname, dns_hostname2) virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <domain name="example.com" localOnly="no"/> <mtu size="9000"/> <dns enable='%s'> <forwarder domain='example.com' addr="8.8.4.4"/> <txt name='%s' value='%s'/> <srv service='%s' protocol='%s' domain='%s' target='%s' port='%s' priority='%s' weight='%s'/> %s </dns> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='%s' end='%s' /> <host mac='%s' ip='%s' name='%s' /> </dhcp> </ip> <ip family='ipv6' address='2001:db8:ca2:2::1' prefix='64'> <dhcp> <range start='%s' end='%s'/> <host id='%s' name='%s' ip='%s'/> </dhcp> </ip> <route family='ipv6' address='2001:db8:ca2:2::' prefix='64' gateway='2001:db8:ca2:2::4'/> <ip address='192.168.101.1' netmask='255.255.255.0'/> <ip family='ipv6' address='2001:db8:ca2:3::1' prefix='64' /> </network> """ % (net_name, net_name, dns_enable, dns_name, dns_value, srv_service, srv_protocol, srv_domain, srv_target, srv_port, srv_priority, srv_weight, dns_host_xml, ipv4_range_start, ipv4_range_end, ipv4_host_mac, ipv4_host_ip, ipv4_host_name, ipv6_range_start, ipv6_range_end, ipv6_host_id, ipv6_host_name, ipv6_host_ip) port_group = """ <portgroup name='engineering' default='no'> <virtualport type='802.1Qbh'> <parameters profileid='test'/> </virtualport> <bandwidth> <inbound average='1000' peak='5000' burst='5120'/> <outbound average='1000' peak='5000' burst='5120'/> </bandwidth> </portgroup> """ if use_in_guest == "yes": vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) vmxml_backup = vmxml.copy() backup_files = [] try: for loop in range(loop_time): if loop_time > 1: logging.info("Round %s:", loop + 1) update_command = params.get("update_command").split(",")[loop] if net_section == "ip-dhcp-host": new_dhcp_host_ip = params.get("new_dhcp_host_ip").split( ",")[loop] new_dhcp_host_name = params.get( "new_dhcp_host_name").split(",")[loop] new_dhcp_host_mac = params.get("new_dhcp_host_mac").split( ",")[loop] status_error = params.get("status_error").split(",")[loop] elif net_section == "dns-txt": net_state = params.get("net_state").split(",")[loop] # Get a tmp_dir. tmp_dir = data_dir.get_tmp_dir() # Write new xml into a tempfile tmp_file = tempfile.NamedTemporaryFile(prefix=("new_xml_"), dir=tmp_dir) xmlfile = tmp_file.name tmp_file.close() # Generate testxml test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net names = locals() if net_section == "portgroup": portgroup_xml = network_xml.PortgroupXML() portgroup_xml.xml = port_group test_xml.portgroup = portgroup_xml elif net_section == "forward-interface": if forward_mode == "bridge": forward_iface = utils_net.get_net_if(state="UP")[0] test_xml.forward = {'mode': forward_mode} test_xml.forward_interface = [{'dev': forward_iface}] del test_xml.bridge del test_xml.mac for ip_num in range(4): del test_xml.ip del test_xml.routes del test_xml.dns del test_xml.mtu del test_xml.domain_name section_index = 0 if ip_version == "ipv6": section_index = 1 element = "/%s" % net_section.replace('-', '/') try: section_xml = test_xml.get_section_string(xpath=element, index=section_index) except xcepts.LibvirtXMLNotFoundError: newxml = section_xml = test_xml.get_section_string( xpath="/ip/dhcp/range") newxml = section_xml logging.debug("section xml is %s", newxml) flag_list = [] flag_list_abs = [] if (update_command == "delete" and error_type not in ["host-mismatch", "range-mismatch"] and not without_sec and not update_sec): logging.info("The delete xml is %s", newxml) else: if net_section == "bridge": new_bridge_name = net_name + "_new" flag_list.append(new_bridge_name) newxml = section_xml.replace(net_name, new_bridge_name) logging.info("The new bridge xml is %s", newxml) elif net_section == "forward": new_mode = "route" flag_list.append(new_mode) newxml = section_xml.replace("nat", new_mode) logging.info("The new forward xml is %s", newxml) elif net_section == "ip": new_netmask = "255.255.0.0" flag_list.append(new_netmask) newxml = section_xml.replace("255.255.255.0", new_netmask) elif net_section == "ip-dhcp-range": newxml = section_xml.replace( names[ip_version + "_range_start"], new_start_ip) newxml = newxml.replace(names[ip_version + "_range_end"], new_end_ip) for location in ["end", "start"]: if names["new_" + location + "_ip"] == "": newxml = newxml.replace(location + "=\"\"", "") else: flag_list.append(names["new_" + location + "_ip"]) elif net_section == "portgroup": new_inbound_average = "2000" flag_list.append(new_inbound_average) newxml = section_xml.replace("1000", new_inbound_average) newxml = newxml.replace("default=\"no\"", "default=\"yes\"") flag_list.append("default=('|\")yes") if update_command in ['add-first', 'add-last', 'add']: newxml = newxml.replace("engineering", "sales") flag_list.append("sales") if update_command == "modify" and status_error == "yes": newxml = newxml.replace("engineering", "") elif net_section == "forward-interface": new_forward_iface = params.get("new_forward_iface") if error_type != "interface-duplicate": find_iface = 0 if not new_forward_iface and forward_mode == "bridge": new_iface_list = utils_net.get_net_if( qdisc="(mq|pfifo_fast)", state="(UP|DOWN)", optional="MULTICAST,UP") logging.info("new_iface_list is %s", new_iface_list) for iface in new_iface_list: if iface[0] != forward_iface: new_forward_iface = iface[0] find_iface = 1 break if not find_iface: test.cancel( "Can not find another physical interface to attach" ) else: new_forward_iface = forward_iface flag_list.append(new_forward_iface) newxml = section_xml.replace(forward_iface, new_forward_iface) elif net_section == "ip-dhcp-host": if (update_sec is None and update_command not in ['modify', 'delete']): if ip_version == "ipv4": update_sec = "ip,mac,name" elif ip_version == "ipv6": update_sec = "ip,id,name" section_update(ip_version + "_host_", "new_dhcp_host_") elif net_section == "dns-txt": section_update("dns_", "new_dns_") elif net_section == "dns-srv": section_update("srv_", "new_srv_") elif net_section == "dns-host": if without_sec == "hostname": newxml = re.sub("<hostname>.*</hostname>\n", "", newxml) if status_error == 'no': flag_list.append("ip=.*?" + dns_hostip) flag_list.append(dns_hostname) flag_list.append(dns_hostname2) # for negative test may have net_section do not match issues elif status_error == "no": test.fail("Unknown network section") logging.info("The new xml of %s is %s", net_section, newxml) with open(xmlfile, 'w') as xmlfile_d: xmlfile_d.write(newxml) if without_ip_dhcp == "yes": test_xml.del_element(element="/ip/dhcp") test_xml.del_element(element="/ip/dhcp") if without_dns == "yes": test_xml.del_element(element='/dns') if without_dns_host == "yes": test_xml.del_element(element='/dns/host') if without_dns_txt == "yes": test_xml.del_element(element='/dns/txt') if without_dns_srv == "yes": test_xml.del_element(element='/dns/srv') if without_dns_forwarder == "yes": test_xml.del_element(element='/dns/forwarder') # Only do net define/start in first loop if (net_section == "ip-dhcp-range" and use_in_guest == "yes" and without_ip_dhcp == "no"): test_xml.del_element(element="/ip/dhcp", index=section_index) if error_type == "index-nonexist": for idx in [3, 2, 1]: test_xml.del_element(element="/ip", index=idx) test_xml.del_element(element="/route") if loop == 0: try: # Define and start network test_xml.debug_xml() test_xml.define() ori_net_xml = virsh.net_dumpxml(net_name).stdout.strip() if "ipv6" in ori_net_xml: host_ifaces = utils_net.get_net_if(state="UP") backup_files.append( remote.RemoteFile(address='127.0.0.1', client='scp', username=params.get('username'), password=params.get('password'), port='22', remote_path='/proc/sys/net/ipv6/' 'conf/all/accept_ra')) process.run( "echo 2 > /proc/sys/net/ipv6/conf/all/accept_ra", shell=True) for host_iface in host_ifaces: backup_files.append( remote.RemoteFile( address='127.0.0.1', client='scp', username=params.get('username'), password=params.get('password'), port='22', remote_path='/proc/sys/net/ipv6/' 'conf/%s/accept_ra' % host_iface)) process.run( "echo 2 > /proc/sys/net/ipv6/conf/%s/accept_ra" % host_iface, shell=True) process.run( "cat /proc/sys/net/ipv6/conf/%s/accept_ra" % host_iface) if net_state == "active" or net_state == "transient": test_xml.start() if net_state == "transient": test_xml.del_defined() list_result = virsh.net_list("--all --name").stdout.strip() if net_name not in list_result: test.fail("Can not find %s in net-list" % net_name) except xcepts.LibvirtXMLError as detail: test.error("Failed to define a test network.\n" "Detail: %s." % detail) else: # setting net status for following loops if net_state == "active": test_xml.set_active(True) elif net_state == "inactive": test_xml.set_active(False) # get hostfile before update if without_ip_dhcp == "yes" and net_state == "active": hostfile_before = get_hostfile() if hostfile_before != []: test.fail("hostfile is not empty before update: %s" % hostfile_before) logging.info("hostfile is empty before update") # Get dnsmasq pid before update check_dnsmasq = ((update_command == "add" or update_command == "delete") and net_section == "ip-dhcp-range" and status_error == "no" and net_state == "active" and options != "--config") if check_dnsmasq: cmd = "ps aux|grep dnsmasq|grep -v grep|grep %s|awk '{print $2}'" % net_name pid_list_bef = process.run( cmd, shell=True).stdout_text.strip().split('\n') if parent_index: options += " --parent-index %s" % parent_index # Check config before update if net_state == "active": dns_txt = dns_srv = dns_host_str = None try: dns_txt = test_xml.get_section_string(xpath="/dns/txt") dns_srv = test_xml.get_section_string(xpath="/dns/srv") dns_host_str = test_xml.get_section_string( xpath="/dns/host") except xcepts.LibvirtXMLNotFoundError: pass txt_record = "txt-record=%s,%s" % (dns_name, dns_value) srv_host = "srv-host=_%s._%s.%s,%s,%s,%s,%s" % ( srv_service, srv_protocol, srv_domain, srv_target, srv_port, srv_priority, srv_weight) hostline = "%s.*%s.*%s" % (dns_hostip, dns_hostname, dns_hostname2) if dns_txt: check_item(txt_record) if dns_srv: check_item(srv_host) if dns_host_str: check_host(hostline) # Do net-update operation cmd_result = virsh.net_update(net_name, update_command, net_section, xmlfile, options, debug=True) if cmd_result.exit_status: err = cmd_result.stderr.strip() if status_error == "yes": # index-mismatch error info and judgement index_err1 = "the address family of a host entry IP must match the" + \ " address family of the dhcp element's parent" index_err2 = "XML error: Invalid to specify MAC address.* in network" + \ ".* IPv6 static host definition" index_err3 = "mismatch of address family in range.* for network" mismatch_expect = (error_type == "index-mismatch" and (re.search(index_err1, err) or re.search(index_err2, err) or re.search(index_err3, err))) err_dic = {} # multi-host error info err_dic["multi-hosts"] = "dhcp is supported only for a single.*" + \ " address on each network" # range-mismatch error info err_dic["range-mismatch"] = "couldn't locate a matching dhcp " + \ "range entry in network " # index-nonexist error info err_dic["index-nonexist"] = "couldn't update dhcp host entry " + \ "- no <ip.* element found at index 1 in network" # host-mismatch error info err_dic["host-mismatch"] = "couldn't locate a matching dhcp " + \ "host entry in network " # dns-mismatch error info err_dic["dns-mismatch"] = "couldn't locate a matching DNS TXT " + \ "record in network " # range-duplicate error info err_dic["range-duplicate"] = "there is an existing dhcp range" + \ " entry in network.* that matches" # host-duplicate error info err_dic["host-duplicate"] = "there is an existing dhcp host" + \ " entry in network.* that matches" # out_of_range error info err_dic[ "out-of-range"] = "range.* is not entirely within network" # no end for range error err_dic["range-no-end"] = "Missing 'end' attribute in dhcp " + \ "range for network" # no match item for host modify err err_dic["no-match-item"] = "couldn't locate an existing dhcp" + \ " host entry with.* in network" # no host name and mac for modify err err_dic["host-no-name-mac"] = "Static host definition in IPv4 network" + \ ".* must have mac or name attribute" # no host ip for modify err err_dic["host-no-ip"] = "Missing IP address in static host " + \ "definition for network" # wrong command name err_dic["wrong-command-name"] = "unrecognized command name" # wrong section name err_dic["wrong-section-name"] = "unrecognized section name" # delete with only id err_dic["only-id"] = "At least one of name, mac, or ip attribute must be" + \ " specified for static host definition in network" # options exclusive err_dic[ "opt-exclusive"] = "Options --current and.* are mutually exclusive" # range_reverse error info if ip_version == "ipv4": err_dic["range-reverse"] = "range.* is reversed" elif ip_version == "ipv6": err_dic[ "range-reverse"] = "range.*start larger than end" # --live with inactive net err_dic["invalid-state"] = "network is not running" err_dic[ "transient"] = "cannot change persistent config of a transient network" err_dic["dns-disable"] = "Extra data in disabled network" err_dic[ "modify"] = "cannot be modified, only added or deleted" err_dic["not-support"] = "can't update.*section of network" err_dic["unrecognized"] = "unrecognized section name" err_dic["interface-duplicate"] = "there is an existing interface entry " + \ "in network.* that matches" err_dic[ "XML error"] = "XML error: Missing required name attribute in portgroup" if (error_type in list(err_dic.keys()) and re.search(err_dic[error_type], err) or mismatch_expect): logging.debug("Get expect error: %s", err) else: test.fail("Do not get expect err msg: %s, %s" % (error_type, err_dic)) else: test.fail("Failed to execute net-update command") elif status_error == "yes": test.fail("Expect fail, but succeed") # Get dnsmasq pid after update if check_dnsmasq: pid_list_aft = process.run( cmd, shell=True).stdout_text.strip().split('\n') for pid in pid_list_aft: if pid in pid_list_bef: test.fail("dnsmasq do not updated") # Check the actual xml cmd_result = virsh.net_dumpxml(net_name) actual_net_xml = cmd_result.stdout.strip() new_xml_obj = network_xml.NetworkXML.new_from_net_dumpxml(net_name) logging.info("After net-update, the actual net xml is %s", actual_net_xml) if "ip-dhcp" in net_section: if ip_version == "ipv6": new_xml_obj.del_element(element="/ip", index=0) if ip_version == "ipv4": new_xml_obj.del_element(element="/ip", index=1) config_not_work = ("--config" in options and net_state == "active" and "--live" not in options) if config_not_work: if update_command != "delete": flag_list_abs = flag_list flag_list = [] else: flag_list = flag_list_abs flag_list_abs = [] logging.info("The check list is %s, absent list is %s", flag_list, flag_list_abs) if (update_command == "delete" and status_error == "no" and not config_not_work and loop_time == 1): try: section_str = new_xml_obj.get_section_string(xpath=element) except xcepts.LibvirtXMLNotFoundError: section_str = None logging.info("Can not find section %s in xml after delete", element) if section_str is not None: test.fail("The actual net xml is not expected," "element still exists") elif ("duplicate" not in error_type and error_type != "range-mismatch" and error_type != "host-mismatch" and error_type != "not-support"): # check xml should exists for flag_string in flag_list: logging.info( "checking %s should in xml in positive test," "and absent in negative test", flag_string) if not re.search(flag_string, actual_net_xml): if ((status_error == "no" and update_command != "delete") or (update_command == "delete" and status_error == "yes")): test.fail("The actual net xml failed to update," "or expect delete fail but xml missing" ":%s" % flag_string) else: if ((status_error == "yes" and update_command != "delete") or (status_error == "no" and update_command == "delete" and not config_not_work)): test.fail("Expect test fail, but find xml %s" " actual, or expect delete succeed," "but fail in fact" % flag_string) # check xml should not exists for flag_string_abs in flag_list_abs: logging.info( "checking %s should NOT in xml in positive test," "and exist in negative test", flag_string_abs) if re.search(flag_string_abs, actual_net_xml): if status_error == "no": test.fail("Expect absent in net xml, but exists" "in fact: %s" % flag_string_abs) else: if status_error == "yes": test.fail("Should exists in net xml, but it " "disappeared: %s" % flag_string_abs) # Check if add-last, add-fist works well if (status_error == "no" and not config_not_work and update_command in ["add-last", "add", "add-first"]): if update_command == "add-first": find_index = 0 else: find_index = -1 section_str_aft = new_xml_obj.get_section_string( xpath=element, index=find_index) logging.info( "xpath is %s, find_index is %s, section_str_aft is %s", element, find_index, section_str_aft) for flag_string in flag_list: logging.info("flag_string is %s", flag_string) if not re.search(flag_string, section_str_aft): test.fail("Can not find %s in %s" % (flag_string, section_str_aft)) logging.info("%s %s in right place", update_command, section_str_aft) # Check the positive test result if status_error == "no": # Check the network conf file # live update if ("--live" in options or "--config" not in options) and net_state == "active": if net_section == "ip-dhcp-range" and update_command == "add-first": ip_range = "%s,%s" % (new_start_ip, new_end_ip) if ip_version == "ipv6": ip_range = ip_range + ",64" check_item(ip_range) if "dns" in net_section: if update_command == "delete" and loop == 0: if net_section == "dns-srv": check_item_absent(srv_host) if net_section == "dns-txt": check_item_absent(txt_record) if net_section == "dns-host": check_host_absent(dns_host_str) elif "add" in update_command: if net_section == "dns-srv": for sec in update_sec.split(","): srv_host = srv_host.replace( names["srv_" + sec], names["new_srv_" + sec]) check_item(srv_host) if net_section == "dns-txt": for sec in update_sec.split(","): txt_record = txt_record.replace( names["dns_" + sec], names["new_dns_" + sec]) check_item(txt_record) if net_section == "dns-host": check_host(hostline) # Check the hostfile if (net_section == "ip-dhcp-host" and update_command != "modify" and update_command != "delete"): dic_hostfile = {} for sec in ["ip", "mac", "name", "id"]: if update_sec is not None and sec in update_sec.split( ","): dic_hostfile[sec] = names["new_dhcp_host_" + sec] + "," else: dic_hostfile[sec] = names[ip_version + "_host_" + sec] + "," if sec == "ip" and ip_version == "ipv6": dic_hostfile[sec] = "[" + dic_hostfile[ sec].strip(",") + "]" if without_sec is not None and sec in without_sec.split( ","): dic_hostfile[sec] = "" if ip_version == "ipv4": host_info = (dic_hostfile["mac"] + dic_hostfile["ip"] + dic_hostfile["name"]) if dic_hostfile["mac"] == "": host_info = dic_hostfile[ "name"] + dic_hostfile["ip"] if ip_version == "ipv6": host_info = ("id:" + dic_hostfile["id"] + dic_hostfile["name"] + dic_hostfile["ip"]) hostfile = get_hostfile() host_info_patten = host_info.strip(",") + "\n" if host_info_patten in hostfile: logging.info("host info %s is in hostfile %s", host_info, hostfile) else: test.fail("Can not find %s in host file: %s" % (host_info, hostfile)) # Check the net in guest if use_in_guest == "yes" and loop == 0: # Detach all interfaces of vm first iface_index = 0 mac_list = vm_xml.VMXML.get_iface_dev(vm_name) for mac in mac_list: iface_dict = vm_xml.VMXML.get_iface_by_mac( vm_name, mac) virsh.detach_interface( vm_name, "--type %s --mac %s --config" % (iface_dict.get('type'), mac)) vm.free_mac_address(iface_index) iface_index += 1 # attach new interface to guest for j in range(guest_iface_num): if net_section == "ip-dhcp-host" and new_dhcp_host_mac: mac = new_dhcp_host_mac else: mac = utils_net.generate_mac_address_simple() ret = virsh.attach_interface( vm_name, "--type %s --source %s --mac %s --config" % (iface_type, net_name, mac)) if ret.exit_status: test.fail( "Fail to attach new interface to guest: %s" % ret.stderr.strip()) # The sleep here is to make sure the update make effect time.sleep(2) # Start guest and check ip/mac/hostname... vm.start() logging.debug("vm xml is %s", vm.get_xml()) session = vm.wait_for_serial_login(internal_timeout=60) if "ip-dhcp" in net_section: dhclient_cmd = "(if pgrep dhclient;" \ "then pkill dhclient; sleep 3; fi) " \ "&& dhclient -%s -lf /dev/stdout" % ip_version[-1] leases = session.cmd_output(dhclient_cmd) iface_ip = utils_net.get_guest_ip_addr( session, mac, ip_version=ip_version, timeout=10) if net_section == "ip-dhcp-range": if new_start_ip <= iface_ip <= new_end_ip: logging.info("getting ip %s is in range [%s ~ %s]", iface_ip, new_start_ip, new_end_ip) else: test.fail("getting ip %s not in range [%s ~ %s]" % (iface_ip, new_start_ip, new_end_ip)) if net_section == "ip-dhcp-host": if iface_ip == new_dhcp_host_ip: logging.info("getting ip is same with set: %s", iface_ip) else: test.fail( "getting ip %s is not same with setting %s" % (iface_ip, new_dhcp_host_ip)) hostname = session.cmd_output("hostname -s").strip( '\n') # option host-name "redhatipv4-2" dhcp_hostname = "option host-name \"%s\"" % new_dhcp_host_name.split( '.')[0] if hostname == new_dhcp_host_name.split( '.')[0] or dhcp_hostname in leases: logging.info( "getting hostname same with setting: %s", new_dhcp_host_name.split('.')[0]) else: test.fail("getting hostname %s is not same with " "setting: %s" % (hostname, new_dhcp_host_name)) session.close() # Check network connection for macvtap if (use_in_guest == "yes" and net_section == "forward-interface" and forward_mode == "bridge"): xml_obj_use = network_xml.NetworkXML.new_from_net_dumpxml( net_name) net_conn = int(xml_obj_use.connection) iface_conn = xml_obj_use.get_interface_connection() conn_count = 0 for k in iface_conn: conn_count = conn_count + int(k) logging.info( "net_conn=%s, conn_count=%s, guest_iface_num=%s" % (net_conn, conn_count, guest_iface_num)) if (net_conn != conn_count or (loop == 1 and guest_iface_num != net_conn)): test.fail("Can not get expected connection num: " "net_conn = %s, iface_conn = %s" % (net_conn, conn_count)) #Check --config option after net destroyed if (int(check_config_round) == loop or (loop_time == 1 and "--current" in options and net_state == "active")): test_xml.set_active(False) logging.info("Checking xml after net destroyed") cmd_result = virsh.net_dumpxml(net_name) inactive_xml = cmd_result.stdout.strip() logging.info("inactive_xml is %s", inactive_xml) #Check the inactive xml for check_str in flag_list: if update_command != "delete": if "--config" in options: if not re.search(check_str, inactive_xml): test.fail( "Can not find xml after net destroyed") if "--current" in options: if re.search(check_str, inactive_xml): test.fail( "XML still exists after net destroyed") else: if "--config" in options: if re.search(check_str, inactive_xml): test.fail( "XML still exists after net destroyed") if "--current" in options: if not re.search(check_str, inactive_xml): test.fail( "Can not find xml after net destroyed") logging.info("Check for net inactive PASS") finally: if test_xml.get_active(): test_xml.del_active() if test_xml.get_defined(): test_xml.del_defined() if os.path.exists(xmlfile): os.remove(xmlfile) if use_in_guest == "yes": vm = env.get_vm(vm_name) if vm.is_alive(): vm.destroy(gracefully=False) vmxml_backup.sync() for config_file in backup_files: config_file._reset_file()