Use XMLBuilder for Interface XML

So we unify parsing and building the XML.

Since we already do this for vmmDomain, take the opportunity to move
the shared infrastructure into vmmLibvirtObject
This commit is contained in:
Cole Robinson 2013-09-09 17:14:16 -04:00
parent cb06f7eb3d
commit 3db5cb5f06
25 changed files with 743 additions and 1124 deletions

View File

@ -1,21 +1,20 @@
<interface type='bond' name='test-bond-arp'>
<start mode='onboot'/>
<mac address='AA:AA:AA:AA:AA:AA'/>
<mtu size='1501'/>
<protocol family='ipv4'>
</protocol>
<interface type="bond" name="test-bond-arp">
<bond>
<arpmon interval='100' target='192.168.100.200' validate='backup'/>
<interface type='ethernet' name='eth0'>
<start mode='none'/>
<mac address='00:FF:EE:FF:EE:FF'/>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
<interface type='ethernet' name='eth1'>
<mac address='00:FF:EE:FF:EE:AB'/>
<interface type="ethernet" name="eth1">
<mac address="00:FF:EE:FF:EE:AB"/>
</interface>
<interface type='ethernet' name='eth2'>
<start mode='hotplug'/>
<mac address='00:FF:EE:FF:EE:CD'/>
<interface type="ethernet" name="eth2">
<start mode="hotplug"/>
<mac address="00:FF:EE:FF:EE:CD"/>
</interface>
<arpmon interval="100" target="192.168.100.200" validate="backup"/>
</bond>
<start mode="onboot"/>
<mac address="AA:AA:AA:AA:AA:AA"/>
<mtu size="1501"/>
<protocol family="ipv4"/>
</interface>

View File

@ -1,21 +1,20 @@
<interface type='bond' name='test-bond-mii'>
<start mode='onboot'/>
<mac address='AA:AA:AA:AA:AA:AA'/>
<mtu size='1501'/>
<protocol family='ipv4'>
</protocol>
<interface type="bond" name="test-bond-mii">
<bond>
<miimon freq='123' downdelay='34' updelay='12' carrier='netif'/>
<interface type='ethernet' name='eth0'>
<start mode='none'/>
<mac address='00:FF:EE:FF:EE:FF'/>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
<interface type='ethernet' name='eth1'>
<mac address='00:FF:EE:FF:EE:AB'/>
<interface type="ethernet" name="eth1">
<mac address="00:FF:EE:FF:EE:AB"/>
</interface>
<interface type='ethernet' name='eth2'>
<start mode='hotplug'/>
<mac address='00:FF:EE:FF:EE:CD'/>
<interface type="ethernet" name="eth2">
<start mode="hotplug"/>
<mac address="00:FF:EE:FF:EE:CD"/>
</interface>
<miimon freq="123" downdelay="34" updelay="12" carrier="netif"/>
</bond>
<start mode="onboot"/>
<mac address="AA:AA:AA:AA:AA:AA"/>
<mtu size="1501"/>
<protocol family="ipv4"/>
</interface>

View File

@ -1,20 +1,19 @@
<interface type='bond' name='test-bond'>
<start mode='onboot'/>
<mac address='AA:AA:AA:AA:AA:AA'/>
<mtu size='1501'/>
<protocol family='ipv4'>
</protocol>
<interface type="bond" name="test-bond">
<bond>
<interface type='ethernet' name='eth0'>
<start mode='none'/>
<mac address='00:FF:EE:FF:EE:FF'/>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
<interface type='ethernet' name='eth1'>
<mac address='00:FF:EE:FF:EE:AB'/>
<interface type="ethernet" name="eth1">
<mac address="00:FF:EE:FF:EE:AB"/>
</interface>
<interface type='ethernet' name='eth2'>
<start mode='hotplug'/>
<mac address='00:FF:EE:FF:EE:CD'/>
<interface type="ethernet" name="eth2">
<start mode="hotplug"/>
<mac address="00:FF:EE:FF:EE:CD"/>
</interface>
</bond>
<start mode="onboot"/>
<mac address="AA:AA:AA:AA:AA:AA"/>
<mtu size="1501"/>
<protocol family="ipv4"/>
</interface>

View File

@ -1,38 +1,38 @@
<interface type='bridge' name='test-bridge-ip'>
<protocol family='ipv4'>
<dhcp peerdns='yes'/>
<ip address='129.63.1.2'/>
<ip address='255.255.255.0'/>
<route gateway='1.2.3.4'/>
</protocol>
<protocol family='ipv6'>
<autoconf/>
<dhcp peerdns='yes'/>
<ip address='fe99::215:58ff:fe6e:5' prefix='32'/>
<ip address='fe80::215:58ff:fe6e:5' prefix='64'/>
<route gateway='1.2.3.4'/>
</protocol>
<interface type="bridge" name="test-bridge-ip">
<bridge>
<interface type='ethernet' name='vlaneth1'>
<interface type="ethernet" name="vlaneth1">
</interface>
<interface type='bond' name='bond-brbond'>
<start mode='none'/>
<protocol family='ipv6'>
<ip address='3ffe:ffff:0:5::1' prefix='128'/>
<ip address='3ffe:ffff:0:5::3' prefix='128'/>
<ip address='3ffe:ffff:0:5::5' prefix='128'/>
<interface type="bond" name="bond-brbond">
<start mode="none"/>
<protocol family="ipv6">
<ip address="3ffe:ffff:0:5::1" prefix="128"/>
<ip address="3ffe:ffff:0:5::3" prefix="128"/>
<ip address="3ffe:ffff:0:5::5" prefix="128"/>
</protocol>
<bond mode='active-backup'>
<miimon freq='100' updelay='10' carrier='ioctl'/>
<interface type='ethernet' name='brbond-eth0'>
<bond mode="active-backup">
<miimon freq="100" updelay="10" carrier="ioctl"/>
<interface type="ethernet" name="brbond-eth0">
</interface>
<interface type='ethernet' name='brbond-eth1'>
<interface type="ethernet" name="brbond-eth1">
</interface>
</bond>
</interface>
<interface type='ethernet' name='eth0'>
<start mode='none'/>
<mac address='00:FF:EE:FF:EE:FF'/>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
</bridge>
<protocol family="ipv4">
<dhcp peerdns="yes"/>
<ip address="129.63.1.2"/>
<ip address="255.255.255.0"/>
<route gateway="1.2.3.4"/>
</protocol>
<protocol family="ipv6">
<autoconf/>
<dhcp peerdns="yes"/>
<ip address="fe99::215:58ff:fe6e:5" prefix="32"/>
<ip address="fe80::215:58ff:fe6e:5" prefix="64"/>
<route gateway="1.2.3.4"/>
</protocol>
</interface>

View File

@ -1,25 +1,25 @@
<interface type='bridge' name='test-bridge'>
<bridge stp='off' delay='7'>
<interface type='ethernet' name='vlaneth1'>
<interface type="bridge" name="test-bridge">
<bridge stp="off" delay="7">
<interface type="ethernet" name="vlaneth1">
</interface>
<interface type='bond' name='bond-brbond'>
<start mode='none'/>
<protocol family='ipv6'>
<ip address='3ffe:ffff:0:5::1' prefix='128'/>
<ip address='3ffe:ffff:0:5::3' prefix='128'/>
<ip address='3ffe:ffff:0:5::5' prefix='128'/>
<interface type="bond" name="bond-brbond">
<start mode="none"/>
<protocol family="ipv6">
<ip address="3ffe:ffff:0:5::1" prefix="128"/>
<ip address="3ffe:ffff:0:5::3" prefix="128"/>
<ip address="3ffe:ffff:0:5::5" prefix="128"/>
</protocol>
<bond mode='active-backup'>
<miimon freq='100' updelay='10' carrier='ioctl'/>
<interface type='ethernet' name='brbond-eth0'>
<bond mode="active-backup">
<miimon freq="100" updelay="10" carrier="ioctl"/>
<interface type="ethernet" name="brbond-eth0">
</interface>
<interface type='ethernet' name='brbond-eth1'>
<interface type="ethernet" name="brbond-eth1">
</interface>
</bond>
</interface>
<interface type='ethernet' name='eth0'>
<start mode='none'/>
<mac address='00:FF:EE:FF:EE:FF'/>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
</bridge>
</interface>

View File

@ -1,5 +1,5 @@
<interface type='ethernet' name='test-ethernet-copy-proto'>
<protocol family='ipv6'>
<dhcp/>
</protocol>
<interface type="ethernet" name="test-ethernet-copy-proto">
<protocol family="ipv6">
<dhcp/>
</protocol>
</interface>

View File

@ -1,4 +1,4 @@
<interface type='ethernet' name='test-ethernet-params'>
<start mode='hotplug'/>
<mtu size='1234'/>
<interface type="ethernet" name="test-ethernet-params">
<start mode="hotplug"/>
<mtu size="1234"/>
</interface>

View File

@ -1,2 +1 @@
<interface type='ethernet' name='test-ethernet'>
</interface>
<interface type="ethernet" name="test-ethernet"/>

View File

@ -1,5 +1,5 @@
<interface type='vlan' name='test-vlan'>
<vlan tag='123'>
<interface name='eth2'/>
<interface type="vlan" name="test-vlan">
<vlan tag="123">
<interface name="eth2"/>
</vlan>
</interface>

View File

@ -18,48 +18,47 @@ import os
import unittest
import logging
from virtinst import Interface
from virtinst import Interface, InterfaceProtocol
from tests import utils
conn = utils.open_testdriver()
datadir = "tests/interface-xml"
vlan_iface = conn.interfaceLookupByName("vlaneth1")
bond_iface = conn.interfaceLookupByName("bond-brbond")
eth_iface1 = conn.interfaceLookupByName("eth0")
eth_iface2 = conn.interfaceLookupByName("eth1")
eth_iface3 = conn.interfaceLookupByName("eth2")
br_iface = conn.interfaceLookupByName("brempty")
def _m(_n):
xml = conn.interfaceLookupByName(_n).XMLDesc(0)
return Interface(conn, parsexml=xml)
class TestInterfaces(unittest.TestCase):
def setUp(self):
pass
def build_interface(self, interface_type, name):
iclass = Interface.Interface.interface_class_for_type(interface_type)
iobj = iclass(conn, name)
iobj = Interface(conn)
iobj.type = interface_type
iobj.name = name
return iobj
def set_general_params(self, iface_obj):
iface_obj.mtu = 1501
iface_obj.macaddr = "AA:AA:AA:AA:AA:AA"
iface_obj.start_mode = Interface.Interface.INTERFACE_START_MODE_ONBOOT
iface_obj.protocols = [Interface.InterfaceProtocolIPv4()]
iface_obj.start_mode = Interface.INTERFACE_START_MODE_ONBOOT
proto = InterfaceProtocol(conn)
proto.family = InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV4
iface_obj.add_protocol(proto)
def add_child_interfaces(self, iface_obj):
if iface_obj.object_type == Interface.Interface.INTERFACE_TYPE_BRIDGE:
iface_obj.interfaces.append(vlan_iface)
iface_obj.interfaces.append(bond_iface)
iface_obj.interfaces.append(eth_iface1)
elif iface_obj.object_type == Interface.Interface.INTERFACE_TYPE_BOND:
iface_obj.interfaces.append(eth_iface1)
iface_obj.interfaces.append(eth_iface2)
iface_obj.interfaces.append(eth_iface3)
if iface_obj.type == Interface.INTERFACE_TYPE_BRIDGE:
iface_obj.add_interface(_m("vlaneth1"))
iface_obj.add_interface(_m("bond-brbond"))
iface_obj.add_interface(_m("eth0"))
elif iface_obj.type == Interface.INTERFACE_TYPE_BOND:
iface_obj.add_interface(_m("eth0"))
iface_obj.add_interface(_m("eth1"))
iface_obj.add_interface(_m("eth2"))
def define_xml(self, obj, compare=True):
obj.validate()
xml = obj.get_xml_config()
logging.debug("Defining interface XML:\n%s", xml)
@ -77,7 +76,7 @@ class TestInterfaces(unittest.TestCase):
# Bridge tests
def testBridgeInterface(self):
filename = "bridge"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_BRIDGE,
obj = self.build_interface(Interface.INTERFACE_TYPE_BRIDGE,
"test-%s" % filename)
self.add_child_interfaces(obj)
@ -88,44 +87,39 @@ class TestInterfaces(unittest.TestCase):
def testBridgeInterfaceIP(self):
filename = "bridge-ip"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_BRIDGE,
obj = self.build_interface(Interface.INTERFACE_TYPE_BRIDGE,
"test-%s" % filename)
self.add_child_interfaces(obj)
# IPv4 proto
iface_ip1 = Interface.InterfaceProtocolIPAddress("129.63.1.2")
iface_ip2 = Interface.InterfaceProtocolIPAddress("255.255.255.0")
iface_proto1 = Interface.InterfaceProtocol.protocol_class_for_family(
Interface.InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV4)()
iface_proto1.ips = [iface_ip1, iface_ip2]
iface_proto1 = InterfaceProtocol(conn)
iface_proto1.family = InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV4
iface_proto1.add_ip("129.63.1.2")
iface_proto1.add_ip("255.255.255.0")
iface_proto1.gateway = "1.2.3.4"
iface_proto1.dhcp = True
iface_proto1.dhcp_peerdns = True
# IPv6 proto
iface_ip3 = Interface.InterfaceProtocolIPAddress(
"fe99::215:58ff:fe6e:5",
prefix="32")
iface_ip4 = Interface.InterfaceProtocolIPAddress(
"fe80::215:58ff:fe6e:5",
prefix="64")
iface_proto2 = Interface.InterfaceProtocol.protocol_class_for_family(
Interface.InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV6)()
iface_proto2 = InterfaceProtocol(conn)
iface_proto2.family = InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV6
iface_proto2.ips = [iface_ip3, iface_ip4]
iface_proto2.add_ip("fe99::215:58ff:fe6e:5", prefix="32")
iface_proto2.add_ip("fe80::215:58ff:fe6e:5", prefix="64")
iface_proto2.gateway = "1.2.3.4"
iface_proto2.dhcp = True
iface_proto2.dhcp_peerdns = True
iface_proto2.autoconf = True
obj.protocols = [iface_proto1, iface_proto2]
obj.add_protocol(iface_proto1)
obj.add_protocol(iface_proto2)
self.define_xml(obj)
# Bond tests
def testBondInterface(self):
filename = "bond"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_BOND,
obj = self.build_interface(Interface.INTERFACE_TYPE_BOND,
"test-%s" % filename)
self.add_child_interfaces(obj)
self.set_general_params(obj)
@ -134,12 +128,11 @@ class TestInterfaces(unittest.TestCase):
def testBondInterfaceARP(self):
filename = "bond-arp"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_BOND,
obj = self.build_interface(Interface.INTERFACE_TYPE_BOND,
"test-%s" % filename)
self.add_child_interfaces(obj)
self.set_general_params(obj)
obj.monitor_mode = "arpmon"
obj.arp_interval = 100
obj.arp_target = "192.168.100.200"
obj.arp_validate_mode = "backup"
@ -148,12 +141,11 @@ class TestInterfaces(unittest.TestCase):
def testBondInterfaceMII(self):
filename = "bond-mii"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_BOND,
obj = self.build_interface(Interface.INTERFACE_TYPE_BOND,
"test-%s" % filename)
self.add_child_interfaces(obj)
self.set_general_params(obj)
obj.monitor_mode = "miimon"
obj.mii_frequency = "123"
obj.mii_updelay = "12"
obj.mii_downdelay = "34"
@ -164,34 +156,34 @@ class TestInterfaces(unittest.TestCase):
# Ethernet tests
def testEthernetInterface(self):
filename = "ethernet"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_ETHERNET,
obj = self.build_interface(Interface.INTERFACE_TYPE_ETHERNET,
"test-%s" % filename)
self.define_xml(obj)
def testEthernetManyParam(self):
filename = "ethernet-params"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_ETHERNET,
obj = self.build_interface(Interface.INTERFACE_TYPE_ETHERNET,
"test-%s" % filename)
obj.mtu = 1234
obj.mac = "AA:BB:FF:FF:BB:AA"
obj.start_mode = Interface.Interface.INTERFACE_START_MODE_HOTPLUG
obj.start_mode = Interface.INTERFACE_START_MODE_HOTPLUG
self.define_xml(obj)
# VLAN tests
def testVLANInterface(self):
filename = "vlan"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_VLAN,
obj = self.build_interface(Interface.INTERFACE_TYPE_VLAN,
"test-%s" % filename)
obj.tag = "123"
obj.parent_interface = eth_iface3
obj.parent_interface = "eth2"
self.define_xml(obj)
def testVLANInterfaceBusted(self):
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_VLAN,
obj = self.build_interface(Interface.INTERFACE_TYPE_VLAN,
"vlan1")
try:
@ -205,13 +197,14 @@ class TestInterfaces(unittest.TestCase):
# protocol_xml test
def testEthernetProtocolInterface(self):
filename = "ethernet-copy-proto"
obj = self.build_interface(Interface.Interface.INTERFACE_TYPE_ETHERNET,
obj = self.build_interface(Interface.INTERFACE_TYPE_ETHERNET,
"test-%s" % filename)
protoxml = (" <protocol family='ipv6'>\n"
" <dhcp/>\n"
" </protocol>\n")
obj.protocol_xml = protoxml
proto = InterfaceProtocol(conn, parsexml=protoxml)
obj.add_protocol(proto)
self.define_xml(obj)

View File

@ -126,25 +126,26 @@ def sanitize_xml_for_define(xml):
return xml
def test_create(testconn, xml):
def test_create(testconn, xml, define_func="defineXML"):
xml = sanitize_xml_for_define(xml)
try:
dom = testconn.defineXML(xml)
func = getattr(testconn, define_func)
obj = func(xml)
except Exception, e:
raise RuntimeError(str(e) + "\n" + xml)
try:
dom.create()
dom.destroy()
dom.undefine()
obj.create()
obj.destroy()
obj.undefine()
except:
try:
dom.destroy()
obj.destroy()
except:
pass
try:
dom.undefine()
obj.undefine()
except:
pass

View File

@ -0,0 +1,20 @@
<interface type="bond" name="test-bond-arp">
<bond mode="active-backup">
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
<interface type="ethernet" name="eth1">
<mac address="00:FF:EE:FF:EE:AB"/>
</interface>
<interface type="ethernet" name="eth2">
<start mode="hotplug"/>
<mac address="00:FF:EE:FF:EE:CD"/>
</interface>
<arpmon interval="234" target="1.2.3.4" validate="active"/>
</bond>
<start mode="hotplug"/>
<mac address="AA:AA:AA:11:AA:AA"/>
<mtu size="1234"/>
<protocol family="ipv4"/>
</interface>

View File

@ -0,0 +1,20 @@
<interface type="bond" name="test-bond-mii">
<bond>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
<interface type="ethernet" name="eth1">
<mac address="00:FF:EE:FF:EE:AB"/>
</interface>
<interface type="ethernet" name="eth2">
<start mode="hotplug"/>
<mac address="00:FF:EE:FF:EE:CD"/>
</interface>
<miimon freq="111" downdelay="22" updelay="33" carrier="ioctl"/>
</bond>
<start mode="onboot"/>
<mac address="AA:AA:AA:AA:AA:AA"/>
<mtu size="1501"/>
<protocol family="ipv4"/>
</interface>

View File

@ -0,0 +1,21 @@
<interface type="bridge" name="foo-new">
<bridge stp="on" delay="2">
<interface type="ethernet" name="vlaneth1">
</interface>
<interface type="ethernet" name="eth0">
<start mode="none"/>
<mac address="00:FF:EE:FF:EE:FF"/>
</interface>
</bridge>
<protocol family="ipv4">
<dhcp peerdns="no"/>
<ip address="129.63.1.2"/>
<ip address="255.255.255.0"/>
<route gateway="5.5.5.5"/>
</protocol>
<protocol family="ipv6">
<ip address="fe99::215:58ff:fe6e:5" prefix="32"/>
<ip address="foobar" prefix="38"/>
<route gateway="1.2.3.4"/>
</protocol>
</interface>

View File

@ -0,0 +1,5 @@
<interface type="vlan" name="test-vlan">
<vlan tag="456">
<interface name="foonew"/>
</vlan>
</interface>

View File

@ -810,6 +810,103 @@ class XMLParseTest(unittest.TestCase):
utils.diff_compare(snap.get_xml_config(), outfile)
###################
# Interface tests #
###################
def testInterfaceBridgeIP(self):
basename = "test-bridge-ip"
infile = "tests/interface-xml/%s.xml" % basename
outfile = "tests/xmlparse-xml/interface-%s-out.xml" % basename
iface = virtinst.Interface(conn, parsexml=file(infile).read())
self.assertEquals(len(iface.protocols), 2)
self.assertEquals(len(iface.interfaces), 3)
check = self._make_checker(iface)
check("type", "bridge", "foo", "bridge")
check("name", "test-bridge-ip", "foo-new")
check("stp", None, True)
check("delay", None, 2)
check = self._make_checker(iface.protocols[0])
check("family", "ipv4", "foo", "ipv4")
check("dhcp_peerdns", True, False)
check("gateway", "1.2.3.4", "5.5.5.5")
self.assertEquals(iface.protocols[0].ips[1].address, "255.255.255.0")
check = self._make_checker(iface.protocols[1])
check("dhcp", True, False)
check("autoconf", True, False)
check = self._make_checker(iface.protocols[1].ips[1])
check("address", "fe80::215:58ff:fe6e:5", "foobar")
check("prefix", 64, 38)
# Remove a child interface, verify it's data remains intact
child_iface = iface.interfaces[1]
iface.remove_interface(child_iface)
check = self._make_checker(child_iface)
check("name", "bond-brbond")
self.assertEquals(len(child_iface.interfaces), 2)
utils.diff_compare(iface.get_xml_config(), outfile)
utils.test_create(conn, iface.get_xml_config(), "interfaceDefineXML")
def testInterfaceBondArp(self):
basename = "test-bond-arp"
infile = "tests/interface-xml/%s.xml" % basename
outfile = "tests/xmlparse-xml/interface-%s-out.xml" % basename
iface = virtinst.Interface(conn, parsexml=file(infile).read())
check = self._make_checker(iface)
check("start_mode", "onboot", "hotplug")
check("macaddr", "AA:AA:AA:AA:AA:AA", "AA:AA:AA:11:AA:AA")
check("mtu", 1501, 1234)
check("bond_mode", None, "active-backup")
check("arp_interval", 100, 234)
check("arp_target", "192.168.100.200", "1.2.3.4")
check("arp_validate_mode", "backup", "active")
utils.diff_compare(iface.get_xml_config(), outfile)
utils.test_create(conn, iface.get_xml_config(), "interfaceDefineXML")
def testInterfaceBondMii(self):
basename = "test-bond-mii"
infile = "tests/interface-xml/%s.xml" % basename
outfile = "tests/xmlparse-xml/interface-%s-out.xml" % basename
iface = virtinst.Interface(conn, parsexml=file(infile).read())
check = self._make_checker(iface)
check("mii_frequency", 123, 111)
check("mii_downdelay", 34, 22)
check("mii_updelay", 12, 33)
check("mii_carrier_mode", "netif", "ioctl")
utils.diff_compare(iface.get_xml_config(), outfile)
utils.test_create(conn, iface.get_xml_config(), "interfaceDefineXML")
def testInterfaceVLAN(self):
basename = "test-vlan"
infile = "tests/interface-xml/%s.xml" % basename
outfile = "tests/xmlparse-xml/interface-%s-out.xml" % basename
iface = virtinst.Interface(conn, parsexml=file(infile).read())
check = self._make_checker(iface)
check("tag", 123, 456)
check("parent_interface", "eth2", "foonew")
utils.diff_compare(iface.get_xml_config(), outfile)
utils.test_create(conn, iface.get_xml_config(), "interfaceDefineXML")
##############
# Misc tests #
##############
def testzzzzCheckProps(self):
# pylint: disable=W0212
# Access to protected member, needed to unittest stuff

View File

@ -25,7 +25,7 @@ from gi.repository import Gdk
import logging
from virtinst import Interface
from virtinst import Interface, InterfaceProtocol
from virtManager import uihelpers
from virtManager.baseclass import vmmGObjectUI
@ -188,13 +188,13 @@ class vmmCreateInterface(vmmGObjectUI):
text = Gtk.CellRendererText()
type_list.pack_start(text, True)
type_list.add_attribute(text, 'text', 1)
type_model.append([Interface.Interface.INTERFACE_TYPE_BRIDGE,
type_model.append([Interface.INTERFACE_TYPE_BRIDGE,
_("Bridge")])
type_model.append([Interface.Interface.INTERFACE_TYPE_BOND,
type_model.append([Interface.INTERFACE_TYPE_BOND,
_("Bond")])
type_model.append([Interface.Interface.INTERFACE_TYPE_ETHERNET,
type_model.append([Interface.INTERFACE_TYPE_ETHERNET,
_("Ethernet")])
type_model.append([Interface.Interface.INTERFACE_TYPE_VLAN,
type_model.append([Interface.INTERFACE_TYPE_VLAN,
_("VLAN")])
# Start mode
@ -251,7 +251,7 @@ class vmmCreateInterface(vmmGObjectUI):
mode_list.pack_start(txt, True)
mode_list.add_attribute(txt, "text", 0)
mode_model.append([_("System default"), None])
for m in Interface.InterfaceBond.INTERFACE_BOND_MODES:
for m in Interface.INTERFACE_BOND_MODES:
mode_model.append([m, m])
mon_list = self.widget("bond-monitor-mode")
@ -261,7 +261,7 @@ class vmmCreateInterface(vmmGObjectUI):
mon_list.pack_start(txt, True)
mon_list.add_attribute(txt, "text", 0)
mon_model.append([_("System default"), None])
for m in Interface.InterfaceBond.INTERFACE_BOND_MONITOR_MODES:
for m in Interface.INTERFACE_BOND_MONITOR_MODES:
mon_model.append([m, m])
validate_list = self.widget("arp-validate")
@ -270,7 +270,7 @@ class vmmCreateInterface(vmmGObjectUI):
txt = Gtk.CellRendererText()
validate_list.pack_start(txt, True)
validate_list.add_attribute(txt, "text", 0)
for m in Interface.InterfaceBond.INTERFACE_BOND_MONITOR_MODE_ARP_VALIDATE_MODES:
for m in Interface.INTERFACE_BOND_MONITOR_MODE_ARP_VALIDATE_MODES:
validate_model.append([m])
carrier_list = self.widget("mii-carrier")
@ -279,7 +279,7 @@ class vmmCreateInterface(vmmGObjectUI):
txt = Gtk.CellRendererText()
carrier_list.pack_start(txt, True)
carrier_list.add_attribute(txt, "text", 0)
for m in Interface.InterfaceBond.INTERFACE_BOND_MONITOR_MODE_MII_CARRIER_TYPES:
for m in Interface.INTERFACE_BOND_MONITOR_MODE_MII_CARRIER_TYPES:
carrier_model.append([m])
# IP config
@ -364,6 +364,8 @@ class vmmCreateInterface(vmmGObjectUI):
self.widget("ipv6-mode").set_active(IP_NONE)
self.widget("ipv6-autoconf").set_active(False)
self.widget("ipv6-gateway").set_text("")
self.widget("ipv6-address-list").get_model().clear()
self.ipv6_address_selected()
def populate_details_page(self):
@ -373,8 +375,8 @@ class vmmCreateInterface(vmmGObjectUI):
self.widget("interface-name-entry").hide()
self.widget("interface-name-label").hide()
if itype in [Interface.Interface.INTERFACE_TYPE_BRIDGE,
Interface.Interface.INTERFACE_TYPE_BOND]:
if itype in [Interface.INTERFACE_TYPE_BRIDGE,
Interface.INTERFACE_TYPE_BOND]:
widget = "interface-name-entry"
else:
widget = "interface-name-label"
@ -385,9 +387,9 @@ class vmmCreateInterface(vmmGObjectUI):
# Make sure interface type specific fields are shown
type_dict = {
Interface.Interface.INTERFACE_TYPE_BRIDGE : "bridge",
Interface.Interface.INTERFACE_TYPE_BOND : "bond",
Interface.Interface.INTERFACE_TYPE_VLAN : "vlan",
Interface.INTERFACE_TYPE_BRIDGE : "bridge",
Interface.INTERFACE_TYPE_BOND : "bond",
Interface.INTERFACE_TYPE_VLAN : "vlan",
}
for key, value in type_dict.items():
@ -395,10 +397,10 @@ class vmmCreateInterface(vmmGObjectUI):
self.widget("%s-label" % value).set_visible(do_show)
self.widget("%s-box" % value).set_visible(do_show)
if itype == Interface.Interface.INTERFACE_TYPE_BRIDGE:
if itype == Interface.INTERFACE_TYPE_BRIDGE:
self.update_bridge_desc()
elif itype == Interface.Interface.INTERFACE_TYPE_BOND:
elif itype == Interface.INTERFACE_TYPE_BOND:
self.update_bond_desc()
# Populate device list
@ -417,9 +419,9 @@ class vmmCreateInterface(vmmGObjectUI):
copy_model = copy_combo.get_model()
# Only select 'copy from' option if using bridge/bond/vlan
enable_copy = (itype in [Interface.Interface.INTERFACE_TYPE_BRIDGE,
Interface.Interface.INTERFACE_TYPE_BOND,
Interface.Interface.INTERFACE_TYPE_VLAN])
enable_copy = (itype in [Interface.INTERFACE_TYPE_BRIDGE,
Interface.INTERFACE_TYPE_BOND,
Interface.INTERFACE_TYPE_VLAN])
# Set defaults if required
copy_model.clear()
@ -489,18 +491,18 @@ class vmmCreateInterface(vmmGObjectUI):
model = iface_list.get_model()
model.clear()
ifilter = [Interface.Interface.INTERFACE_TYPE_ETHERNET]
ifilter = [Interface.INTERFACE_TYPE_ETHERNET]
msg = None
if itype == Interface.Interface.INTERFACE_TYPE_BRIDGE:
ifilter.append(Interface.Interface.INTERFACE_TYPE_VLAN)
ifilter.append(Interface.Interface.INTERFACE_TYPE_BOND)
if itype == Interface.INTERFACE_TYPE_BRIDGE:
ifilter.append(Interface.INTERFACE_TYPE_VLAN)
ifilter.append(Interface.INTERFACE_TYPE_BOND)
msg = _("Choose interface(s) to bridge:")
elif itype == Interface.Interface.INTERFACE_TYPE_VLAN:
elif itype == Interface.INTERFACE_TYPE_VLAN:
msg = _("Choose parent interface:")
elif itype == Interface.Interface.INTERFACE_TYPE_BOND:
elif itype == Interface.INTERFACE_TYPE_BOND:
msg = _("Choose interfaces to bond:")
elif itype == Interface.Interface.INTERFACE_TYPE_ETHERNET:
elif itype == Interface.INTERFACE_TYPE_ETHERNET:
msg = _("Choose an unconfigured interface:")
self.widget("interface-list-text").set_text(msg)
@ -524,7 +526,7 @@ class vmmCreateInterface(vmmGObjectUI):
if iface_type not in ifilter:
continue
if itype == Interface.Interface.INTERFACE_TYPE_ETHERNET:
if itype == Interface.INTERFACE_TYPE_ETHERNET:
if name in row_dict:
del(row_dict[name])
@ -557,22 +559,22 @@ class vmmCreateInterface(vmmGObjectUI):
itype = self.get_config_interface_type()
name = _("No interface selected")
if itype == Interface.Interface.INTERFACE_TYPE_BRIDGE:
name = Interface.Interface.find_free_name(self.conn.get_backend(),
if itype == Interface.INTERFACE_TYPE_BRIDGE:
name = Interface.find_free_name(self.conn.get_backend(),
"br")
elif itype == Interface.Interface.INTERFACE_TYPE_BOND:
name = Interface.Interface.find_free_name(self.conn.get_backend(),
elif itype == Interface.INTERFACE_TYPE_BOND:
name = Interface.find_free_name(self.conn.get_backend(),
"bond")
else:
ifaces = self.get_config_selected_interfaces()
if len(ifaces) > 0:
iface = ifaces[0][INTERFACE_ROW_NAME]
if itype == Interface.Interface.INTERFACE_TYPE_VLAN:
if itype == Interface.INTERFACE_TYPE_VLAN:
tag = uihelpers.spin_get_helper(self.widget("vlan-tag"))
name = "%s.%s" % (iface, int(tag))
elif itype == Interface.Interface.INTERFACE_TYPE_ETHERNET:
elif itype == Interface.INTERFACE_TYPE_ETHERNET:
name = iface
return name
@ -642,8 +644,8 @@ class vmmCreateInterface(vmmGObjectUI):
active = src.get_active()
model = slave_list.get_model()
if itype in [Interface.Interface.INTERFACE_TYPE_ETHERNET,
Interface.Interface.INTERFACE_TYPE_VLAN]:
if itype in [Interface.INTERFACE_TYPE_ETHERNET,
Interface.INTERFACE_TYPE_VLAN]:
# Deselect any selected rows
for row in model:
if row == model[index]:
@ -658,8 +660,8 @@ class vmmCreateInterface(vmmGObjectUI):
def update_interface_name(self, ignore1=None, ignore2=None):
itype = self.get_config_interface_type()
if itype not in [Interface.Interface.INTERFACE_TYPE_VLAN,
Interface.Interface.INTERFACE_TYPE_ETHERNET]:
if itype not in [Interface.INTERFACE_TYPE_VLAN,
Interface.INTERFACE_TYPE_ETHERNET]:
# The rest have editable name fields, so don't overwrite
return
@ -769,14 +771,13 @@ class vmmCreateInterface(vmmGObjectUI):
def build_ip(addr_str):
if not addr_str:
return None
return None, None
ret = addr_str.rsplit("/", 1)
ip = Interface.InterfaceProtocolIPAddress(ret[0])
address = ret[0]
prefix = None
if len(ret) > 1:
ip.prefix = ret[1]
return ip
prefix = ret[1]
return address, prefix
is_manual = self.widget("ip-do-manual").get_active()
@ -804,25 +805,28 @@ class vmmCreateInterface(vmmGObjectUI):
else:
# Build IPv4 Info
if v4_mode != IP_NONE:
ipv4 = Interface.InterfaceProtocolIPv4()
ipv4 = InterfaceProtocol(self.conn.get_backend())
ipv4.family = "ipv4"
ipv4.dhcp = bool(v4_mode == IP_DHCP)
if not ipv4.dhcp:
if v4_addr:
ipv4.ips.append(build_ip(v4_addr))
addr, prefix = build_ip(v4_addr)
if addr:
ipv4.add_ip(addr, prefix)
if v4_gate:
ipv4.gateway = v4_gate
# Build IPv6 Info
if v6_mode != IP_NONE:
ipv6 = Interface.InterfaceProtocolIPv6()
ipv6 = InterfaceProtocol(self.conn.get_backend())
ipv6.family = "ipv6"
ipv6.dhcp = bool(v6_mode == IP_DHCP)
ipv6.autoconf = bool(v6_auto)
if not ipv6.dhcp:
if v6_gate:
ipv6.gateway = v6_gate
if v6_addrlist:
ipv6.ips = [build_ip(i) for i in v6_addrlist]
addr, prefix = build_ip(v4_addr)
if addr:
ipv6.add_ip(addr, prefix)
return [is_manual, copy_name, ipv4, ipv6, proto_xml]
@ -912,29 +916,34 @@ class vmmCreateInterface(vmmGObjectUI):
name = self.get_config_interface_name()
start = self.get_config_interface_startmode()
ifaces = self.get_config_selected_interfaces()
iclass = Interface.Interface.interface_class_for_type(itype)
if not name:
return self.err.val_err(_("An interface name is required."))
if (itype != Interface.Interface.INTERFACE_TYPE_BRIDGE and
if (itype != Interface.INTERFACE_TYPE_BRIDGE and
len(ifaces) == 0):
return self.err.val_err(_("An interface must be selected"))
try:
iobj = iclass(self.conn.get_backend(), name)
iobj = Interface(self.conn.get_backend())
iobj.type = itype
iobj.name = name
iobj.start_mode = start
check_conflict = False
# Pull info from selected interfaces
if hasattr(iobj, "interfaces"):
iobj.interfaces = [x[INTERFACE_ROW_KEY] for x in ifaces]
if (itype == Interface.INTERFACE_TYPE_BRIDGE or
itype == Interface.INTERFACE_TYPE_BOND):
for row in ifaces:
child = Interface(self.conn.get_backend(),
parsexml=row[INTERFACE_ROW_KEY].XMLDesc(0))
iobj.add_interface(child)
check_conflict = True
elif hasattr(iobj, "parent_interface"):
iobj.parent_interface = ifaces[0][INTERFACE_ROW_KEY]
elif itype == Interface.INTERFACE_TYPE_VLAN:
iobj.parent_interface = ifaces[0][INTERFACE_ROW_NAME]
elif itype == Interface.Interface.INTERFACE_TYPE_ETHERNET:
elif itype == Interface.INTERFACE_TYPE_ETHERNET:
iobj.macaddr = ifaces[0][INTERFACE_ROW_MAC]
# Warn about defined interfaces
@ -963,28 +972,30 @@ class vmmCreateInterface(vmmGObjectUI):
ipv6, proto_xml) = self.get_config_ip_info()
if is_manual:
protos = []
if ipv4:
protos.append(ipv4)
iobj.add_protocol(ipv4)
if ipv6:
protos.append(ipv6)
iobj.protocols = protos
iobj.add_protocol(ipv6)
else:
iobj.protocol_xml = proto_xml
for proto in proto_xml:
iobj.add_protocol(InterfaceProtocol(
self.conn.get_backend(),
parsexml=proto.get_xml_config()))
if itype == Interface.Interface.INTERFACE_TYPE_BRIDGE:
if itype == Interface.INTERFACE_TYPE_BRIDGE:
ret = self.validate_bridge(iobj, ifaces)
elif itype == Interface.Interface.INTERFACE_TYPE_BOND:
elif itype == Interface.INTERFACE_TYPE_BOND:
ret = self.validate_bond(iobj, ifaces)
elif itype == Interface.Interface.INTERFACE_TYPE_VLAN:
elif itype == Interface.INTERFACE_TYPE_VLAN:
ret = self.validate_vlan(iobj, ifaces)
elif itype == Interface.Interface.INTERFACE_TYPE_ETHERNET:
elif itype == Interface.INTERFACE_TYPE_ETHERNET:
ret = self.validate_ethernet(iobj, ifaces)
if not ret:
return ret
iobj.get_xml_config()
iobj.validate()
self.interface = iobj
except Exception, e:
@ -1030,7 +1041,6 @@ class vmmCreateInterface(vmmGObjectUI):
mii_down = self.widget("mii-downdelay").get_value()
iobj.bond_mode = mode
iobj.monitor_mode = mon
if not mon:
# No monitor params, just return

View File

@ -144,22 +144,19 @@ class vmmDomainSnapshot(vmmLibvirtObject):
Class wrapping a virDomainSnapshot object
"""
def __init__(self, conn, backend):
vmmLibvirtObject.__init__(self, conn, backend, backend.getName())
vmmLibvirtObject.__init__(self, conn, backend, backend.getName(),
parseclass=virtinst.DomainSnapshot)
self._xmlbackend = None
self.refresh_xml()
def get_name(self):
return self.xml.name
return self.xmlobj.name
def _XMLDesc(self, flags):
rawxml = self._backend.getXMLDesc(flags=flags)
self._xmlbackend = virtinst.DomainSnapshot(self.conn.get_backend(),
rawxml)
return self._xmlbackend.get_xml_config()
return self._backend.getXMLDesc(flags=flags)
def _get_xml_backend(self):
return self._xmlbackend
xml = property(_get_xml_backend)
def _get_xmlobj_prop(self):
return self._get_xmlobj()
xmlobj = property(_get_xmlobj_prop)
def is_current(self):
return self._backend.isCurrent()
@ -181,7 +178,8 @@ class vmmDomain(vmmLibvirtObject):
}
def __init__(self, conn, backend, key):
vmmLibvirtObject.__init__(self, conn, backend, key)
vmmLibvirtObject.__init__(self, conn, backend, key,
parseclass=virtinst.Guest)
self.uuid = key
self.cloning = False
@ -202,9 +200,6 @@ class vmmDomain(vmmLibvirtObject):
self._name = None
self._snapshot_list = None
self._inactive_xml_flags = 0
self._active_xml_flags = 0
self.lastStatus = libvirt.VIR_DOMAIN_SHUTOFF
self._getvcpus_supported = None
@ -213,9 +208,6 @@ class vmmDomain(vmmLibvirtObject):
self.remote_console_supported = False
self.snapshots_supported = False
self._guest = None
self._guest_to_define = None
self._enable_net_poll = False
self._stats_net_supported = True
self._stats_net_skip = []
@ -259,8 +251,6 @@ class vmmDomain(vmmLibvirtObject):
"""
Initialization to do if backed by a libvirt virDomain
"""
self._reparse_xml()
self.managedsave_supported = self.conn.get_dom_managedsave_supported(
self._backend)
@ -290,7 +280,6 @@ class vmmDomain(vmmLibvirtObject):
self.toggle_sample_disk_io))
self.connect("status-changed", self._update_start_vcpus)
self.connect("config-changed", self._reparse_xml)
self.connect("pre-startup", self._prestartup_nodedev_check)
def _prestartup_nodedev_check(self, src, ret):
@ -385,21 +374,11 @@ class vmmDomain(vmmLibvirtObject):
def _invalidate_xml(self):
vmmLibvirtObject._invalidate_xml(self)
self._guest_to_define = None
self._name = None
self._id = None
def _get_guest_to_define(self):
if not self._guest_to_define:
self._guest_to_define = self._get_guest(inactive=True)
return self._guest_to_define
def _redefine_guest(self, cb):
guest = self._get_guest_to_define()
return cb(guest)
def _redefine_device(self, cb, origdev):
defguest = self._get_guest_to_define()
defguest = self._get_xmlobj_to_define()
dev = find_device(defguest, origdev)
if dev:
return cb(dev)
@ -407,56 +386,15 @@ class vmmDomain(vmmLibvirtObject):
# If we are removing multiple dev from an active VM, a double
# attempt may result in a lookup failure. If device is present
# in the active XML, assume all is good.
if find_device(self._get_guest(), origdev):
if find_device(self._get_xmlobj(), origdev):
logging.debug("Device in active config but not inactive config.")
return
raise RuntimeError(_("Could not find specified device in the "
"inactive VM configuration: %s") % repr(origdev))
def redefine_cached(self):
if not self._guest_to_define:
logging.debug("No cached XML to define, skipping.")
return
guest = self._get_guest_to_define()
xml = guest.get_xml_config()
self._redefine_xml(xml)
def _get_domain_xml(self, inactive=False, refresh_if_nec=True):
return vmmLibvirtObject.get_xml(self,
inactive=inactive,
refresh_if_nec=refresh_if_nec)
def get_xml(self, inactive=False, refresh_if_nec=True):
guest = self._get_guest(inactive=inactive,
refresh_if_nec=refresh_if_nec)
return guest.get_xml_config()
def _get_guest(self, inactive=False, refresh_if_nec=True):
xml = self._get_domain_xml(inactive, refresh_if_nec)
if inactive:
# If inactive XML requested, always return a fresh guest even
# the current Guest is inactive XML (like when the domain is
# stopped). Callers that request inactive are basically expecting
# a new copy.
return self._build_guest(xml)
return self._guest
get_guest_for_virtinst_func = _get_guest
def _build_guest(self, xml):
return virtinst.Guest(self.conn.get_backend(),
parsexml=xml)
def _reparse_xml(self, ignore=None):
try:
self._guest = self._build_guest(self._get_domain_xml())
except libvirt.libvirtError, e:
if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
return
raise
def get_guest_for_virtinst_func(self, *args, **kwargs):
return self._get_xmlobj(*args, **kwargs)
##############################
@ -465,10 +403,10 @@ class vmmDomain(vmmLibvirtObject):
# Rename
def define_name(self, newname):
# Do this, so that _guest_to_define has original inactive XML
# Do this, so that _xmlobj_to_define has original inactive XML
self._invalidate_xml()
guest = self._get_guest_to_define()
guest = self._get_xmlobj_to_define()
if guest.name == newname:
return
@ -494,7 +432,7 @@ class vmmDomain(vmmLibvirtObject):
"""
def change(guest):
guest.add_device(devobj)
ret = self._redefine_guest(change)
ret = self._redefine(change)
self.redefine_cached()
return ret
@ -518,7 +456,7 @@ class vmmDomain(vmmLibvirtObject):
guest.remove_device(editdev)
return self._redefine_device(rmdev, devobj)
ret = self._redefine_guest(change)
ret = self._redefine(change)
self.redefine_cached()
return ret
@ -527,11 +465,11 @@ class vmmDomain(vmmLibvirtObject):
def change(guest):
guest.curvcpus = int(vcpus)
guest.vcpus = int(maxvcpus)
return self._redefine_guest(change)
return self._redefine(change)
def define_cpuset(self, cpuset):
def change(guest):
guest.cpuset = cpuset
return self._redefine_guest(change)
return self._redefine(change)
def define_cpu_topology(self, sockets, cores, threads):
def change(guest):
@ -539,7 +477,7 @@ class vmmDomain(vmmLibvirtObject):
cpu.sockets = sockets
cpu.cores = cores
cpu.threads = threads
return self._redefine_guest(change)
return self._redefine(change)
def define_cpu(self, model, vendor, from_host, featurelist):
def change(guest):
if from_host:
@ -574,14 +512,14 @@ class vmmDomain(vmmLibvirtObject):
for fname, fpol in featurelist:
set_feature(fname, fpol)
return self._redefine_guest(change)
return self._redefine(change)
# Mem define methods
def define_both_mem(self, memory, maxmem):
def change(guest):
guest.memory = int(memory)
guest.maxmemory = int(maxmem)
return self._redefine_guest(change)
return self._redefine(change)
# Security define methods
def define_seclabel(self, model, t, label, relabel):
@ -601,53 +539,53 @@ class vmmDomain(vmmLibvirtObject):
if label:
seclabel.label = label
return self._redefine_guest(change)
return self._redefine(change)
# Machine config define methods
def define_acpi(self, newvalue):
def change(guest):
guest.features["acpi"] = newvalue
return self._redefine_guest(change)
return self._redefine(change)
def define_apic(self, newvalue):
def change(guest):
guest.features["apic"] = newvalue
return self._redefine_guest(change)
return self._redefine(change)
def define_clock(self, newvalue):
def change(guest):
guest.clock.offset = newvalue
return self._redefine_guest(change)
return self._redefine(change)
def define_machtype(self, newvalue):
def change(guest):
guest.os.machine = newvalue
return self._redefine_guest(change)
return self._redefine(change)
def define_description(self, newvalue):
def change(guest):
guest.description = newvalue or None
return self._redefine_guest(change)
return self._redefine(change)
# Boot define methods
def set_boot_device(self, boot_list):
def change(guest):
guest.os.bootorder = boot_list
return self._redefine_guest(change)
return self._redefine(change)
def set_boot_menu(self, newval):
def change(guest):
guest.os.enable_bootmenu = bool(newval)
return self._redefine_guest(change)
return self._redefine(change)
def set_boot_kernel(self, kernel, initrd, dtb, args):
def change(guest):
guest.os.kernel = kernel or None
guest.os.initrd = initrd or None
guest.os.dtb = dtb or None
guest.os.kernel_args = args or None
return self._redefine_guest(change)
return self._redefine(change)
def set_boot_init(self, init):
def change(guest):
guest.os.init = init
return self._redefine_guest(change)
return self._redefine(change)
# Disk define methods
def define_storage_media(self, devobj, newpath):
@ -782,7 +720,7 @@ class vmmDomain(vmmLibvirtObject):
if not apply_spice_defaults:
return
guest = self._get_guest_to_define()
guest = self._get_xmlobj_to_define()
is_spice = (newval == virtinst.VirtualGraphics.TYPE_SPICE)
if is_spice:
@ -852,7 +790,7 @@ class vmmDomain(vmmLibvirtObject):
def change(editdev):
ignore = editdev
guest = self._get_guest_to_define()
guest = self._get_xmlobj_to_define()
ctrls = guest.get_devices("controller")
ctrls = [x for x in ctrls if (x.type ==
virtinst.VirtualController.TYPE_USB)]
@ -1016,49 +954,49 @@ class vmmDomain(vmmLibvirtObject):
########################
def is_container(self):
return self._get_guest().os.is_container()
return self._get_xmlobj().os.is_container()
def is_xenpv(self):
return self._get_guest().os.is_xenpv()
return self._get_xmlobj().os.is_xenpv()
def is_hvm(self):
return self._get_guest().os.is_hvm()
return self._get_xmlobj().os.is_hvm()
def get_uuid(self):
return self.uuid
def get_abi_type(self):
return self._get_guest().os.os_type
return self._get_xmlobj().os.os_type
def get_hv_type(self):
return self._get_guest().type
return self._get_xmlobj().type
def get_pretty_hv_type(self):
return uihelpers.pretty_hv(self.get_abi_type(), self.get_hv_type())
def get_arch(self):
return self._get_guest().os.arch
return self._get_xmlobj().os.arch
def get_init(self):
return self._get_guest().os.init
return self._get_xmlobj().os.init
def get_emulator(self):
return self._get_guest().emulator
return self._get_xmlobj().emulator
def get_acpi(self):
return self._get_guest().features["acpi"]
return self._get_xmlobj().features["acpi"]
def get_apic(self):
return self._get_guest().features["apic"]
return self._get_xmlobj().features["apic"]
def get_clock(self):
return self._get_guest().clock.offset
return self._get_xmlobj().clock.offset
def get_machtype(self):
return self._get_guest().os.machine
return self._get_xmlobj().os.machine
def get_description(self):
# Always show the inactive <description>, let's us fake hotplug
# for a field that's strictly metadata
return self._get_guest(inactive=True).description
return self._get_xmlobj(inactive=True).description
def get_memory(self):
return int(self._get_guest().memory)
return int(self._get_xmlobj().memory)
def maximum_memory(self):
return int(self._get_guest().maxmemory)
return int(self._get_xmlobj().maxmemory)
def vcpu_count(self):
return int(self._get_guest().vcpus)
return int(self._get_xmlobj().vcpus)
def vcpu_max_count(self):
guest = self._get_guest()
guest = self._get_xmlobj()
has_xml_max = (guest.curvcpus != guest.vcpus)
if has_xml_max or not self.is_active():
return guest.vcpus
@ -1068,22 +1006,22 @@ class vmmDomain(vmmLibvirtObject):
return int(self._startup_vcpus)
def vcpu_pinning(self):
return self._get_guest().cpuset or ""
return self._get_xmlobj().cpuset or ""
def get_cpu_config(self):
return self._get_guest().cpu
return self._get_xmlobj().cpu
def get_boot_device(self):
return self._get_guest().os.bootorder
return self._get_xmlobj().os.bootorder
def get_boot_menu(self):
guest = self._get_guest()
guest = self._get_xmlobj()
return bool(guest.os.enable_bootmenu)
def get_boot_kernel_info(self):
guest = self._get_guest()
guest = self._get_xmlobj()
return (guest.os.kernel, guest.os.initrd,
guest.os.dtb, guest.os.kernel_args)
def get_seclabel(self):
seclabel = self._get_guest().seclabel
seclabel = self._get_xmlobj().seclabel
model = seclabel.model
t = seclabel.type or "dynamic"
label = seclabel.label or ""
@ -1109,7 +1047,7 @@ class vmmDomain(vmmLibvirtObject):
def _build_device_list(self, device_type,
refresh_if_nec=True, inactive=False):
guest = self._get_guest(refresh_if_nec=refresh_if_nec,
guest = self._get_xmlobj(refresh_if_nec=refresh_if_nec,
inactive=inactive)
devs = guest.get_devices(device_type)
@ -1835,9 +1773,9 @@ class vmmDomainVirtinst(vmmDomain):
def _XMLDesc(self, flags):
raise RuntimeError("Shouldn't be called")
def get_xml(self, inactive=False, refresh_if_nec=True):
ignore = inactive
ignore = refresh_if_nec
def get_xml(self, *args, **kwargs):
ignore = args
ignore = kwargs
xml = self._backend.get_install_xml(install=False)
if not self._orig_xml:
@ -1845,10 +1783,13 @@ class vmmDomainVirtinst(vmmDomain):
return xml
# Internal XML implementations
def _get_guest(self, inactive=False, refresh_if_nec=True):
def _get_xmlobj(self, inactive=False, refresh_if_nec=True):
# Make sure XML is up2date
self.get_xml()
return self._backend
def _reparse_xml(self, *args, **kwargs):
ignore = args
ignore = kwargs
def _define(self, newxml):
ignore = newxml
@ -1873,4 +1814,4 @@ class vmmDomainVirtinst(vmmDomain):
def define_name(self, newname):
def change(guest):
guest.name = str(newname)
return self._redefine_guest(change)
return self._redefine(change)

View File

@ -1212,8 +1212,8 @@ class vmmHost(vmmGObjectUI):
self.widget("interface-start").set_sensitive(not active)
show_child = (children or
itype in [Interface.Interface.INTERFACE_TYPE_BRIDGE,
Interface.Interface.INTERFACE_TYPE_BOND])
itype in [Interface.INTERFACE_TYPE_BRIDGE,
Interface.INTERFACE_TYPE_BOND])
self.widget("interface-child-box").set_visible(show_child)
self.populate_interface_children()

View File

@ -19,24 +19,20 @@
#
from virtinst import Interface
from virtinst import util
from virtManager.libvirtobject import vmmLibvirtObject
class vmmInterface(vmmLibvirtObject):
def __init__(self, conn, backend, key):
vmmLibvirtObject.__init__(self, conn, backend, key)
vmmLibvirtObject.__init__(self, conn, backend, key,
parseclass=Interface)
self._name = key
self._active = True
self._xml = None
self._xml_flags = None
(self._inactive_xml_flags,
self._active_xml_flags) = self.conn.get_interface_flags(
self._backend)
self._active_xml_flags) = self.conn.get_interface_flags(self._backend)
self._support_isactive = None
@ -49,17 +45,6 @@ class vmmInterface(vmmLibvirtObject):
def _define(self, xml):
return self.conn.define_interface(xml)
def xpath(self, *args, **kwargs):
# Must use this function for ALL XML parsing
ret = util.xpath(self.get_xml(), *args, **kwargs)
if ret:
return ret
if not self.is_active():
return ret
# The running config did not have the info requested
return util.xpath(self.get_xml(inactive=True), *args, **kwargs)
def set_active(self, state):
if state == self._active:
return
@ -89,7 +74,7 @@ class vmmInterface(vmmLibvirtObject):
return self._name
def get_mac(self):
return self.xpath("/interface/mac/@address")
return self._get_xmlobj().macaddr
def _kick_conn(self):
self.conn.schedule_priority_tick(polliface=True)
@ -113,12 +98,12 @@ class vmmInterface(vmmLibvirtObject):
return typ == "bridge"
def get_type(self):
return self.xpath("/interface/@type")
return self._get_xmlobj().type
def get_pretty_type(self):
itype = self.get_type()
if itype == Interface.Interface.INTERFACE_TYPE_VLAN:
if itype == Interface.INTERFACE_TYPE_VLAN:
return "VLAN"
elif itype:
return str(itype).capitalize()
@ -126,124 +111,57 @@ class vmmInterface(vmmLibvirtObject):
return "Interface"
def get_startmode(self):
return self.xpath("/interface/start/@mode") or "none"
return self._get_xmlobj().start_mode or "none"
def set_startmode(self, newmode):
def set_start_xml(doc, ctx):
node = ctx.xpathEval("/interface/start[1]")
node = (node and node[0] or None)
iface_node = ctx.xpathEval("/interface")[0]
if not node:
node = iface_node.newChild(None, "start", None)
node.setProp("mode", newmode)
return doc.serialize()
self._redefine(util.xml_parse_wrapper, set_start_xml)
def change(obj):
obj.start_mode = newmode
self._redefine(change)
self.redefine_cached()
def get_slaves(self):
typ = self.get_type()
xpath = "/interface/%s/interface/@name" % typ
def node_func(ctx):
nodes = ctx.xpathEval(xpath)
names = [x.content for x in nodes]
ret = []
for name in names:
type_path = ("/interface/%s/interface[@name='%s']/@type" %
(typ, name))
nodes = ctx.xpathEval(type_path)
ret.append((name, nodes and nodes[0].content or "Unknown"))
return ret
ret = self.xpath(func=node_func)
if not ret:
return []
return ret
return [[obj.name, obj.type or "Unknown"] for obj in
self._get_xmlobj().interfaces]
def get_slave_names(self):
# Returns a list of names of all enslaved interfaces
return [x[0] for x in self.get_slaves()]
def _get_ip(self, iptype):
obj = self._get_xmlobj()
found = None
for protocol in obj.protocols:
if protocol.family == iptype:
found = protocol
break
if not found:
return None, []
ret = []
for ip in found.ips:
ipstr = ip.address
if not ipstr:
continue
if ip.prefix:
ipstr += "/%s" % ip.prefix
ret.append(ipstr)
return found, ret
def get_ipv4(self):
base_xpath = "/interface/protocol[@family='ipv4']"
if not self.xpath(base_xpath):
proto, ips = self._get_ip("ipv4")
if proto is None:
return []
dhcp = bool(self.xpath("count(%s/dhcp)" % base_xpath))
addr = self.xpath(base_xpath + "/ip/@address")
if addr:
prefix = self.xpath(base_xpath + "/ip[@address='%s']/@prefix" %
addr)
if prefix:
addr += "/%s" % prefix
return [dhcp, addr]
ipstr = None
if ips:
ipstr = ips[0]
return [proto.dhcp, ipstr]
def get_ipv6(self):
base_xpath = "/interface/protocol[@family='ipv6']"
if not self.xpath(base_xpath):
proto, ips = self._get_ip("ipv6")
if proto is None:
return []
dhcp = bool(self.xpath("count(%s/dhcp)" % base_xpath))
autoconf = bool(self.xpath("count(%s/autoconf)" % base_xpath))
def addr_func(ctx):
nodes = ctx.xpathEval(base_xpath + "/ip")
nodes = nodes or []
ret = []
for node in nodes:
addr = node.prop("address")
pref = node.prop("prefix")
if not addr:
continue
if pref:
addr += "/%s" % pref
ret.append(addr)
return ret
ret = self.xpath(func=addr_func)
return [dhcp, autoconf, ret]
return [proto.dhcp, proto.autoconf, ips]
def get_protocol_xml(self):
def protocol(ctx):
node = ctx.xpathEval("/interface/protocol")
node = node and node[0] or None
ret = None
if node:
ret = node.serialize()
return ret
ret = self.xpath(func=protocol)
if ret:
ret = " %s\n" % ret
return ret
def _redefine(self, xml_func, *args):
"""
Helper function for altering a redefining VM xml
@param xml_func: Function to alter the running XML. Takes the
original XML as its first argument.
@param args: Extra arguments to pass to xml_func
"""
origxml = self._xml_to_redefine()
# Sanitize origxml to be similar to what we will get back
origxml = util.xml_parse_wrapper(origxml, lambda d, c: d.serialize())
newxml = xml_func(origxml, *args)
self._redefine_xml(newxml)
return self._get_xmlobj().protocols[:]

View File

@ -47,19 +47,25 @@ class vmmLibvirtObject(vmmGObject):
"stopped": (GObject.SignalFlags.RUN_FIRST, None, []),
}
def __init__(self, conn, backend, key):
def __init__(self, conn, backend, key, parseclass=None):
vmmGObject.__init__(self)
self._conn = conn
self._backend = backend
self._key = key
self._parseclass = parseclass
self._xml = None
self._is_xml_valid = False
self._xmlobj = None
self._xmlobj_to_define = None
# These should be set by the child classes if necessary
self._inactive_xml_flags = 0
self._active_xml_flags = 0
self.connect("config-changed", self._reparse_xml)
def _cleanup(self):
pass
@ -91,27 +97,13 @@ class vmmLibvirtObject(vmmGObject):
# Public XML API #
##################
def get_xml(self, inactive=False, refresh_if_nec=True):
def get_xml(self, *args, **kwargs):
"""
Get domain xml. If cached xml is invalid, update.
@param inactive: Return persistent XML, not the running config.
No effect if domain is not running. Use this flag
if the XML will be used for redefining a guest
@param refresh_if_nec: Check if XML is out of date, and if so,
refresh it (default behavior). Skipping a refresh is
useful to prevent updating xml in the tick loop when
it's not that important (disk/net stats)
See _get_raw_xml for parameter docs
"""
if inactive:
return self._XMLDesc(self._inactive_xml_flags)
if self._xml is None:
self.refresh_xml()
elif refresh_if_nec and not self._is_xml_valid:
self.refresh_xml()
return self._xml
if self._parseclass:
return self._get_xmlobj(*args, **kwargs).get_xml_config()
return self._get_raw_xml(*args, **kwargs)
def refresh_xml(self, forcesignal=False):
# Force an xml update. Signal 'config-changed' if domain xml has
@ -133,15 +125,74 @@ class vmmLibvirtObject(vmmGObject):
def _invalidate_xml(self):
# Mark cached xml as invalid
self._is_xml_valid = False
self._xmlobj_to_define = None
##########################
# Internal API functions #
##########################
def _get_raw_xml(self, inactive=False, refresh_if_nec=True):
"""
Get object xml. If cached xml is invalid, update.
@param inactive: Return persistent XML, not the running config.
No effect if domain is not running. Use this flag
if the XML will be used for redefining a guest
@param refresh_if_nec: Check if XML is out of date, and if so,
refresh it (default behavior). Skipping a refresh is
useful to prevent updating xml in the tick loop when
it's not that important (disk/net stats)
"""
if inactive:
return self._XMLDesc(self._inactive_xml_flags)
if self._xml is None:
self.refresh_xml()
elif refresh_if_nec and not self._is_xml_valid:
self.refresh_xml()
return self._xml
def _get_xmlobj(self, inactive=False, refresh_if_nec=True):
xml = self._get_raw_xml(inactive, refresh_if_nec)
if inactive:
# If inactive XML requested, always return a fresh object even
# the current object is inactive XML (like when the domain is
# stopped). Callers that request inactive are basically expecting
# a new copy.
return self._build_xmlobj(xml)
if not self._xmlobj:
self._reparse_xml()
return self._xmlobj
def _xml_to_redefine(self):
return _sanitize_xml(self.get_xml(inactive=True))
def redefine_cached(self):
if not self._xmlobj_to_define:
logging.debug("No cached XML to define, skipping.")
return
obj = self._get_xmlobj_to_define()
xml = obj.get_xml_config()
self._redefine_xml(xml)
def _reparse_xml(self, ignore=None):
if not self._parseclass:
return
self._xmlobj = self._build_xmlobj(self._get_raw_xml())
def _build_xmlobj(self, xml):
return self._parseclass(self.conn.get_backend(), parsexml=xml)
def _get_xmlobj_to_define(self):
if not self._xmlobj_to_define:
self._xmlobj_to_define = self._get_xmlobj(inactive=True)
return self._xmlobj_to_define
def _redefine_helper(self, origxml, newxml):
origxml = _sanitize_xml(origxml)
newxml = _sanitize_xml(newxml)
@ -164,3 +215,7 @@ class vmmLibvirtObject(vmmGObject):
def _redefine_xml(self, newxml):
origxml = self._xml_to_redefine()
return self._redefine_helper(origxml, newxml)
def _redefine(self, cb):
guest = self._get_xmlobj_to_define()
return cb(guest)

View File

@ -177,7 +177,7 @@ class vmmSnapshotPage(vmmGObjectUI):
do_select = None
for snap in snapshots:
desc = snap.xml.description
desc = snap.xmlobj.description
if not uihelpers.can_set_row_none:
desc = desc or ""
@ -202,12 +202,12 @@ class vmmSnapshotPage(vmmGObjectUI):
self.widget("snapshot-notebook").set_current_page(0)
name = snap and snap.get_name() or ""
desc = snap and snap.xml.description or ""
state = snap and snap.xml.state or "shutoff"
desc = snap and snap.xmlobj.description or ""
state = snap and snap.xmlobj.state or "shutoff"
timestamp = ""
if snap:
timestamp = str(datetime.datetime.fromtimestamp(
snap.xml.creationTime))
snap.xmlobj.creationTime))
current = ""
if snap and snap.is_current():
@ -253,8 +253,8 @@ class vmmSnapshotPage(vmmGObjectUI):
desc_widget = self.widget("snapshot-description")
desc = desc_widget.get_buffer().get_property("text") or ""
snap.xml.description = desc
newxml = snap.xml.get_xml_config()
snap.xmlobj.description = desc
newxml = snap.xmlobj.get_xml_config()
self.vm.create_snapshot(newxml, redefine=True)
snap.refresh_xml()
self._set_snapshot_state(snap)

View File

@ -32,7 +32,7 @@ from virtinst.seclabel import Seclabel
import virtinst.storage as Storage
import virtinst.nodedev as NodeDeviceParser
import virtinst.capabilities as CapabilitiesParser
import virtinst.interface as Interface
from virtinst.interface import Interface, InterfaceProtocol
from virtinst.device import VirtualDevice
from virtinst.deviceinterface import VirtualNetworkInterface

View File

@ -20,14 +20,55 @@
Classes for building and installing libvirt interface xml
"""
import libvirt
import logging
import libvirt
from virtinst import util
from virtinst.xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
class Interface(object):
class _IPAddress(XMLBuilder):
_XML_PROP_ORDER = ["address", "prefix"]
_XML_ROOT_NAME = "ip"
address = XMLProperty("./@address")
prefix = XMLProperty("./@prefix", is_int=True)
class InterfaceProtocol(XMLBuilder):
INTERFACE_PROTOCOL_FAMILY_IPV4 = "ipv4"
INTERFACE_PROTOCOL_FAMILY_IPV6 = "ipv6"
INTERFACE_PROTOCOL_FAMILIES = [INTERFACE_PROTOCOL_FAMILY_IPV4,
INTERFACE_PROTOCOL_FAMILY_IPV6]
_XML_ROOT_NAME = "protocol"
_XML_PROP_ORDER = ["autoconf", "dhcp", "dhcp_peerdns", "ips", "gateway"]
family = XMLProperty("./@family")
dhcp = XMLProperty("./dhcp", is_bool=True, doc=_("Whether to enable DHCP"))
dhcp_peerdns = XMLProperty("./dhcp/@peerdns", is_yesno=True)
gateway = XMLProperty("./route/@gateway", doc=_("Network gateway address"))
autoconf = XMLProperty("./autoconf", is_bool=True,
doc=_("Whether to enable IPv6 autoconfiguration"))
#####################
# IP child handling #
#####################
def add_ip(self, addr, prefix=None):
ip = _IPAddress(self.conn)
ip.address = addr
ip.prefix = prefix
self._add_child(ip)
def remove_ip(self, ip):
self._remove_child(ip)
ip.clear()
ips = XMLChildProperty(_IPAddress)
class Interface(XMLBuilder):
"""
Base class for building any libvirt interface object.
@ -48,22 +89,20 @@ class Interface(object):
INTERFACE_START_MODE_ONBOOT,
INTERFACE_START_MODE_HOTPLUG]
@staticmethod
def interface_class_for_type(interface_type):
if interface_type not in Interface.INTERFACE_TYPES:
raise ValueError("Unknown interface type '%s'" % interface_type)
INTERFACE_BOND_MODES = ["active-backup", "balance-alb", "balance-rr",
"balance-tlb", "balance-xor", "broadcast",
"802.3ad"]
INTERFACE_BOND_MONITOR_MODE_ARP = "arpmon"
INTERFACE_BOND_MONITOR_MODE_MII = "miimon"
INTERFACE_BOND_MONITOR_MODES = [INTERFACE_BOND_MONITOR_MODE_ARP,
INTERFACE_BOND_MONITOR_MODE_MII]
INTERFACE_BOND_MONITOR_MODE_ARP_VALIDATE_MODES = ["active", "backup",
"all"]
INTERFACE_BOND_MONITOR_MODE_MII_CARRIER_TYPES = ["netif", "ioctl"]
if interface_type == Interface.INTERFACE_TYPE_BRIDGE:
return InterfaceBridge
elif interface_type == Interface.INTERFACE_TYPE_BOND:
return InterfaceBond
elif interface_type == Interface.INTERFACE_TYPE_ETHERNET:
return InterfaceEthernet
elif interface_type == Interface.INTERFACE_TYPE_VLAN:
return InterfaceVLAN
else:
raise ValueError("No class for interface type '%s'" %
interface_type)
@staticmethod
def find_free_name(conn, prefix):
@ -73,92 +112,41 @@ class Interface(object):
etc.
"""
return util.generate_name(prefix, conn.interfaceLookupByName, sep="",
force_num=True)
force_num=True)
def __init__(self, conn, object_type, name):
"""
Initialize object parameters
"""
if object_type not in self.INTERFACE_TYPES:
raise ValueError("Unknown interface object type: %s" %
object_type)
_XML_ROOT_NAME = "interface"
_XML_PROP_ORDER = ["type", "name", "start_mode", "macaddr", "mtu",
"stp", "delay", "bond_mode", "arp_interval",
"arp_target", "arp_validate_mode", "mii_frequency",
"mii_downdelay", "mii_updelay", "mii_carrier_mode",
"tag", "parent_interface",
"protocols", "interfaces"]
self._object_type = object_type
self._conn = conn
self._name = None
self._mtu = None
self._macaddr = None
self._start_mode = None
self._protocols = []
self._protocol_xml = None
##################
# Child handling #
##################
self.name = name
def add_interface(self, obj):
self._add_child(obj)
def remove_interface(self, obj):
self._remove_child(obj)
# 'interfaces' property is added outside this class, since it needs
# to reference the completed Interface class
# Initialize all optional properties
self._perms = None
def add_protocol(self, obj):
self._add_child(obj)
def remove_protocol(self, obj):
self._remove_child(obj)
protocols = XMLChildProperty(InterfaceProtocol)
## Properties
def _get_object_type(self):
return self._object_type
object_type = property(_get_object_type)
######################
# Validation helpers #
######################
def _get_conn(self):
return self._conn
conn = property(_get_conn)
def _get_name(self):
return self._name
def _set_name(self, val):
util.validate_name(_("Interface name"), val)
self._check_name_collision(val)
self._name = val
name = property(_get_name, _set_name,
doc=_("Name for the interface object."))
def _get_mtu(self):
return self._mtu
def _set_mtu(self, val):
self._mtu = val
mtu = property(_get_mtu, _set_mtu,
doc=_("Maximum transmit size in bytes"))
def _get_macaddr(self):
return self._macaddr
def _set_macaddr(self, val):
util.validate_macaddr(val)
self._macaddr = val
macaddr = property(_get_macaddr, _set_macaddr,
doc=_("Interface MAC address"))
def _get_start_mode(self):
return self._start_mode
def _set_start_mode(self, val):
if val not in self.INTERFACE_START_MODES:
raise ValueError(_("Unknown start mode '%s") % val)
self._start_mode = val
start_mode = property(_get_start_mode, _set_start_mode,
doc=_("When the interface will be auto-started."))
def _get_protocols(self):
return self._protocols
def _set_protocols(self, val):
self._protocols = val
protocols = property(_get_protocols, _set_protocols,
doc=_("Network protocol configuration"))
def _get_protocol_xml_attr(self):
return self._protocol_xml
def _set_protocol_xml_attr(self, val):
self._protocol_xml = val
protocol_xml = property(_get_protocol_xml_attr, _set_protocol_xml_attr,
doc="String of XML to use in place of "
"generated protocol XML. This can be "
"parsed from an existing interface for "
"example.")
def _check_name_collision(self, name):
def _validate_name(self, name):
if name == self.name:
return
try:
self.conn.interfaceLookupByName(name)
except libvirt.libvirtError:
@ -167,52 +155,84 @@ class Interface(object):
raise ValueError(_("Name '%s' already in use by another interface.") %
name)
# XML Building
def _get_protocol_xml(self):
"""
Returns IP protocol XML
"""
if self.protocol_xml is not None:
return self.protocol_xml
xml = ""
for p in self.protocols:
xml += p.get_xml_config()
return xml
def _get_interface_xml(self):
"""
Returns the bridge/bond/... specific xml blob
"""
raise NotImplementedError("Must be implemented in subclass")
def get_xml_config(self):
"""
Construct the xml description of the interface object
@returns: xml description
@rtype: C{str}
"""
xml = ""
def _validate_mac(self, val):
util.validate_macaddr(val)
return val
xml += "<interface type='%s' name='%s'>\n""" % (self.object_type,
self.name)
##################
# General params #
##################
if self.start_mode:
xml += " <start mode='%s'/>\n" % self.start_mode
type = XMLProperty("./@type")
mtu = XMLProperty("./mtu/@size", is_int=True,
doc=_("Maximum transmit size in bytes"))
start_mode = XMLProperty("./start/@mode",
doc=_("When the interface will be auto-started."))
if self.macaddr:
xml += " <mac address='%s'/>\n" % self.macaddr
name = XMLProperty("./@name", validate_cb=_validate_name,
doc=_("Name for the interface object."))
if self.mtu is not None:
xml += " <mtu size='%s'/>\n" % str(self.mtu)
macaddr = XMLProperty("./mac/@address", validate_cb=_validate_mac,
doc=_("Interface MAC address"))
xml += self._get_protocol_xml()
xml += self._get_interface_xml()
xml += "</interface>\n"
#################
# Bridge params #
#################
return xml
stp = XMLProperty("./bridge/@stp", is_onoff=True,
doc=_("Whether STP is enabled on the bridge"))
delay = XMLProperty("./bridge/@delay",
doc=_("Delay in seconds before forwarding begins when "
"joining a network."))
###############
# Bond params #
###############
bond_mode = XMLProperty("./bond/@mode",
doc=_("Mode of operation of the bonding device"))
arp_interval = XMLProperty("./bond/arpmon/@interval", is_int=True,
doc=_("ARP monitoring interval in "
"milliseconds"))
arp_target = XMLProperty("./bond/arpmon/@target",
doc=_("IP target used in ARP monitoring packets"))
arp_validate_mode = XMLProperty("./bond/arpmon/@validate",
doc=_("ARP monitor validation mode"))
mii_carrier_mode = XMLProperty("./bond/miimon/@carrier",
doc=_("MII monitoring method."))
mii_frequency = XMLProperty("./bond/miimon/@freq", is_int=True,
doc=_("MII monitoring interval in "
"milliseconds"))
mii_updelay = XMLProperty("./bond/miimon/@updelay", is_int=True,
doc=_("Time in milliseconds to wait before "
"enabling a slave after link recovery "))
mii_downdelay = XMLProperty("./bond/miimon/@downdelay", is_int=True,
doc=_("Time in milliseconds to wait before "
"disabling a slave after link failure"))
###############
# VLAN params #
###############
tag = XMLProperty("./vlan/@tag", is_int=True,
doc=_("VLAN device tag number"))
parent_interface = XMLProperty("./vlan/interface/@name",
doc=_("Parent interface to create VLAN on"))
##################
# Build routines #
##################
def validate(self):
if (self.type == self.INTERFACE_TYPE_VLAN and
(self.tag is None or self.parent_interface is None)):
raise ValueError(_("VLAN Tag and parent interface are required."))
def install(self, meter=None, create=True):
"""
@ -245,484 +265,5 @@ class Interface(object):
return iface
class _InterfaceCompound(Interface):
"""
Class representing an interface which can have child interfaces
"""
def __init__(self, conn, interface_type, name):
Interface.__init__(self, conn, interface_type, name)
self._interfaces = []
def _get_interfaces(self):
return self._interfaces
def _set_interfaces(self, val):
if val is not None:
if type(val) is not list:
raise ValueError("Interfaces must be a list or None")
for i in val:
if type(i) is str:
# Assume this is a plain ethernet name
continue
if not isinstance(i, libvirt.virInterface):
raise ValueError("List members must be virInterface "
"instances, not %s" % type(i))
self._interfaces = val
interfaces = property(_get_interfaces, _set_interfaces)
def _indent_xml(self, xml, indent_size):
newxml = ""
for line in xml.split("\n"):
if line:
line = (" " * indent_size) + line + "\n"
newxml += line
return newxml
def _get_child_interface_xml(self):
xml = ""
for i in self.interfaces:
if type(i) is str:
iface_xml = " <interface name='%s' type='ethernet'/>\n" % i
else:
iface_xml = self._indent_xml(i.XMLDesc(0), 4)
xml += iface_xml
return xml
def _get_interface_xml(self):
raise NotImplementedError("Must be implemented in subclass")
class InterfaceBridge(_InterfaceCompound):
"""
Class for building and installing libvirt interface bridge xml
"""
def __init__(self, conn, name):
_InterfaceCompound.__init__(self, conn,
Interface.INTERFACE_TYPE_BRIDGE, name)
self._stp = None
self._delay = None
def _get_stp(self):
return self._stp
def _set_stp(self, val):
if type(val) is not bool:
raise ValueError("STP must be a bool value")
self._stp = val
stp = property(_get_stp, _set_stp,
doc=_("Whether STP is enabled on the bridge"))
def _get_delay(self):
return self._delay
def _set_delay(self, val):
self._delay = val
delay = property(_get_delay, _set_delay,
doc=_("Delay in seconds before forwarding begins when "
"joining a network."))
def _get_interface_xml(self):
xml = " <bridge"
if self.stp is not None:
xml += " stp='%s'" % (self.stp and "on" or "off")
if self.delay is not None:
xml += " delay='%s'" % str(self.delay)
xml += ">\n"
xml += self._get_child_interface_xml()
xml += " </bridge>\n"
return xml
class InterfaceBond(_InterfaceCompound):
"""
Class for building and installing libvirt interface bond xml
"""
INTERFACE_BOND_MODES = ["active-backup", "balance-alb", "balance-rr",
"balance-tlb", "balance-xor", "broadcast",
"802.3ad"]
INTERFACE_BOND_MONITOR_MODE_ARP = "arpmon"
INTERFACE_BOND_MONITOR_MODE_MII = "miimon"
INTERFACE_BOND_MONITOR_MODES = [INTERFACE_BOND_MONITOR_MODE_ARP,
INTERFACE_BOND_MONITOR_MODE_MII]
INTERFACE_BOND_MONITOR_MODE_ARP_VALIDATE_MODES = ["active", "backup",
"all"]
INTERFACE_BOND_MONITOR_MODE_MII_CARRIER_TYPES = ["netif", "ioctl"]
def __init__(self, conn, name):
_InterfaceCompound.__init__(self, conn,
Interface.INTERFACE_TYPE_BOND, name)
self._bond_mode = None
self._monitor_mode = None
# ARP values
self._arp_interval = None
self._arp_target = None
self._arp_validate_mode = None
# MII values
self._mii_frequency = None
self._mii_updelay = None
self._mii_downdelay = None
self._mii_carrier_mode = None
def _get_bond_mode(self):
return self._bond_mode
def _set_bond_mode(self, val):
if val is None:
self._bond_mode = None
return
self._bond_mode = val
bond_mode = property(_get_bond_mode, _set_bond_mode,
doc=_("Mode of operation of the bonding device"))
def _get_monitor_mode(self):
return self._monitor_mode
def _set_monitor_mode(self, val):
if val is None:
self._monitor_mode = None
return
self._monitor_mode = val
monitor_mode = property(_get_monitor_mode, _set_monitor_mode,
doc=_("Availability monitoring mode for the bond "
"device"))
# ARP props
def _get_arp_interval(self):
return self._arp_interval
def _set_arp_interval(self, val):
self._arp_interval = val
arp_interval = property(_get_arp_interval, _set_arp_interval,
doc=_("ARP monitoring interval in milliseconds"))
def _get_arp_target(self):
return self._arp_target
def _set_arp_target(self, val):
self._arp_target = val
arp_target = property(_get_arp_target, _set_arp_target,
doc=_("IP target used in ARP monitoring packets"))
def _get_arp_validate_mode(self):
return self._arp_validate_mode
def _set_arp_validate_mode(self, val):
self._arp_validate_mode = val
arp_validate_mode = property(_get_arp_validate_mode,
_set_arp_validate_mode,
doc=_("ARP monitor validation mode"))
# MII props
def _get_mii_carrier_mode(self):
return self._mii_carrier_mode
def _set_mii_carrier_mode(self, val):
self._mii_carrier_mode = val
mii_carrier_mode = property(_get_mii_carrier_mode, _set_mii_carrier_mode,
doc=_("MII monitoring method."))
def _get_mii_frequency(self):
return self._mii_frequency
def _set_mii_frequency(self, val):
self._mii_frequency = val
mii_frequency = property(_get_mii_frequency, _set_mii_frequency,
doc=_("MII monitoring interval in milliseconds"))
def _get_mii_updelay(self):
return self._mii_updelay
def _set_mii_updelay(self, val):
self._mii_updelay = val
mii_updelay = property(_get_mii_updelay, _set_mii_updelay,
doc=_("Time in milliseconds to wait before "
"enabling a slave after link recovery "))
def _get_mii_downdelay(self):
return self._mii_downdelay
def _set_mii_downdelay(self, val):
self._mii_downdelay = val
mii_downdelay = property(_get_mii_downdelay, _set_mii_downdelay,
doc=_("Time in milliseconds to wait before "
"disabling a slave after link failure"))
# XML Building methods
def _get_monitor_xml(self):
mode_xml = ""
if self.monitor_mode == self.INTERFACE_BOND_MONITOR_MODE_ARP:
mode_xml = " <arpmon"
if self.arp_interval is not None:
mode_xml += " interval='%s'" % str(self.arp_interval)
if self.arp_target is not None:
mode_xml += " target='%s'" % str(self.arp_target)
if self.arp_validate_mode is not None:
mode_xml += " validate='%s'" % str(self.arp_validate_mode)
mode_xml += "/>\n"
elif self.monitor_mode == self.INTERFACE_BOND_MONITOR_MODE_MII:
mode_xml = " <miimon"
if self.mii_frequency is not None:
mode_xml += " freq='%s'" % str(self.mii_frequency)
if self.mii_downdelay is not None:
mode_xml += " downdelay='%s'" % str(self.mii_downdelay)
if self.mii_updelay is not None:
mode_xml += " updelay='%s'" % str(self.mii_updelay)
if self.mii_carrier_mode is not None:
mode_xml += " carrier='%s'" % str(self.mii_carrier_mode)
mode_xml += "/>\n"
return mode_xml
def _get_interface_xml(self):
xml = ""
xml += " <bond"
if self.bond_mode:
xml += " mode='%s'" % self.bond_mode
xml += ">\n"
xml += self._get_monitor_xml()
xml += self._get_child_interface_xml()
xml += " </bond>\n"
return xml
class InterfaceEthernet(Interface):
"""
Class for building and installing libvirt interface ethernet xml
"""
def __init__(self, conn, name):
Interface.__init__(self, conn,
Interface.INTERFACE_TYPE_ETHERNET, name)
def _get_interface_xml(self):
# No ethernet specific XML
return ""
class InterfaceVLAN(Interface):
"""
Class for building and installing libvirt interface vlan xml
"""
def __init__(self, conn, name):
Interface.__init__(self, conn,
Interface.INTERFACE_TYPE_VLAN, name)
self._tag = None
self._parent_interface = None
def _get_tag(self):
return self._tag
def _set_tag(self, val):
self._tag = val
tag = property(_get_tag, _set_tag,
doc=_("VLAN device tag number"))
def _get_parent_interface(self):
return self._parent_interface
def _set_parent_interface(self, val):
if (type(val) is not str and
not isinstance(val, libvirt.virInterface)):
raise ValueError("VLAN parent interface must be a virInterface "
"instance or string, not '%s'" % val)
self._parent_interface = val
parent_interface = property(_get_parent_interface,
_set_parent_interface,
doc=_("Parent interface to create VLAN on"))
def _get_interface_xml(self):
if self.tag is None or self.parent_interface is None:
raise ValueError(_("Tag and parent interface are required."))
if type(self.parent_interface) is str:
name = self.parent_interface
else:
name = self.parent_interface.name()
xml = " <vlan tag='%s'>\n" % self.tag
xml += " <interface name='%s'/>\n" % name
xml += " </vlan>\n"
return xml
class InterfaceProtocol(object):
INTERFACE_PROTOCOL_FAMILY_IPV4 = "ipv4"
INTERFACE_PROTOCOL_FAMILY_IPV6 = "ipv6"
INTERFACE_PROTOCOL_FAMILIES = [INTERFACE_PROTOCOL_FAMILY_IPV4,
INTERFACE_PROTOCOL_FAMILY_IPV6]
@staticmethod
def protocol_class_for_family(family):
if family not in InterfaceProtocol.INTERFACE_PROTOCOL_FAMILIES:
raise ValueError("Unknown interface protocol family '%s'" %
family)
if family == InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV4:
return InterfaceProtocolIPv4
elif family == InterfaceProtocol.INTERFACE_PROTOCOL_FAMILY_IPV6:
return InterfaceProtocolIPv6
def __init__(self, family):
if family not in InterfaceProtocol.INTERFACE_PROTOCOL_FAMILIES:
raise ValueError("Unknown interface protocol family '%s'" %
family)
self._family = family
def _get_family(self):
return self._family
family = property(_get_family)
def _get_protocol_xml(self):
raise NotImplementedError("Must be implemented in subclass")
def get_xml_config(self):
xml = ""
xml += " <protocol family='%s'>\n" % self.family
xml += self._get_protocol_xml()
xml += " </protocol>\n"
return xml
class InterfaceProtocolIP(InterfaceProtocol):
def __init__(self, family):
InterfaceProtocol.__init__(self, family)
self._autoconf = False
self._dhcp = False
self._dhcp_peerdns = None
self._ips = []
self._gateway = None
def _get_dhcp(self):
return self._dhcp
def _set_dhcp(self, val):
self._dhcp = val
dhcp = property(_get_dhcp, _set_dhcp,
doc=_("Whether to enable DHCP"))
def _get_dhcp_peerdns(self):
return self._dhcp_peerdns
def _set_dhcp_peerdns(self, val):
self._dhcp_peerdns = val
dhcp_peerdns = property(_get_dhcp_peerdns, _set_dhcp_peerdns)
def _get_gateway(self):
return self._gateway
def _set_gateway(self, val):
self._gateway = val
gateway = property(_get_gateway, _set_gateway,
doc=_("Network gateway address"))
def _get_ips(self):
return self._ips
def _set_ips(self, val):
self._ips = val
ips = property(_get_ips, _set_ips,
doc=_("Static IP addresses"))
def _get_protocol_xml(self):
raise NotImplementedError("Must be implemented in subclass")
def _get_ip_xml(self):
xml = ""
if self.dhcp:
xml += " <dhcp"
if self.dhcp_peerdns is not None:
xml += " peerdns='%s'" % (bool(self.dhcp_peerdns) and "yes"
or "no")
xml += "/>\n"
for ip in self.ips:
xml += ip.get_xml_config()
if self.gateway:
xml += " <route gateway='%s'/>\n" % self.gateway
return xml
class InterfaceProtocolIPv4(InterfaceProtocolIP):
def __init__(self):
InterfaceProtocolIP.__init__(self, self.INTERFACE_PROTOCOL_FAMILY_IPV4)
def _get_protocol_xml(self):
return self._get_ip_xml()
class InterfaceProtocolIPv6(InterfaceProtocolIP):
def __init__(self):
InterfaceProtocolIP.__init__(self, self.INTERFACE_PROTOCOL_FAMILY_IPV6)
self._autoconf = False
def _get_autoconf(self):
return self._autoconf
def _set_autoconf(self, val):
self._autoconf = bool(val)
autoconf = property(_get_autoconf, _set_autoconf,
doc=_("Whether to enable IPv6 autoconfiguration"))
def _get_protocol_xml(self):
xml = ""
if self.autoconf:
xml += " <autoconf/>\n"
xml += self._get_ip_xml()
return xml
class InterfaceProtocolIPAddress(object):
def __init__(self, address, prefix=None):
self._address = address
self._prefix = prefix
def _get_prefix(self):
return self._prefix
def _set_prefix(self, val):
self._prefix = val
prefix = property(_get_prefix, _set_prefix,
doc=_("IPv6 address prefix"))
def _get_address(self):
return self._address
def _set_address(self, val):
self._address = val
address = property(_get_address, _set_address,
doc=_("IP address"))
def get_xml_config(self):
xml = " <ip address='%s'" % self.address
if self.prefix is not None:
xml += " prefix='%s'" % self.prefix
xml += "/>\n"
return xml
Interface.interfaces = XMLChildProperty(Interface,
relative_xpath="./%(type)s")

View File

@ -955,7 +955,8 @@ class XMLBuilder(object):
if not obj._xmlstate.is_build:
use_xpath = obj.get_root_xpath().rsplit("/", 1)[0]
newnode = libxml2.parseDoc(xml).children
indent = 2 * obj.get_root_xpath().count("/")
newnode = libxml2.parseDoc(_indent(xml, indent)).children
_build_xpath_node(self._xmlstate.xml_ctx, use_xpath, newnode)
obj._xmlstate._parse(None, self._xmlstate.xml_node)