From 707e54d02fde9cee2e5ad83e674d34446e362f0e Mon Sep 17 00:00:00 2001 From: Haijiao Zhao Date: Mon, 27 Jun 2022 11:56:02 +0800 Subject: [PATCH] Update class of NetworkXMLBase and add unittest - Update implementation of ips and portgroups - Modify code of references - Add unittest of network xml Signed-off-by: Haijiao Zhao --- selftests/unit/test_libvirt_xml.py | 4 +- virttest/libvirt_xml/network_xml.py | 102 ++++++++++------- virttest/libvirt_xml/vm_xml.py | 3 +- .../unittests/libvirt_xml/test_network_xml.py | 104 ++++++++++++++++++ virttest/utils_libvirt/libvirt_network.py | 2 +- virttest/utils_test/libvirt.py | 14 ++- 6 files changed, 178 insertions(+), 51 deletions(-) create mode 100644 virttest/unittests/libvirt_xml/test_network_xml.py diff --git a/selftests/unit/test_libvirt_xml.py b/selftests/unit/test_libvirt_xml.py index 2601534f29..59cf2e0bd5 100644 --- a/selftests/unit/test_libvirt_xml.py +++ b/selftests/unit/test_libvirt_xml.py @@ -729,7 +729,7 @@ def _from_scratch(self): ipxml = network_xml.IPXML() ipxml.address = ('address_test') ipxml.netmask = ('netmask_test') - netxml.ip = ipxml + netxml.ips = [ipxml] return netxml def test_getters(self): @@ -747,7 +747,7 @@ def test_valid_xml(self): def test_ip_getter(self): netxml = self._from_scratch() - ipxml = netxml.ip + ipxml = netxml.ips[0] self.assertEqual(ipxml.address, 'address_test') self.assertEqual(ipxml.netmask, 'netmask_test') diff --git a/virttest/libvirt_xml/network_xml.py b/virttest/libvirt_xml/network_xml.py index 340ce07b35..9210ce06fd 100644 --- a/virttest/libvirt_xml/network_xml.py +++ b/virttest/libvirt_xml/network_xml.py @@ -427,8 +427,8 @@ class NetworkXMLBase(base.LibvirtXMLBase): """ __slots__ = ('name', 'uuid', 'bridge', 'defined', 'active', - 'autostart', 'persistent', 'forward', 'mac', 'ip', - 'bandwidth_inbound', 'bandwidth_outbound', 'portgroup', + 'autostart', 'persistent', 'forward', 'mac', 'ips', + 'bandwidth_inbound', 'bandwidth_outbound', 'portgroups', 'dns', 'domain_name', 'nat_port', 'forward_interface', 'routes', 'virtualport_type', 'vf_list', 'driver', 'pf', 'mtu', 'connection', 'port', 'nat_attrs') @@ -448,6 +448,10 @@ def __init__(self, virsh_instance=base.virsh): tag_name='uuid') accessors.XMLAttribute('mac', self, parent_xpath='/', tag_name='mac', attribute='address') + accessors.XMLElementList('ips', self, parent_xpath='/', + marshal_from=self.marshal_from_ips, + marshal_to=self.marshal_to_ips, + has_subclass=True) accessors.XMLElementDict('forward', self, parent_xpath='/', tag_name='forward') accessors.XMLElementList('forward_interface', self, parent_xpath='/forward', @@ -479,6 +483,10 @@ def __init__(self, virsh_instance=base.virsh): tag_name='mtu', attribute='size') accessors.XMLAttribute('domain_name', self, parent_xpath='/', tag_name='domain', attribute='name') + accessors.XMLElementList('portgroups', self, parent_xpath='/', + marshal_from=self.marshal_from_portgroups, + marshal_to=self.marshal_to_portgroups, + has_subclass=True) accessors.XMLElementNest('dns', self, parent_xpath='/', tag_name='dns', subclass=DNSXML, subclass_dargs={ @@ -617,17 +625,7 @@ def get_persistent(self): set_persistent = set_defined del_persistent = del_defined - def get_ip(self): - xmltreefile = self.__dict_get__('xml') - try: - ip_root = xmltreefile.reroot('/ip') - except KeyError as detail: - raise xcepts.LibvirtXMLError(detail) - ipxml = IPXML(virsh_instance=self.__dict_get__('virsh')) - ipxml.xmltreefile = ip_root - return ipxml - - def set_ip(self, value): + def add_ip(self, value): if not issubclass(type(value), IPXML): raise xcepts.LibvirtXMLError("value must be a IPXML or subclass") xmltreefile = self.__dict_get__('xml') @@ -636,13 +634,6 @@ def set_ip(self, value): root.append(value.xmltreefile.getroot()) xmltreefile.write() - def del_ip(self): - xmltreefile = self.__dict_get__('xml') - element = xmltreefile.find('/ip') - if element is not None: - xmltreefile.remove(element) - xmltreefile.write() - def del_element(self, element='', index=0): """ Delete element from network xml @@ -660,28 +651,57 @@ def del_element(self, element='', index=0): xmltreefile.remove(del_elem) xmltreefile.write() - def get_portgroup(self): - try: - portgroup_root = self.xmltreefile.reroot('/portgroup') - except KeyError as detail: - raise xcepts.LibvirtXMLError(detail) - portgroup_xml = PortgroupXML(virsh_instance=self.__dict_get__('virsh')) - portgroup_xml.xmltreefile = portgroup_root - return portgroup_xml - - def set_portgroup(self, value): - if not issubclass(type(value), PortgroupXML): - raise xcepts.LibvirtXMLError("value must be a PortgroupXML" - "instance or subclass.") - root = self.xmltreefile.getroot() - root.append(value.xmltreefile.getroot()) - self.xmltreefile.write() + @staticmethod + def marshal_from_ips(item, index, libvirtxml): + """ + Convert an xml object to ip tag and xml element. + """ + if isinstance(item, IPXML): + return 'ip', item + elif isinstance(item, dict): + ip = IPXML() + ip.setup_attrs(**item) + return 'ip', ip + else: + raise xcepts.LibvirtXMLError("Expected a list of IPXML " + "instances, not a %s" % str(item)) + + @staticmethod + def marshal_to_ips(tag, new_treefile, index, libvirtxml): + """ + Convert a ip tag xml element to an object of IPXML. + """ + if tag != 'ip': + return None # Don't convert this item + newone = IPXML(virsh_instance=libvirtxml.virsh) + newone.xmltreefile = new_treefile + return newone - def del_portgroup(self): - element = self.xmltreefile.find("/portgroup") - if element is not None: - self.xmltreefile.remove(element) - self.xmltreefile.write() + @staticmethod + def marshal_from_portgroups(item, index, libvirtxml): + """ + Convert an xml object to portgroup tag and xml element. + """ + if isinstance(item, PortgroupXML): + return 'portgroup', item + elif isinstance(item, dict): + portgroup = PortgroupXML() + portgroup.setup_attrs(**item) + return 'portgroup', portgroup + else: + raise xcepts.LibvirtXMLError("Expected a list of PortgroupXML " + "instances, not a %s" % str(item)) + + @staticmethod + def marshal_to_portgroups(tag, new_treefile, index, libvirtxml): + """ + Convert a portgroup tag xml element to an object of PortgroupXML. + """ + if tag != 'portgroup': + return None # Don't convert this item + newone = PortgroupXML(virsh_instance=libvirtxml.virsh) + newone.xmltreefile = new_treefile + return newone def get_interface_connection(self): try: diff --git a/virttest/libvirt_xml/vm_xml.py b/virttest/libvirt_xml/vm_xml.py index 219fc05927..21aa547147 100755 --- a/virttest/libvirt_xml/vm_xml.py +++ b/virttest/libvirt_xml/vm_xml.py @@ -10,6 +10,7 @@ from .. import xml_utils from .. import utils_misc from ..libvirt_xml import base, accessors, xcepts +from ..libvirt_xml.base import LibvirtXMLBase from ..libvirt_xml.devices import librarian LOG = logging.getLogger('avocado.' + __name__) @@ -56,7 +57,7 @@ def by_device_tag(self, tag): return result -class VMXMLBase(base.LibvirtXMLBase): +class VMXMLBase(LibvirtXMLBase): """ Accessor methods for VMXML class properties (items in __slots__) diff --git a/virttest/unittests/libvirt_xml/test_network_xml.py b/virttest/unittests/libvirt_xml/test_network_xml.py new file mode 100644 index 0000000000..9e741825e1 --- /dev/null +++ b/virttest/unittests/libvirt_xml/test_network_xml.py @@ -0,0 +1,104 @@ +import unittest + +from virttest.libvirt_xml import network_xml + +# TODO: The current test doesn't cover all attributes of a network xml. +# It needs update later +XML = ''' + + testnet + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +''' + +network_attrs = { + 'bridge': {'name': 'br0'}, + 'forward': {'mode': 'bridge'}, + 'ips': [{'address': '192.168.122.1', + 'dhcp_ranges': {'attrs': {'end': '192.168.122.254', + 'start': '192.168.122.2'}}, + 'netmask': '255.255.255.0'}, + {'address': '2001:db8:ca2:2::1', + 'family': 'ipv6', + 'hosts': [{'attrs': {'ip': '2001:db8:ca2:2:3::1', 'name': 'paul'}}, + {'attrs': {'id': '0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66', + 'ip': '2001:db8:ca2:2:3::2'}}, + {'attrs': {'id': '0:3:0:1:0:16:3e:11:22:33', + 'ip': '2001:db8:ca2:2:3::3', + 'name': 'ralph'}}, + {'attrs': {'id': '0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63', + 'ip': '2001:db8:ca2:2:3::4', + 'name': 'badbob'}}], + 'netmask': '255.255.255.0', + 'prefix': '64'}], + 'name': 'testnet', + 'port': {'isolated': 'yes'}, + 'portgroups': [{'bandwidth_inbound': {'average': '1000', + 'burst': '5120', + 'peak': '5000'}, + 'bandwidth_outbound': {'average': '1000', + 'burst': '5120', + 'peak': '5000'}, + 'default': 'yes', + 'name': 'engineering', + 'virtualport_type': '802.1Qbh'}, + {'bandwidth_inbound': {'average': '500', + 'burst': '2560', + 'peak': '2000'}, + 'bandwidth_outbound': {'average': '128', + 'burst': '256', + 'peak': '256'}, + 'name': 'sales', + 'virtualport_type': '802.1Qbh'}] +} + + +class TestNetworkXML(unittest.TestCase): + + def test_setup_network_default(self): + network = network_xml.NetworkXML() + network.setup_attrs(**network_attrs) + + cmp_device = network_xml.NetworkXML() + cmp_device.xml = XML.strip() + self.assertEqual(network, cmp_device) + + def test_fetch_attrs_network_default(self): + network = network_xml.NetworkXML() + network.xml = XML.strip() + fetched_attrs = network.fetch_attrs() + self.assertEqual(network_attrs, fetched_attrs) + + +if __name__ == '__main__': + unittest.main() diff --git a/virttest/utils_libvirt/libvirt_network.py b/virttest/utils_libvirt/libvirt_network.py index 6fab949f3e..87bbf1a0c1 100644 --- a/virttest/utils_libvirt/libvirt_network.py +++ b/virttest/utils_libvirt/libvirt_network.py @@ -140,7 +140,7 @@ def modify_network_xml(net_dict, testnet_xml): if del_nat is True: testnet_xml.del_nat_attrs() if del_ip: - testnet_xml.del_ip() + testnet_xml.del_ips() if dns_txt: dns_dict = {"txt": ast.literal_eval(dns_txt)} dns_obj = testnet_xml.new_dns(**dns_dict) diff --git a/virttest/utils_test/libvirt.py b/virttest/utils_test/libvirt.py index 4a50fce542..407cec2e44 100644 --- a/virttest/utils_test/libvirt.py +++ b/virttest/utils_test/libvirt.py @@ -113,7 +113,7 @@ def create_network_xml_with_dhcp(self): ran = network_xml.RangeXML() ran.attrs = {'start': dhcp_start, 'end': dhcp_end} ip.dhcp_ranges = ran - net_xml.ip = ip + net_xml.ips = [ip] net_xml.bridge = {'name': self.kwargs.get('br_name'), 'stp': 'on', 'delay': '0'} return net_xml @@ -133,7 +133,7 @@ def create_vnet_xml(self): ran = network_xml.RangeXML() ran.attrs = {'start': dhcp_start, 'end': dhcp_end} ip.dhcp_ranges = ran - net_xml.ip = ip + net_xml.ips = [ip] return address, net_xml def create_macvtap_xml(self): @@ -1879,7 +1879,7 @@ def create_net_xml(net_name, params): if not virsh.net_info(net_name, ignore_status=True).exit_status: # Edit an existed network netxml = network_xml.NetworkXML.new_from_net_dumpxml(net_name) - netxml.del_ip() + netxml.del_ips() else: netxml = network_xml.NetworkXML(net_name) if disable_dns: @@ -1950,7 +1950,7 @@ def create_net_xml(net_name, params): host_xml_6.attrs = {"name": guest_name, "ip": guest_ipv6} ipxml.hosts = [host_xml_6] - netxml.set_ip(ipxml) + netxml.add_ip(ipxml) if net_ip_address: ipxml = network_xml.IPXML(net_ip_address, net_ip_netmask) @@ -1970,7 +1970,7 @@ def create_net_xml(net_name, params): "ip": guest_ipv4, "mac": guest_mac} ipxml.hosts = [host_xml_4] - netxml.set_ip(ipxml) + netxml.add_ip(ipxml) if routes: netxml.routes = [ast.literal_eval(x) for x in routes] if pg_name: @@ -1983,6 +1983,7 @@ def create_net_xml(net_name, params): pg_bandwidth_outbound = params.get( "portgroup_bandwidth_outbound", "").split() pg_vlan = params.get("portgroup_vlan", "").split() + pgs = [] for i in range(len(pg_name)): pgxml = network_xml.PortgroupXML() pgxml.name = pg_name[i] @@ -1998,7 +1999,8 @@ def create_net_xml(net_name, params): pg_bandwidth_outbound[i]) if len(pg_vlan) > i: pgxml.vlan_tag = ast.literal_eval(pg_vlan[i]) - netxml.set_portgroup(pgxml) + pgs.append(pgxml) + netxml.portgroups = pgs vf_list = ast.literal_eval(vf_list_attrs) if vf_list: