def run(test, params, env): net_name = params.get("net_update_net_name", "updatenet") net_section = params.get("network_section", "ip-dhcp-range") update_command = params.get("update_command", "add-last") add_portgroup = "yes" == params.get("add_portgroup", "no") options = params.get("cmd_options", "") net_state = params.get("net_state") virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.100.2' end='192.168.100.254' /> <host mac='52:54:00:5a:a0:8b' ip='192.168.100.152' /> </dhcp> </ip> </network> """ % (net_name, net_name) 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> """ try: test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net if net_section == "portgroup": portgroup_xml = network_xml.PortgroupXML() portgroup_xml.xml = port_group test_xml.portgroup = portgroup_xml elif net_section == "forward-interface": test_xml.forward = {'mode': 'passthrough'} test_xml.forward_interface = [{'dev': 'eth2'}] del test_xml.bridge del test_xml.mac del test_xml.ip test_xml.define() if net_state == "active": test_xml.start() test_xml.debug_xml() virsh.net_dumpxml(net_name) except xcepts.LibvirtXMLError, detail: raise error.TestError("Failed to define a test network.\n" "Detail: %s." % detail)
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 get_info(self, name): infos = {} for line in virsh.net_info(name).stdout.strip().splitlines(): if line.startswith('Name') or line.startswith('UUID'): key, value = line.split() else: key, value = line.split(':', 1) infos[key.lower()] = value.strip() infos['inactive xml'] = virsh.net_dumpxml( name, '--inactive').stdout.splitlines() return infos
def network_validate(net_name, file=None, **virsh_dargs): """ Test for schema network """ if net_name is None: raise error.TestNAError("None network is specified.") # Confirm the network exists. output = virsh.net_list("--all").stdout.strip() if not re.search(net_name, output): raise error.TestNAError("Make sure the network exists!!") cmd_result = virsh.net_dumpxml(net_name, to_file=file) libvirt.check_exit_status(cmd_result)
def new_all_networks_dict(virsh_instance=virsh): """ Return a dictionary of names to NetworkXML instances for all networks @param: virsh: virsh module or instance to use @return: Dictionary of network name to NetworkXML instance """ result = {} # Values should all share virsh property new_netxml = NetworkXML(virsh_instance) networks = new_netxml.virsh.net_state_dict(only_names=True).keys() for net_name in networks: new_copy = new_netxml.copy() new_copy.xml = virsh.net_dumpxml(net_name).stdout.strip() result[net_name] = new_copy return result
if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or net_state[net_name]['persistent']): raise error.TestFail("Found wrong network states" " after restarting libvirtd: %s" % net_state) edit_net_xml() if test_create: # Network become persistent after editing net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): raise error.TestFail("Found wrong network states" " after editing: %s" % net_state) cmd_result = virsh.net_dumpxml(net_name, '--inactive', debug=True) if cmd_result.exit_status: raise error.TestFail("Failed to dump xml of virtual network %s" % net_name) # The xml should contain the match_string match_string = "100.253" xml = cmd_result.stdout.strip() if not re.search(match_string, xml): raise error.TestFail("The xml is not expected") finally: test_xml.orbital_nuclear_strike()
def run(test, params, env): """ Test command: virsh net-edit <network> 1) Define a temp virtual network 2) Execute virsh net-edit to modify it 3) Dump its xml then check it """ def edit_net_xml(edit_cmd, expect_error, **dargs): """ Edit net xml with virsh net-edit :params edit_cmd: The edit cmd to execute :params expect_error: Boolean, expect success or not :params **dargs: The virsh edit's option """ logging.debug("edit_cmd: %s", edit_cmd) readonly = dargs.get("readonly", False) session = aexpect.ShellSession("sudo -s") try: logging.info("Execute virsh net-edit %s", net_name) virsh_cmd = "virsh net-edit %s" % net_name if readonly: virsh_cmd = "virsh -r net-edit %s" % net_name logging.debug("virsh_cmd: %s", virsh_cmd) session.sendline(virsh_cmd) session.sendline(edit_cmd) session.send('\x1b') session.send('ZZ') remote.handle_prompts(session, None, None, r"[\#\$]\s*$") session.close() except (aexpect.ShellError, aexpect.ExpectError, remote.LoginTimeoutError) as details: log = session.get_output() session.close() if not expect_error: test.fail("Failed to do net-edit: %s\n%s" % (details, log)) logging.debug("Expected error: %s" % log) if readonly and "read only" not in log: test.fail("Not expected error") # Gather test parameters net_name = params.get("net_edit_net_name", "editnet") test_create = "yes" == params.get("test_create", "no") virsh_dargs = {'debug': True, 'ignore_status': True} virsh_instance = virsh.VirshPersistent(**virsh_dargs) change_attribute = params.get("attribute", None) old_value = params.get("old_value", None) new_value = params.get("new_value", None) edit_type = params.get("edit_type", "modify") status_error = (params.get("status_error", "no") == "yes") readonly = (params.get("net_edit_readonly", "no") == "yes") # Get all network instance nets = network_xml.NetworkXML.new_all_networks_dict(virsh_instance) # First check if a bridge of this name already exists # Increment suffix integer from 1 then append it to net_name # till there is no name conflict. if net_name in nets: net_name_fmt = net_name + "%d" suffix_num = 1 while ((net_name_fmt % suffix_num) in nets): suffix_num += 1 net_name = net_name_fmt % suffix_num virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.100.2' end='192.168.100.254' /> </dhcp> </ip> </network> """ % (net_name, net_name) try: test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net if test_create: test_xml.create() else: test_xml.define() except xcepts.LibvirtXMLError as detail: test.cancel("Failed to define a test network.\n" "Detail: %s." % detail) # Run test case try: libvirtd = utils_libvirtd.Libvirtd() if change_attribute == "uuid": # if the attribute need to change is uuid, the old uuid should get # from current network, and new uuid can generate by uuidgen new_value = process.run("uuidgen", shell=True).stdout[:-1] old_value = virsh.net_uuid(net_name).stdout.strip() if test_create: # Restart libvirtd and check state libvirtd.restart() net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or net_state[net_name]['persistent']): test.fail("Found wrong network states" " after restarting libvirtd: %s" % net_state) else: libvirtd.restart() net_state = virsh.net_state_dict() if (net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): test.fail("Found wrong network states: %s" % net_state) result = virsh.net_start(net_name) logging.debug("start the persistent network return: %s", result) if edit_type == "modify": edit_cmd = r":%%s/%s=\'%s\'/%s=\'%s\'" % ( change_attribute, old_value, change_attribute, new_value) match_string = "%s=\'%s\'" % (change_attribute, new_value) if edit_type == "delete": match_string = "%s" % change_attribute # Pattern to be more accurate if old_value and change_attribute != 'uuid': match_string = "%s=\'%s\'" % (change_attribute, old_value) else: match_string = old_value edit_cmd = r":/%s/d" % match_string edit_net_xml(edit_cmd, status_error, readonly=readonly) net_state = virsh.net_state_dict() # transient Network become persistent after editing if not status_error and (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): test.fail("Found wrong network states" " after editing: %s" % net_state) cmd_result = virsh.net_dumpxml(net_name, '--inactive', debug=True) if cmd_result.exit_status: test.fail("Failed to dump xml of virtual network %s" % net_name) # The inactive xml should contain the match string xml = cmd_result.stdout.strip() if edit_type == "modify": if not status_error and not re.search(match_string, xml): test.fail("The inactive xml should contain the change '%s'" % match_string) if status_error and re.search(match_string, xml): test.fail("Expect to modify failure but run success") if edit_type == "delete": if not status_error and re.search(match_string, xml): test.fail("The inactive xml should delete the change '%s'" % match_string) if status_error and not re.search(match_string, xml): test.fail("Expect to delete failure but run success") # The active xml should not contain the match string if net_state[net_name]['active']: if not status_error: cmd_result = virsh.net_dumpxml(net_name, debug=True) if cmd_result.exit_status: test.fail( "Failed to dump active xml of virtual network %s" % net_name) xml = cmd_result.stdout.strip() if edit_type == "modify" and re.search(match_string, xml): test.fail( "The active xml should not contain the change '%s'" % match_string) if edit_type == "delete" and not re.search(match_string, xml): test.fail( "The active xml should not delete the change '%s'" % match_string) finally: test_xml.orbital_nuclear_strike()
cmd_result = virsh.net_update(net_name, update_command, net_section, xmlfile, debug=True) if cmd_result.exit_status: err = cmd_result.stderr.strip() if re.search("is not supported", err): raise error.TestNAError("Skip the test: %s" % err) else: raise error.TestFail("Failed to execute " "virsh net-update command") # Check the actual xml cmd_result = virsh.net_dumpxml(net_name) actual_net_xml = cmd_result.stdout.strip() logging.info("After net-update, the actual net xml is %s", actual_net_xml) if update_command == "delete": new_xml_obj = network_xml.NetworkXML.new_from_net_dumpxml(net_name) try: section_str = new_xml_obj.get_section_string(xpath=element) except xcepts.LibvirtXMLNotFoundError: section_str = None if section_str is not None: raise error.TestFail("The actual net xml is not expected," "element still exists") else:
def run_virsh_net_list(test, params, env): """ Test command: virsh net-list. The command returns list of networks. 1.Get all parameters from configuration. 2.Get current network's status(State, Autostart). 3.Do some prepare works for testing. 4.Perform virsh net-list operation. 5.Recover network status. 6.Confirm the result. """ option = params.get("net_list_option", "") extra = params.get("net_list_extra", "") status_error = params.get("status_error", "no") net_name = params.get("net_list_name", "default") persistent = params.get("net_list_persistent", "yes") net_status = params.get("net_list_error", "active") tmp_xml = os.path.join(test.tmpdir, "tmp.xml") net_current_status = "active" autostart_status = "yes" if not virsh.net_state_dict()[net_name]['active']: net_current_status = "inactive" if not virsh.net_state_dict()[net_name]['autostart']: autostart_status = "no" # Create a transient network. try: if persistent == "no": virsh.net_dumpxml(net_name, to_file=tmp_xml, ignore_status=False) if net_current_status == "inactive": virsh.net_destroy(net_name, ignore_status=False) virsh.net_undefine(net_name, ignore_status=False) virsh.net_create(tmp_xml, ignore_status=False) except error.CmdError: raise error.TestFail("Transient network test failed!") # Prepare network's status for testing. if net_status == "active": try: if not virsh.net_state_dict()[net_name]['active']: virsh.net_start(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Active network test failed!") else: try: if virsh.net_state_dict()[net_name]['active']: virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Inactive network test failed!") result = virsh.net_list(option, extra, ignore_status=True) status = result.exit_status output = result.stdout.strip() # Recover network try: if persistent == "no": virsh.net_destroy(net_name, ignore_status=False) virsh.net_define(tmp_xml, ignore_status=False) if net_current_status == "active": virsh.net_start(net_name, ignore_status=False) if autostart_status == "yes": virsh.net_autostart(net_name, ignore_status=False) else: if net_current_status == "active" and net_status == "inactive": virsh.net_start(net_name, ignore_status=False) elif net_current_status == "inactive" and net_status == "active": virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Recover network failed!") # check result if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command") if option == "--inactive": if net_status == "active": if re.search(net_name, output): raise error.TestFail("Found an active network with" " --inactive option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Found no inactive networks with" " --inactive option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive networks" " with --inactive option") elif option == "": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with no" " option") else: if re.search(net_name, output): raise error.TestFail("Found inactive network with" " no option") elif option == "--all": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with" " --all option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Can't find inactive network with" " --all option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive network" " with --all option")
def run(test, params, env): """ Test command: virsh net-list. The command returns list of networks. 1.Get all parameters from configuration. 2.Get current network's status(State, Autostart). 3.Do some prepare works for testing. 4.Perform virsh net-list operation. 5.Recover network status. 6.Confirm the result. """ option = params.get("net_list_option", "") extra = params.get("net_list_extra", "") status_error = params.get("status_error", "no") net_name = params.get("net_list_name", "default") persistent = params.get("net_list_persistent", "yes") net_status = params.get("net_list_error", "active") tmp_xml = os.path.join(test.tmpdir, "tmp.xml") net_current_status = "active" autostart_status = "yes" if not virsh.net_state_dict()[net_name]['active']: net_current_status = "inactive" if not virsh.net_state_dict()[net_name]['autostart']: autostart_status = "no" # acl polkit params uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') 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.") # Create a transient network. try: if persistent == "no": virsh.net_dumpxml(net_name, to_file=tmp_xml, ignore_status=False) if net_current_status == "inactive": virsh.net_destroy(net_name, ignore_status=False) virsh.net_undefine(net_name, ignore_status=False) virsh.net_create(tmp_xml, ignore_status=False) except error.CmdError: raise error.TestFail("Transient network test failed!") # Prepare network's status for testing. if net_status == "active": try: if not virsh.net_state_dict()[net_name]['active']: virsh.net_start(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Active network test failed!") else: try: if virsh.net_state_dict()[net_name]['active']: virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Inactive network test failed!") virsh_dargs = {'ignore_status': True} if params.get('setup_libvirt_polkit') == 'yes': virsh_dargs['unprivileged_user'] = unprivileged_user virsh_dargs['uri'] = uri result = virsh.net_list(option, extra, **virsh_dargs) status = result.exit_status output = result.stdout.strip() # Recover network try: if persistent == "no": virsh.net_destroy(net_name, ignore_status=False) virsh.net_define(tmp_xml, ignore_status=False) if net_current_status == "active": virsh.net_start(net_name, ignore_status=False) if autostart_status == "yes": virsh.net_autostart(net_name, ignore_status=False) else: if net_current_status == "active" and net_status == "inactive": virsh.net_start(net_name, ignore_status=False) elif net_current_status == "inactive" and net_status == "active": virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Recover network failed!") # check result if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command") if option == "--inactive": if net_status == "active": if re.search(net_name, output): raise error.TestFail("Found an active network with" " --inactive option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Found no inactive networks with" " --inactive option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail( "Found transient inactive networks" " with --inactive option") elif option == "": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with no" " option") else: if re.search(net_name, output): raise error.TestFail("Found inactive network with" " no option") elif option == "--all": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with" " --all option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Can't find inactive network with" " --all option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive network" " with --all option")
def run_virsh_net_dumpxml(test, params, env): """ Test command: virsh net-dumpxml. This command can output the network information as an XML dump to stdout. 1.Get all parameters from config file. 2.If test case's network status is inactive, destroy it. 3.Perform virsh net-dumpxml operation. 4.Recover test environment(network status). 5.Confirm the test result. """ status_error = params.get("status_error", "no") net_ref = params.get("net_dumpxml_net_ref") net_name = params.get("net_dumpxml_network", "default") net_status = params.get("net_dumpxml_network_status", "active") xml_flie = params.get("net_dumpxml_xml_file", "default.xml") extra = params.get("net_dumpxml_extra", "") network_xml = os.path.join(test.tmpdir, xml_flie) # Run test case if net_ref == "uuid": net_ref = virsh.net_uuid(net_name).stdout.strip() elif net_ref == "name": net_ref = net_name net_status_current = "active" if not virsh.net_state_dict()[net_name]['active']: net_status_current = "inactive" if not virsh.net_state_dict()[net_name]['persistent']: raise error.TestError("Network is transient!") try: if net_status == "inactive" and net_status_current == "active": status_destroy = virsh.net_destroy(net_name, ignore_status=True).exit_status if status_destroy != 0: raise error.TestError("Network destroied failed!") result = virsh.net_dumpxml(net_ref, extra, network_xml, ignore_status=True) status = result.exit_status err = result.stderr.strip() xml_validate_cmd = "virt-xml-validate %s network" % network_xml valid_s = utils.run(xml_validate_cmd, ignore_status=True).exit_status # Check option valid or not. if extra.find("--") != -1: options = extra.split("--") for option in options: if option.strip() == "": continue if not virsh.has_command_help_match("net-dumpxml", option.strip()): status_error = "yes" break finally: # Recover network if net_status == "inactive" and net_status_current == "active": status_start = virsh.net_start(net_name, ignore_status=True).exit_status if status_start != 0: raise error.TestError("Network started failed!") # Check status_error if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") if err == "": raise error.TestFail("The wrong command has no error outputed!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command!") if valid_s != 0: raise error.TestFail("Command output is invalid!") else: raise error.TestError("The status_error must be 'yes' or 'no'!")
def run(test, params, env): """ Test command: virsh net-list. The command returns list of networks. 1.Get all parameters from configuration. 2.Get current network's status(State, Autostart). 3.Do some prepare works for testing. 4.Perform virsh net-list operation. 5.Recover network status. 6.Confirm the result. """ option = params.get("net_list_option", "") extra = params.get("net_list_extra", "") status_error = params.get("status_error", "no") net_name = params.get("net_list_name", "default") persistent = params.get("net_list_persistent", "yes") net_status = params.get("net_list_error", "active") tmp_xml = os.path.join(test.tmpdir, "tmp.xml") net_current_status = "active" autostart_status = "yes" if not virsh.net_state_dict()[net_name]['active']: net_current_status = "inactive" if not virsh.net_state_dict()[net_name]['autostart']: autostart_status = "no" # acl polkit params uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') 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.") # Create a transient network. try: if persistent == "no": virsh.net_dumpxml(net_name, to_file=tmp_xml, ignore_status=False) if net_current_status == "inactive": virsh.net_destroy(net_name, ignore_status=False) virsh.net_undefine(net_name, ignore_status=False) virsh.net_create(tmp_xml, ignore_status=False) except error.CmdError: raise error.TestFail("Transient network test failed!") # Prepare network's status for testing. if net_status == "active": try: if not virsh.net_state_dict()[net_name]['active']: virsh.net_start(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Active network test failed!") else: try: if virsh.net_state_dict()[net_name]['active']: virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Inactive network test failed!") virsh_dargs = {'ignore_status': True} if params.get('setup_libvirt_polkit') == 'yes': virsh_dargs['unprivileged_user'] = unprivileged_user virsh_dargs['uri'] = uri result = virsh.net_list(option, extra, **virsh_dargs) status = result.exit_status output = result.stdout.strip() # Recover network try: if persistent == "no": virsh.net_destroy(net_name, ignore_status=False) virsh.net_define(tmp_xml, ignore_status=False) if net_current_status == "active": virsh.net_start(net_name, ignore_status=False) if autostart_status == "yes": virsh.net_autostart(net_name, ignore_status=False) else: if net_current_status == "active" and net_status == "inactive": virsh.net_start(net_name, ignore_status=False) elif net_current_status == "inactive" and net_status == "active": virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Recover network failed!") # check result if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command") if option == "--inactive": if net_status == "active": if re.search(net_name, output): raise error.TestFail("Found an active network with" " --inactive option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Found no inactive networks with" " --inactive option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive networks" " with --inactive option") elif option == "": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with no" " option") else: if re.search(net_name, output): raise error.TestFail("Found inactive network with" " no option") elif option == "--all": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with" " --all option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Can't find inactive network with" " --all option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive network" " with --all option")
</dhcp> </ip> </network> """ % (net_name, net_name) try: test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net test_xml.define() except xcepts.LibvirtXMLError, detail: raise error.TestNAError("Failed to define a test network.\n" "Detail: %s." % detail) # Run test case try: edit_net_xml() cmd_result = virsh.net_dumpxml(net_name, debug=True) if cmd_result.exit_status: raise error.TestFail("Failed to dump xml of virtual network %s" % net_name) # The xml should contain the match_string match_string = "100.253" xml = cmd_result.stdout.strip() if not re.search(match_string, xml): raise error.TestFail("The xml is not expected") finally: test_xml.undefine()
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 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)
net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or net_state[net_name]['persistent']): raise error.TestFail("Found wrong network states" " after restarting libvirtd: %s" % net_state) edit_net_xml() if test_create: # Network become persistent after editing net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): raise error.TestFail("Found wrong network states" " after editing: %s" % net_state) cmd_result = virsh.net_dumpxml(net_name, '--inactive', debug=True) if cmd_result.exit_status: raise error.TestFail("Failed to dump xml of virtual network %s" % net_name) # The xml should contain the match_string match_string = "100.253" xml = cmd_result.stdout.strip() if not re.search(match_string, xml): raise error.TestFail("The xml is not expected") finally: test_xml.orbital_nuclear_strike()
def run(test, params, env): """ Since 3.3.0, Coalesce setting is supported. This case is to set coalesce and check for 4 network types and each guest interface type. Only network/bridge guest interface type take effect for setting interface coalesce. For each host network type, guest can use bridge/network interface type to set coalesce except macvtap network type. Execute 'ethtool -c ${interface}|grep "rx-frames"' and anylize the output to check whether coalesce setting take effect or not. For macvtap network type, guest can start but query coalesce will fail. 1. For default host network network definition is below: <network> <name>default</name> <bridge name="virbr0"/> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.2" end="192.168.122.254"/> </dhcp> </ip> </network> This is default network. 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:a7:4d:f7'/> <source bridge='virbr0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: <interface type='network'> <source network='default'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 2. For bridge host network This mode need true bridge in host network. 'nmcli con add type bridge con-name br0 ifname br0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='br0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for bridge br0 'virsh net-define net-br0.xml' 'virsh net-dumpxml net-br0' <network> <name>net-br0</name> <forward mode='bridge'/> <bridge name='br0'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-br0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 3. For openvswitch bridge host network This mode need true openvswitch bridge in host network. 'ovs-vsctl add-br ovsbr0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='ovsbr0'/> <virtualport type='openvswitch'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for openvswitch bridge ovsbr0 'virsh net-define net-ovsbr0.xml' 'virsh net-dumpxml net-ovsbr0' <network> <name>net-ovs0</name> <forward mode='bridge'/> <bridge name='ovsbr0'/> <virtualport type='openvswitch'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-ovs0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 4. For macvtap bridge mode on host network For this mode, first, create one virtual network. Note, should set dev to one ture physical interface. 'virsh net-define net-br-macvtap.xml' 'virsh net-dumpxml net-br-macvtap' <network> <name>net-br-macvtap</name> <forward dev='eno1' mode='bridge'> <interface dev='eno1'/> </forward> </network> Set guest to use this macvtap network and set coalesc <interface type='network'> <mac address='52:54:00:6e:f4:f1'/> <source network='net-br-macvtap'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> Steps in this test: 1. Prepare test environment,destroy or suspend a VM. 2. Prepare network if necessary. 3. Edit guest interface with definite network and set coalesce. 4. Start guest and check whether coalesce setting take effect. 5. Recover network and guest. """ if not libvirt_version.version_compare(3, 3, 0): test.skip("Coalesce setting is only supported by libvirt3.3.0 and above") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def get_first_phy_iface(): """ Get first physical network interface from output of 'ls /sys/class/net' #ls /sys/class/net eno1 lo virbr0 virbr0-nic :return: interface name """ interface = '' lines = process.run('ls /sys/class/net').stdout_text.splitlines() interfaces = lines[0].split() for iface in interfaces: if iface != 'lo' and 'vir' not in iface: interface = iface break if interface == '': test.fail("There is no physical network interface") return interface def modify_iface_xml(): """ Modify interface xml options Two methods to modify domain interfae: 1. modify guest xml, define it 2. attach one interface for running guest :return: 0 for successful negative case test.fail is fail for positive/negative case None for successful positive case """ if hotplug_iface: iface = Interface(iface_type) else: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_type == 'network': iface.type_name = iface_type source = {iface_type: net_name} elif iface_type == 'bridge' and bridge_name: iface.type_name = iface_type source = {iface_type: bridge_name} elif iface_type == 'direct': iface.type_name = iface_type source = {'dev': interface, 'mode': 'bridge'} if source: del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model iface.coalesce = {'max': coalesce_value} if network_type == "ovsbridge" and iface_type == "bridge": iface.virtualport_type = "openvswitch" if not hotplug_iface: vmxml.devices = xml_devices vmxml.xmltreefile.write() try: vmxml.sync() except xcepts.LibvirtXMLError as details: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") else: if not vm.is_alive(): vm.start() # Wait guest boot completely time.sleep(2) try: ret = virsh.attach_device(vm_name, iface.xml, ignore_status=False, debug=True) except process.CmdError as error: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") start_error = "yes" == params.get("start_error", "no") status_error = "yes" == params.get("status_error", "no") # Get coalesce value. expect_coalesce = params.get("expect_coalesce", "") coalesce_value = params.get("coalesce", "15") if expect_coalesce == '': expect_coalesce = coalesce_value # Network specific attributes. network_type = params.get("network_type", "default") net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") # Get guest interface type iface_type = params.get("iface_type", "network") # Whether attach interface hotplug_iface = "yes" == params.get("hotplug_iface", "no") error_info = params.get("error_info", "") # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Build the xml and run test. try: interface = get_first_phy_iface() # Prepare network for specific network type. # Create bridge/ovsbridge for host bridge/ovsbridge network type if network_type == "default" and iface_type == "bridge": bridge_name = "virbr0" elif network_type == "bridge": bridge_name = eval(net_bridge)['name'] bridge = utils_net.Bridge() # Try to add bridge if not exist if bridge_name not in bridge.list_br(): bridge.add_bridge(bridge_name) elif network_type == 'ovsbridge': bridge_name = eval(net_bridge)['name'] # Try to add ovs bridge if not exist if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) if iface_type == "network": # Define virtual network if not exist for 'network' type of guest interface network = NetworkXML() network.name = net_name # Prepare virtual network required parameters params['net_forward'] = "{'mode':'bridge'}" if network_type == "ovsbridge": params['net_virtualport'] = "openvswitch" if network_type == "macvtap": # For bridge type of macvtap network, one true physical interface shold be added # Check whether physical interface has been added into one bridge. if yes, skip macvtap test # If interface already added to a bridge, the output of the nmcli # command will include "connection.slave-type: bridge" out = process.run('nmcli dev show %s' % interface).stdout_text con_l = re.findall(r'GENERAL.CONNECTION:(.+?)\n', out) if not con_l: test.cancel("no connection for the interface") else: con = con_l[0].strip() if "bridge" not in process.run('nmcli con show "%s"' % con).stdout_text: params['forward_iface'] = interface params['net_forward'] = "{'mode':'bridge', 'dev': '%s'}" % interface else: test.cancel("interface %s has been added into one brige, but macvtap" "need also add this interface, so current network can't" "suit macvtap testing" % interface) if not network.exists(): netxml = libvirt.create_net_xml(net_name, params) netxml.define() netxml.start() virsh.net_dumpxml(network.name, debug=True) # Edit the interface xml. # For successful negative case, return 0 to specify PASS result directly ret = modify_iface_xml() if ret == 0: return 0 try: # Get all interface link_before = set(process.run('ls /sys/class/net').stdout_text.splitlines()) # Start the VM. vm.start() if start_error: raise test.fail("VM started unexpectedly") # Get guest virtual network interface link_after = set(process.run('ls /sys/class/net').stdout_text.splitlines()) newinterface = (link_after - link_before).pop() out = process.run('ethtool -c %s' % newinterface, ignore_status=True) if network_type == 'macvtap': # Currently, output coalesce for macvtap is not supported err_msg = "Cannot get device coalesce settings: Operation not supported" std_msg = "Coalesce parameters for %s:" % newinterface if err_msg not in out.stderr_text or std_msg not in out.stdout_text: test.fail("coalesce setting on %s failed." % network_type) else: # Get coalesce value and check it is true if out.exit_status == 0: for line in out.stdout_text.splitlines(): if 'rx-frames:' in line: coalesce = line.split(':')[1].strip() if expect_coalesce != coalesce: test.fail("coalesce setting failed for %s" % network_type) break else: test.fail("coalesce setting on %s failed." % network_type) except virt_vm.VMStartError as details: logging.info(str(details)) if not start_error: test.fail('VM failed to start:\n%s' % details) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery bridge if network_type == "bridge" and bridge_name: if bridge_name in bridge.list_br(): bridge.del_bridge(bridge_name) elif network_type == "ovsbridge" and bridge_name: if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) vmxml_backup.sync()
def make_net_persistent(net_name): logging.debug(virsh.net_dumpxml(net_name).stdout) with open("/tmp/default.xml", "w") as f: f.write(virsh.net_dumpxml(net_name).stdout) virsh.net_define("/tmp/default.xml", ignore_status=False) return None
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 command: virsh net-destroy. The command can forcefully stop a given network. 1.Make sure the network exists. 2.Prepare network status. 3.Perform virsh net-destroy operation. 4.Check if the network has been destroied. 5.Recover network environment. 6.Confirm the test result. """ net_ref = params.get("net_destroy_net_ref") extra = params.get("net_destroy_extra", "") network_name = params.get("net_destroy_network", "default") network_status = params.get("net_destroy_status", "active") status_error = params.get("status_error", "no") net_persistent = "yes" == params.get("net_persistent", "yes") net_cfg_file = params.get("net_cfg_file", "/usr/share/libvirt/networks/default.xml") check_libvirtd = "yes" == params.get("check_libvirtd") vm_defined = "yes" == params.get("vm_defined") check_vm = "yes" == params.get("check_vm") # libvirt acl polkit related params 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.") uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') if unprivileged_user: if unprivileged_user.count('EXAMPLE'): unprivileged_user = '******' output_all = virsh.net_list("--all").stdout.strip() # prepare the network status: active, persistent if not re.search(network_name, output_all): if net_persistent: virsh.net_define(net_cfg_file, ignore_status=False) virsh.net_start(network_name, ignore_status=False) else: virsh.create(net_cfg_file, ignore_status=False) # Backup the current network xml net_xml_bk = os.path.join(data_dir.get_tmp_dir(), "%s.xml" % network_name) virsh.net_dumpxml(network_name, to_file=net_xml_bk) if net_persistent: if not virsh.net_state_dict()[network_name]['persistent']: logging.debug("make the network persistent...") virsh.net_define(net_xml_bk) else: if virsh.net_state_dict()[network_name]['persistent']: virsh.net_undefine(network_name, ignore_status=False) if not virsh.net_state_dict()[network_name]['active']: if network_status == "active": virsh.net_start(network_name, ignore_status=False) else: if network_status == "inactive": logging.debug( "destroy network as we need to test inactive network...") virsh.net_destroy(network_name, ignore_status=False) logging.debug("After prepare: %s" % virsh.net_state_dict()) # Run test case if net_ref == "uuid": net_ref = virsh.net_uuid(network_name).stdout.strip() elif net_ref == "name": net_ref = network_name if check_libvirtd or check_vm: vm_name = params.get("main_vm") if virsh.is_alive(vm_name): virsh.destroy(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) vmxml_backup = vmxml # make sure there is interface with source network as default iface_devices = vmxml.get_devices(device_type="interface") has_default_net = False for iface in iface_devices: source = iface.get_source() if 'network' in source.keys() and source['network'] == 'default': has_default_net = True break elif 'bridge' in source.keys() and source['bridge'] == 'virbr0': has_default_net = True break if not has_default_net: options = "network default --current" virsh.attach_interface(vm_name, options, ignore_status=False) try: if vm_defined: ret = virsh.start(vm_name) else: logging.debug("undefine the vm, then create the vm...") vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) virsh.undefine(vm_name) ret = virsh.create(vmxml.xml) logging.debug(ret.stdout) # check the create or start cmd status utils_test.libvirt.check_exit_status( ret, expect_error=(network_status != 'active')) status = 1 if status_error != 'yes': libvirtd = utils_libvirtd.Libvirtd("virtqemud") daemon_name = libvirtd.service_name pid_before_run = utils_misc.get_pid(daemon_name) ret = virsh.net_destroy(net_ref, extra, uri=uri, debug=True, unprivileged_user=unprivileged_user, ignore_status=True) utils_test.libvirt.check_exit_status(ret, expect_error=False) # check_libvirtd pid no change pid_after_run = utils_misc.get_pid(daemon_name) if pid_after_run != pid_before_run: test.fail("libvirtd crash after destroy network!") status = 1 else: logging.debug( "libvirtd do not crash after destroy network!") status = 0 if check_libvirtd: # destroy vm, check libvirtd pid no change ret = virsh.destroy(vm_name) utils_test.libvirt.check_exit_status(ret, expect_error=False) pid_after_run2 = utils_misc.get_pid(daemon_name) if pid_after_run2 != pid_before_run: test.fail("libvirtd crash after destroy vm!") status = 1 else: logging.debug( "libvirtd do not crash after destroy vm!") status = 0 elif check_vm: # restart libvirtd and check vm is running libvirtd = utils_libvirtd.Libvirtd() libvirtd.restart() if not virsh.is_alive(vm_name): test.fail( "vm shutdown when transient network destroyed then libvirtd restart" ) else: status = 0 finally: if not vm_defined: vmxml_backup.define() vmxml_backup.sync() else: readonly = (params.get("net_destroy_readonly", "no") == "yes") status = virsh.net_destroy(net_ref, extra, uri=uri, readonly=readonly, debug=True, unprivileged_user=unprivileged_user, ignore_status=True).exit_status # Confirm the network has been destroyed. if net_persistent: if virsh.net_state_dict()[network_name]['active']: status = 1 else: output_all = virsh.net_list("--all").stdout.strip() if re.search(network_name, output_all): status = 1 logging.debug( "transient network should not exists after destroy") # Recover network status to system default status try: if network_name not in virsh.net_state_dict(): virsh.net_define(net_xml_bk, ignore_status=False) if not virsh.net_state_dict()[network_name]['active']: virsh.net_start(network_name, ignore_status=False) if not virsh.net_state_dict()[network_name]['persistent']: virsh.net_define(net_xml_bk, ignore_status=False) if not virsh.net_state_dict()[network_name]['autostart']: virsh.net_autostart(network_name, ignore_status=False) except process.CmdError: test.error("Recover network status failed!") # Clean up the backup network xml file if os.path.isfile(net_xml_bk): data_dir.clean_tmp_files() logging.debug("Cleaning up the network backup xml") # Check status_error if status_error == "yes": if status == 0: test.fail("Run successfully with wrong command!") elif status_error == "no": if status != 0: test.fail("Run failed with right command") else: test.error("The status_error must be 'yes' or 'no'!")
def run(test, params, env): """ Test command: virsh net-dumpxml. This command can output the network information as an XML dump to stdout. 1.Get all parameters from config file. 2.If test case's network status is inactive, destroy it. 3.Perform virsh net-dumpxml operation. 4.Recover test environment(network status). 5.Confirm the test result. """ status_error = params.get("status_error", "no") net_ref = params.get("net_dumpxml_net_ref") net_name = params.get("net_dumpxml_network", "default") net_status = params.get("net_dumpxml_network_status", "active") xml_flie = params.get("net_dumpxml_xml_file", "default.xml") extra = params.get("net_dumpxml_extra", "") network_xml = os.path.join(data_dir.get_tmp_dir(), xml_flie) # acl polkit params uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') 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.") # Run test case if net_ref == "uuid": net_ref = virsh.net_uuid(net_name).stdout.strip() elif net_ref == "name": net_ref = net_name net_status_current = "active" if not virsh.net_state_dict()[net_name]['active']: net_status_current = "inactive" if not virsh.net_state_dict()[net_name]['persistent']: test.error("Network is transient!") try: if net_status == "inactive" and net_status_current == "active": status_destroy = virsh.net_destroy(net_name, ignore_status=True).exit_status if status_destroy != 0: test.error("Network destroied failed!") virsh_dargs = {'ignore_status': True} if params.get('setup_libvirt_polkit') == 'yes': virsh_dargs['unprivileged_user'] = unprivileged_user virsh_dargs['uri'] = uri result = virsh.net_dumpxml(net_ref, extra, network_xml, **virsh_dargs) status = result.exit_status err = result.stderr.strip() xml_validate_cmd = "virt-xml-validate %s network" % network_xml valid_s = process.run(xml_validate_cmd, ignore_status=True, shell=True).exit_status # Check option valid or not. if extra.find("--") != -1: options = extra.split("--") for option in options: if option.strip() == "": continue if not virsh.has_command_help_match("net-dumpxml", option.strip()) and\ status_error == "no": test.cancel("The current libvirt version" " doesn't support '%s' option" % option.strip()) finally: # Recover network if net_status == "inactive" and net_status_current == "active": status_start = virsh.net_start(net_name, ignore_status=True).exit_status if status_start != 0: test.error("Network started failed!") # Check status_error if status_error == "yes": if status == 0: test.fail("Run successfully with wrong command!") if err == "": test.fail("The wrong command has no error outputed!") elif status_error == "no": if status != 0: test.fail("Run failed with right command!") if valid_s != 0: test.fail("Command output is invalid!") else: test.error("The status_error must be 'yes' or 'no'!")
net_section, xmlfile, options, debug=True) if cmd_result.exit_status: err = cmd_result.stderr.strip() if re.search("not supported", err): raise error.TestNAError("Skip the test: %s" % err) else: raise error.TestFail("Failed to execute " "virsh net-update command") # Check the actual xml virsh_option = "" if options == "--config": virsh_option = "--inactive" cmd_result = virsh.net_dumpxml(net_name, virsh_option) actual_net_xml = cmd_result.stdout.strip() logging.info("After net-update, the actual net xml is %s", actual_net_xml) if update_command == "delete": new_xml_obj = network_xml.NetworkXML.new_from_net_dumpxml( net_name, extra=virsh_option) try: section_str = new_xml_obj.get_section_string(xpath=element) except xcepts.LibvirtXMLNotFoundError: section_str = None if section_str is not None: raise error.TestFail("The actual net xml is not expected," "element still exists")
def run(test, params, env): """ Since 3.3.0, Coalesce setting is supported. This case is to set coalesce and check for 4 network types and each guest interface type. Only network/bridge guest interface type take effect for setting interface coalesce. For each host network type, guest can use bridge/network interface type to set coalesce except macvtap network type. Execute 'ethtool -c ${interface}|grep "rx-frames"' and anylize the output to check whether coalesce setting take effect or not. For macvtap network type, guest can start but query coalesce will fail. 1. For default host network network definition is below: <network> <name>default</name> <bridge name="virbr0"/> <forward/> <ip address="192.168.122.1" netmask="255.255.255.0"> <dhcp> <range start="192.168.122.2" end="192.168.122.254"/> </dhcp> </ip> </network> This is default network. 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:a7:4d:f7'/> <source bridge='virbr0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: <interface type='network'> <source network='default'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 2. For bridge host network This mode need true bridge in host network. 'nmcli con add type bridge con-name br0 ifname br0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='br0'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for bridge br0 'virsh net-define net-br0.xml' 'virsh net-dumpxml net-br0' <network> <name>net-br0</name> <forward mode='bridge'/> <bridge name='br0'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-br0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 3. For openvswitch bridge host network This mode need true openvswitch bridge in host network. 'ovs-vsctl add-br ovsbr0' 1) guest interface type 'bridge' and set coalesce: <interface type='bridge'> <mac address='52:54:00:8e:f3:6f'/> <source bridge='ovsbr0'/> <virtualport type='openvswitch'/> <target dev='vnet0'/> <model type='virtio'/> <coalesce> <rx> <frames max='64'/> </rx> </coalesce> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </interface> 2) guest interface type 'network' and set coalesce: First, define one virtual network for openvswitch bridge ovsbr0 'virsh net-define net-ovsbr0.xml' 'virsh net-dumpxml net-ovsbr0' <network> <name>net-ovs0</name> <forward mode='bridge'/> <bridge name='ovsbr0'/> <virtualport type='openvswitch'/> </network> Secondly, use this network for guest <interface type='network'> <source network='net-ovs0'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> </interface> 4. For macvtap bridge mode on host network For this mode, first, create one virtual network. Note, should set dev to one ture physical interface. 'virsh net-define net-br-macvtap.xml' 'virsh net-dumpxml net-br-macvtap' <network> <name>net-br-macvtap</name> <forward dev='eno1' mode='bridge'> <interface dev='eno1'/> </forward> </network> Set guest to use this macvtap network and set coalesc <interface type='network'> <mac address='52:54:00:6e:f4:f1'/> <source network='net-br-macvtap'/> <model type='virtio'/> <coalesce> <rx> <frames max='32'/> </rx> </coalesce> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> Steps in this test: 1. Prepare test environment,destroy or suspend a VM. 2. Prepare network if necessary. 3. Edit guest interface with definite network and set coalesce. 4. Start guest and check whether coalesce setting take effect. 5. Recover network and guest. """ if not libvirt_version.version_compare(3, 3, 0): test.skip( "Coalesce setting is only supported by libvirt3.3.0 and above") vm_name = params.get("main_vm") vm = env.get_vm(vm_name) def get_first_phy_iface(): """ Get first physical network interface from output of 'ls /sys/class/net' #ls /sys/class/net eno1 lo virbr0 virbr0-nic :return: interface name """ interface = '' lines = process.run('ls /sys/class/net').stdout_text.splitlines() interfaces = lines[0].split() for iface in interfaces: if iface != 'lo' and 'vir' not in iface: interface = iface break if interface == '': test.fail("There is no physical network interface") return interface def modify_iface_xml(): """ Modify interface xml options Two methods to modify domain interfae: 1. modify guest xml, define it 2. attach one interface for running guest :return: 0 for successful negative case test.fail is fail for positive/negative case None for successful positive case """ if hotplug_iface: iface = Interface(iface_type) else: vmxml = vm_xml.VMXML.new_from_dumpxml(vm_name) xml_devices = vmxml.devices iface_index = xml_devices.index( xml_devices.by_device_tag("interface")[0]) iface = xml_devices[iface_index] if iface_type == 'network': iface.type_name = iface_type source = {iface_type: net_name} elif iface_type == 'bridge' and bridge_name: iface.type_name = iface_type source = {iface_type: bridge_name} elif iface_type == 'direct': iface.type_name = iface_type source = {'dev': interface, 'mode': 'bridge'} if source: del iface.source iface.source = source iface_model = params.get("iface_model", "virtio") iface.model = iface_model iface.coalesce = {'max': coalesce_value} if network_type == "ovsbridge" and iface_type == "bridge": iface.virtualport_type = "openvswitch" if not hotplug_iface: vmxml.devices = xml_devices vmxml.xmltreefile.write() try: vmxml.sync() except xcepts.LibvirtXMLError as details: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") else: if not vm.is_alive(): vm.start() # Wait guest boot completely time.sleep(2) try: ret = virsh.attach_device(vm_name, iface.xml, ignore_status=False, debug=True) except process.CmdError as error: if status_error: # Expect error for negetive test return 0 else: test.fail("Define guest: FAIL") start_error = "yes" == params.get("start_error", "no") status_error = "yes" == params.get("status_error", "no") # Get coalesce value. expect_coalesce = params.get("expect_coalesce", "") coalesce_value = params.get("coalesce", "15") if expect_coalesce == '': expect_coalesce = coalesce_value # Network specific attributes. network_type = params.get("network_type", "default") net_name = params.get("net_name", "default") net_bridge = params.get("net_bridge", "{'name':'virbr0'}") # Get guest interface type iface_type = params.get("iface_type", "network") # Whether attach interface hotplug_iface = "yes" == params.get("hotplug_iface", "no") error_info = params.get("error_info", "") # Destroy the guest first if vm.is_alive(): vm.destroy(gracefully=False) # Back up xml file. netxml_backup = NetworkXML.new_from_net_dumpxml("default") vmxml_backup = vm_xml.VMXML.new_from_inactive_dumpxml(vm_name) # Build the xml and run test. try: interface = get_first_phy_iface() # Prepare network for specific network type. # Create bridge/ovsbridge for host bridge/ovsbridge network type if network_type == "default" and iface_type == "bridge": bridge_name = "virbr0" elif network_type == "bridge": bridge_name = eval(net_bridge)['name'] bridge = utils_net.Bridge() # Try to add bridge if not exist if bridge_name not in bridge.list_br(): bridge.add_bridge(bridge_name) elif network_type == 'ovsbridge': bridge_name = eval(net_bridge)['name'] # Try to add ovs bridge if not exist if not utils_net.ovs_br_exists(bridge_name): utils_net.add_ovs_bridge(bridge_name) if iface_type == "network": # Define virtual network if not exist for 'network' type of guest interface network = NetworkXML() network.name = net_name # Prepare virtual network required parameters params['net_forward'] = "{'mode':'bridge'}" if network_type == "ovsbridge": params['net_virtualport'] = "openvswitch" if network_type == "macvtap": # For bridge type of macvtap network, one true physical interface shold be added # Check whether physical interface has been added into one bridge. if yes, skip macvtap test # If interface already added to a bridge, the output of the nmcli # command will include "connection.slave-type: bridge" out = process.run('nmcli dev show %s' % interface).stdout_text con_l = re.findall(r'GENERAL.CONNECTION:(.+?)\n', out) if not con_l: test.cancel("no connection for the interface") else: con = con_l[0].strip() if "bridge" not in process.run('nmcli con show "%s"' % con).stdout_text: params['forward_iface'] = interface params[ 'net_forward'] = "{'mode':'bridge', 'dev': '%s'}" % interface else: test.cancel( "interface %s has been added into one brige, but macvtap" "need also add this interface, so current network can't" "suit macvtap testing" % interface) if not network.exists(): netxml = libvirt.create_net_xml(net_name, params) netxml.define() netxml.start() virsh.net_dumpxml(network.name, debug=True) # Edit the interface xml. # For successful negative case, return 0 to specify PASS result directly ret = modify_iface_xml() if ret == 0: return 0 try: # Get all interface link_before = set( process.run('ls /sys/class/net').stdout_text.splitlines()) # Start the VM. vm.start() if start_error: raise test.fail("VM started unexpectedly") # Get guest virtual network interface link_after = set( process.run('ls /sys/class/net').stdout_text.splitlines()) newinterface = (link_after - link_before).pop() out = process.run('ethtool -c %s' % newinterface, ignore_status=True) if network_type == 'macvtap': # Currently, output coalesce for macvtap is not supported err_msg = "Cannot get device coalesce settings: Operation not supported" std_msg = "Coalesce parameters for %s:" % newinterface if err_msg not in out.stderr_text or std_msg not in out.stdout_text: test.fail("coalesce setting on %s failed." % network_type) else: # Get coalesce value and check it is true if out.exit_status == 0: for line in out.stdout_text.splitlines(): if 'rx-frames:' in line: coalesce = line.split(':')[1].strip() if expect_coalesce != coalesce: test.fail("coalesce setting failed for %s" % network_type) break else: test.fail("coalesce setting on %s failed." % network_type) except virt_vm.VMStartError as details: logging.info(str(details)) if not start_error: test.fail('VM failed to start:\n%s' % details) finally: # Recover VM. if vm.is_alive(): vm.destroy(gracefully=False) logging.info("Restoring network...") if net_name == "default": netxml_backup.sync() else: # Destroy and undefine new created network virsh.net_destroy(net_name) virsh.net_undefine(net_name) # Try to recovery bridge if network_type == "bridge" and bridge_name: if bridge_name in bridge.list_br(): bridge.del_bridge(bridge_name) elif network_type == "ovsbridge" and bridge_name: if utils_net.ovs_br_exists(bridge_name): utils_net.del_ovs_bridge(bridge_name) vmxml_backup.sync()
def run(test, params, env): """ Test command: virsh net-dumpxml. This command can output the network information as an XML dump to stdout. 1.Get all parameters from config file. 2.If test case's network status is inactive, destroy it. 3.Perform virsh net-dumpxml operation. 4.Recover test environment(network status). 5.Confirm the test result. """ status_error = params.get("status_error", "no") net_ref = params.get("net_dumpxml_net_ref") net_name = params.get("net_dumpxml_network", "default") net_status = params.get("net_dumpxml_network_status", "active") xml_flie = params.get("net_dumpxml_xml_file", "default.xml") extra = params.get("net_dumpxml_extra", "") network_xml = os.path.join(test.tmpdir, xml_flie) # acl polkit params uri = params.get("virsh_uri") unprivileged_user = params.get('unprivileged_user') 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.") # Run test case if net_ref == "uuid": net_ref = virsh.net_uuid(net_name).stdout.strip() elif net_ref == "name": net_ref = net_name net_status_current = "active" if not virsh.net_state_dict()[net_name]['active']: net_status_current = "inactive" if not virsh.net_state_dict()[net_name]['persistent']: test.error("Network is transient!") try: if net_status == "inactive" and net_status_current == "active": status_destroy = virsh.net_destroy(net_name, ignore_status=True).exit_status if status_destroy != 0: test.error("Network destroied failed!") virsh_dargs = {'ignore_status': True} if params.get('setup_libvirt_polkit') == 'yes': virsh_dargs['unprivileged_user'] = unprivileged_user virsh_dargs['uri'] = uri result = virsh.net_dumpxml(net_ref, extra, network_xml, **virsh_dargs) status = result.exit_status err = result.stderr.strip() xml_validate_cmd = "virt-xml-validate %s network" % network_xml valid_s = process.run(xml_validate_cmd, ignore_status=True, shell=True).exit_status # Check option valid or not. if extra.find("--") != -1: options = extra.split("--") for option in options: if option.strip() == "": continue if not virsh.has_command_help_match("net-dumpxml", option.strip()) and\ status_error == "no": test.cancel("The current libvirt version" " doesn't support '%s' option" % option.strip()) finally: # Recover network if net_status == "inactive" and net_status_current == "active": status_start = virsh.net_start(net_name, ignore_status=True).exit_status if status_start != 0: test.error("Network started failed!") # Check status_error if status_error == "yes": if status == 0: test.fail("Run successfully with wrong command!") if err == "": test.fail("The wrong command has no error outputed!") elif status_error == "no": if status != 0: test.fail("Run failed with right command!") if valid_s != 0: test.fail("Command output is invalid!") else: test.error("The status_error must be 'yes' or 'no'!")
def run_virsh_net_list(test, params, env): """ Test command: virsh net-list. The command returns list of networks. 1.Get all parameters from configuration. 2.Get current network's status(State, Autostart). 3.Do some prepare works for testing. 4.Perform virsh net-list operation. 5.Recover network status. 6.Confirm the result. """ option = params.get("net_list_option", "") extra = params.get("net_list_extra", "") status_error = params.get("status_error", "no") net_name = params.get("net_list_name", "default") persistent = params.get("net_list_persistent", "yes") net_status = params.get("net_list_error", "active") tmp_xml = os.path.join(test.tmpdir, "tmp.xml") net_current_status = "active" autostart_status = "yes" if not virsh.net_state_dict()[net_name]["active"]: net_current_status = "inactive" if not virsh.net_state_dict()[net_name]["autostart"]: autostart_status = "no" # Create a transient network. try: if persistent == "no": virsh.net_dumpxml(net_name, to_file=tmp_xml, ignore_status=False) if net_current_status == "inactive": virsh.net_destroy(net_name, ignore_status=False) virsh.net_undefine(net_name, ignore_status=False) virsh.net_create(tmp_xml, ignore_status=False) except error.CmdError: raise error.TestFail("Transient network test failed!") # Prepare network's status for testing. if net_status == "active": try: if not virsh.net_state_dict()[net_name]["active"]: virsh.net_start(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Active network test failed!") else: try: if virsh.net_state_dict()[net_name]["active"]: virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Inactive network test failed!") result = virsh.net_list(option, extra, ignore_status=True) status = result.exit_status output = result.stdout.strip() # Recover network try: if persistent == "no": virsh.net_destroy(net_name, ignore_status=False) virsh.net_define(tmp_xml, ignore_status=False) if net_current_status == "active": virsh.net_start(net_name, ignore_status=False) if autostart_status == "yes": virsh.net_autostart(net_name, ignore_status=False) else: if net_current_status == "active" and net_status == "inactive": virsh.net_start(net_name, ignore_status=False) elif net_current_status == "inactive" and net_status == "active": virsh.net_destroy(net_name, ignore_status=False) except error.CmdError: raise error.TestFail("Recover network failed!") # check result if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command") if option == "--inactive": if net_status == "active": if re.search(net_name, output): raise error.TestFail("Found an active network with" " --inactive option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Found no inactive networks with" " --inactive option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive networks" " with --inactive option") elif option == "": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with no" " option") else: if re.search(net_name, output): raise error.TestFail("Found inactive network with" " no option") elif option == "--all": if net_status == "active": if not re.search(net_name, output): raise error.TestFail("Can't find active network with" " --all option") else: if persistent == "yes": if not re.search(net_name, output): raise error.TestFail("Can't find inactive network with" " --all option") else: # If network is transient, after net-destroy it, # it will disapear. if re.search(net_name, output): raise error.TestFail("Found transient inactive network" " with --all option")
def run(test, params, env): """ Test command: virsh net-edit <network> 1) Define a temp virtual network 2) Execute virsh net-edit to modify it 3) Dump its xml then check it """ def edit_net_xml(): edit_cmd = r":%s /100.254/100.253" session = aexpect.ShellSession("sudo -s") try: logging.info("Execute virsh net-edit %s", net_name) session.sendline("virsh net-edit %s" % net_name) logging.info("Change the ip value of dhcp end") session.sendline(edit_cmd) session.send('\x1b') session.send('ZZ') remote.handle_prompts(session, None, None, r"[\#\$]\s*$") session.close() except (aexpect.ShellError, aexpect.ExpectError) as details: log = session.get_output() session.close() test.fail("Failed to do net-edit: %s\n%s" % (details, log)) # Gather test parameters net_name = params.get("net_edit_net_name", "editnet") test_create = "yes" == params.get("test_create", "no") virsh_dargs = {'debug': True, 'ignore_status': True} virsh_instance = virsh.VirshPersistent(**virsh_dargs) # Get all network instance nets = network_xml.NetworkXML.new_all_networks_dict(virsh_instance) # First check if a bridge of this name already exists # Increment suffix integer from 1 then append it to net_name # till there is no name conflict. if net_name in nets: net_name_fmt = net_name + "%d" suffix_num = 1 while ((net_name_fmt % suffix_num) in nets): suffix_num += 1 net_name = net_name_fmt % suffix_num virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.100.2' end='192.168.100.254' /> </dhcp> </ip> </network> """ % (net_name, net_name) try: test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net if test_create: test_xml.create() else: test_xml.define() except xcepts.LibvirtXMLError as detail: test.cancel("Failed to define a test network.\n" "Detail: %s." % detail) # Run test case try: libvirtd = utils_libvirtd.Libvirtd() if test_create: # Restart libvirtd and check state libvirtd.restart() net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or net_state[net_name]['persistent']): test.fail("Found wrong network states" " after restarting libvirtd: %s" % net_state) else: libvirtd.restart() net_state = virsh.net_state_dict() if (net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): test.fail("Found wrong network states: %s" % net_state) virsh.net_start(net_name) edit_net_xml() if test_create: # Network become persistent after editing net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): test.fail("Found wrong network states" " after editing: %s" % net_state) cmd_result = virsh.net_dumpxml(net_name, '--inactive', debug=True) if cmd_result.exit_status: test.fail("Failed to dump xml of virtual network %s" % net_name) # The xml should contain the match_string match_string = "100.253" xml = cmd_result.stdout.strip() if not re.search(match_string, xml): test.fail("The xml is not expected") # The active xml should not contain the match_string cmd_result = virsh.net_dumpxml(net_name, debug=True) if cmd_result.exit_status: test.fail("Failed to dump active xml of virtual network %s" % net_name) # The xml should contain the match_string match_string = "100.253" xml = cmd_result.stdout.strip() if re.search(match_string, xml): test.fail("The active xml should not change") finally: test_xml.orbital_nuclear_strike()
def run(test, params, env): net_name = params.get("net_update_net_name", "updatenet") net_section = params.get("network_section", "ip-dhcp-range") update_command = params.get("update_command", "add-last") options = params.get("cmd_options", "") net_state = params.get("net_state") virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.100.2' end='192.168.100.254' /> <host mac='52:54:00:5a:a0:8b' ip='192.168.100.152' /> </dhcp> </ip> </network> """ % (net_name, net_name) 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> """ try: test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net if net_section == "portgroup": portgroup_xml = network_xml.PortgroupXML() portgroup_xml.xml = port_group test_xml.portgroup = portgroup_xml elif net_section == "forward-interface": test_xml.forward = {'mode': 'passthrough'} test_xml.forward_interface = [{'dev': 'eth2'}] del test_xml.bridge del test_xml.mac del test_xml.ip test_xml.define() if net_state == "active": test_xml.start() test_xml.debug_xml() virsh.net_dumpxml(net_name) except xcepts.LibvirtXMLError as detail: test.error("Failed to define a test network.\n" "Detail: %s." % detail) try: # 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() element = "/%s" % net_section.replace('-', '/') section_xml = test_xml.get_section_string(xpath=element) flag_list = [] if update_command == "delete": newxml = section_xml 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) logging.info("The new xml of ip section is %s", newxml) elif net_section == "ip-dhcp-range": new_end_ip = "192.168.100.253" flag_list.append(new_end_ip) newxml = section_xml.replace("192.168.100.254", new_end_ip) logging.info("The new xml of ip-dhcp-range is %s", newxml) 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("no", "yes") flag_list.append("yes") if update_command in ['add-first', 'add-last']: newxml = newxml.replace("engineering", "sales") flag_list.append("sales") logging.info("The new xml of portgroup is %s", newxml) elif net_section == "forward-interface": new_forward_iface = params.get("new_forward_iface", "eth4") flag_list.append(new_forward_iface) newxml = section_xml.replace("eth2", new_forward_iface) logging.info("The new xml of forward-interface is %s", newxml) elif net_section == "ip-dhcp-host": new_ip_dhcp_host = params.get("new_ip_dhcp_host", "192.168.100.153") flag_list.append(new_ip_dhcp_host) newxml = section_xml.replace("192.168.100.152", new_ip_dhcp_host) if update_command in ['add-first', 'add-last']: new_ip_dhcp_mac = params.get("new_ip_dhcp_mac", "52:54:00:5a:a0:9b") newxml = newxml.replace("52:54:00:5a:a0:8b", new_ip_dhcp_mac) flag_list.append(new_ip_dhcp_mac) logging.info("The new xml of forward-interface is %s", newxml) else: test.fail("Unknown network section") fd = open(xmlfile, 'w') fd.write(newxml) fd.close() 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) else: test.fail("Failed to execute " "virsh net-update command") # Check the actual xml virsh_option = "" if options == "--config": virsh_option = "--inactive" cmd_result = virsh.net_dumpxml(net_name, virsh_option) actual_net_xml = cmd_result.stdout.strip() logging.info("After net-update, the actual net xml is %s", actual_net_xml) if update_command == "delete": new_xml_obj = network_xml.NetworkXML.new_from_net_dumpxml( net_name, extra=virsh_option) try: section_str = new_xml_obj.get_section_string(xpath=element) except xcepts.LibvirtXMLNotFoundError: section_str = None if section_str is not None: test.fail("The actual net xml is not expected," "element still exists") else: for flag_string in flag_list: if not re.search(flag_string, actual_net_xml): test.fail("The actual net xml failed to update") finally: test_xml.undefine() if os.path.exists(xmlfile): os.remove(xmlfile)
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") 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 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 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[ "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" 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 = 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" 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() 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 command: virsh net-dumpxml. This command can output the network information as an XML dump to stdout. 1.Get all parameters from config file. 2.If test case's network status is inactive, destroy it. 3.Perform virsh net-dumpxml operation. 4.Recover test environment(network status). 5.Confirm the test result. """ status_error = params.get("status_error", "no") net_ref = params.get("net_dumpxml_net_ref") net_name = params.get("net_dumpxml_network", "default") net_status = params.get("net_dumpxml_network_status", "active") xml_flie = params.get("net_dumpxml_xml_file", "default.xml") extra = params.get("net_dumpxml_extra", "") network_xml = os.path.join(test.tmpdir, xml_flie) # Run test case if net_ref == "uuid": net_ref = virsh.net_uuid(net_name).stdout.strip() elif net_ref == "name": net_ref = net_name net_status_current = "active" if not virsh.net_state_dict()[net_name]['active']: net_status_current = "inactive" if not virsh.net_state_dict()[net_name]['persistent']: raise error.TestError("Network is transient!") try: if net_status == "inactive" and net_status_current == "active": status_destroy = virsh.net_destroy(net_name, ignore_status=True).exit_status if status_destroy != 0: raise error.TestError("Network destroied failed!") result = virsh.net_dumpxml(net_ref, extra, network_xml, ignore_status=True) status = result.exit_status err = result.stderr.strip() xml_validate_cmd = "virt-xml-validate %s network" % network_xml valid_s = utils.run(xml_validate_cmd, ignore_status=True).exit_status # Check option valid or not. if extra.find("--") != -1: options = extra.split("--") for option in options: if option.strip() == "": continue if not virsh.has_command_help_match("net-dumpxml", option.strip()): status_error = "yes" break finally: # Recover network if net_status == "inactive" and net_status_current == "active": status_start = virsh.net_start(net_name, ignore_status=True).exit_status if status_start != 0: raise error.TestError("Network started failed!") # Check status_error if status_error == "yes": if status == 0: raise error.TestFail("Run successfully with wrong command!") if err == "": raise error.TestFail("The wrong command has no error outputed!") elif status_error == "no": if status != 0: raise error.TestFail("Run failed with right command!") if valid_s != 0: raise error.TestFail("Command output is invalid!") else: raise error.TestError("The status_error must be 'yes' or 'no'!")
def run(test, params, env): """ Test command: virsh net-edit <network> 1) Define a temp virtual network 2) Execute virsh net-edit to modify it 3) Dump its xml then check it """ def edit_net_xml(edit_cmd, expect_error, **dargs): """ Edit net xml with virsh net-edit :params edit_cmd: The edit cmd to execute :params expect_error: Boolen, expect success or not :params **dargs: The virsh edit's option """ logging.debug("edit_cmd: %s", edit_cmd) readonly = dargs.get("readonly", False) session = aexpect.ShellSession("sudo -s") try: logging.info("Execute virsh net-edit %s", net_name) virsh_cmd = "virsh net-edit %s" % net_name if readonly: virsh_cmd = "virsh -r net-edit %s" % net_name logging.debug("virsh_cmd: %s", virsh_cmd) session.sendline(virsh_cmd) session.sendline(edit_cmd) session.send('\x1b') session.send('ZZ') remote.handle_prompts(session, None, None, r"[\#\$]\s*$") session.close() except (aexpect.ShellError, aexpect.ExpectError, remote.LoginTimeoutError) as details: log = session.get_output() session.close() if not expect_error: test.fail("Failed to do net-edit: %s\n%s" % (details, log)) logging.debug("Expected error: %s" % log) if readonly and "read only" not in log: test.fail("Not expected error") # Gather test parameters net_name = params.get("net_edit_net_name", "editnet") test_create = "yes" == params.get("test_create", "no") virsh_dargs = {'debug': True, 'ignore_status': True} virsh_instance = virsh.VirshPersistent(**virsh_dargs) change_attribute = params.get("attribute", None) old_value = params.get("old_value", None) new_value = params.get("new_value", None) edit_type = params.get("edit_type", "modify") status_error = (params.get("status_error", "no") == "yes") readonly = (params.get("net_edit_readonly", "no") == "yes") # Get all network instance nets = network_xml.NetworkXML.new_all_networks_dict(virsh_instance) # First check if a bridge of this name already exists # Increment suffix integer from 1 then append it to net_name # till there is no name conflict. if net_name in nets: net_name_fmt = net_name + "%d" suffix_num = 1 while ((net_name_fmt % suffix_num) in nets): suffix_num += 1 net_name = net_name_fmt % suffix_num virtual_net = """ <network> <name>%s</name> <forward mode='nat'/> <bridge name='%s' stp='on' delay='0' /> <mac address='52:54:00:03:78:6c'/> <ip address='192.168.100.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.100.2' end='192.168.100.254' /> </dhcp> </ip> </network> """ % (net_name, net_name) try: test_xml = network_xml.NetworkXML(network_name=net_name) test_xml.xml = virtual_net if test_create: test_xml.create() else: test_xml.define() except xcepts.LibvirtXMLError as detail: test.cancel("Failed to define a test network.\n" "Detail: %s." % detail) # Run test case try: libvirtd = utils_libvirtd.Libvirtd() if change_attribute == "uuid": # if the attribute need to change is uuid, the old uuid should get # from current network, and new uuid can generate by uuidgen new_value = process.run("uuidgen", shell=True).stdout[:-1] old_value = virsh.net_uuid(net_name).stdout.strip() if test_create: # Restart libvirtd and check state libvirtd.restart() net_state = virsh.net_state_dict() if (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or net_state[net_name]['persistent']): test.fail("Found wrong network states" " after restarting libvirtd: %s" % net_state) else: libvirtd.restart() net_state = virsh.net_state_dict() if (net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): test.fail("Found wrong network states: %s" % net_state) result = virsh.net_start(net_name) logging.debug("start the persistent network return: %s", result) if edit_type == "modify": edit_cmd = r":%%s/%s=\'%s\'/%s=\'%s\'" % (change_attribute, old_value, change_attribute, new_value) match_string = "%s=\'%s\'" % (change_attribute, new_value) if edit_type == "delete": match_string = "%s" % change_attribute # Pattern to be more accurate if old_value and change_attribute != 'uuid': match_string = "%s=\'%s\'" % (change_attribute, old_value) else: match_string = old_value edit_cmd = r":/%s/d" % match_string edit_net_xml(edit_cmd, status_error, readonly=readonly) net_state = virsh.net_state_dict() # transient Network become persistent after editing if not status_error and (not net_state[net_name]['active'] or net_state[net_name]['autostart'] or not net_state[net_name]['persistent']): test.fail("Found wrong network states" " after editing: %s" % net_state) cmd_result = virsh.net_dumpxml(net_name, '--inactive', debug=True) if cmd_result.exit_status: test.fail("Failed to dump xml of virtual network %s" % net_name) # The inactive xml should contain the match string xml = cmd_result.stdout.strip() if edit_type == "modify": if not status_error and not re.search(match_string, xml): test.fail("The inactive xml should contain the change '%s'" % match_string) if status_error and re.search(match_string, xml): test.fail("Expect to modify failure but run success") if edit_type == "delete": if not status_error and re.search(match_string, xml): test.fail("The inactive xml should delete the change '%s'" % match_string) if status_error and not re.search(match_string, xml): test.fail("Expect to delete failure but run success") # The active xml should not contain the match string if net_state[net_name]['active']: if not status_error: cmd_result = virsh.net_dumpxml(net_name, debug=True) if cmd_result.exit_status: test.fail("Failed to dump active xml of virtual network %s" % net_name) xml = cmd_result.stdout.strip() if edit_type == "modify" and re.search(match_string, xml): test.fail("The active xml should not contain the change '%s'" % match_string) if edit_type == "delete" and not re.search(match_string, xml): test.fail("The active xml should not delete the change '%s'" % match_string) finally: test_xml.orbital_nuclear_strike()