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 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()