diff --git a/virtinst/interface.py b/virtinst/interface.py index 24b84d72..f56bfd80 100644 --- a/virtinst/interface.py +++ b/virtinst/interface.py @@ -63,6 +63,18 @@ class InterfaceProtocol(XMLBuilder): ips = XMLChildProperty(_IPAddress) +class _BondConfig(XMLBuilder): + _XML_ROOT_NAME = "bond" + + +class _BridgeConfig(XMLBuilder): + _XML_ROOT_NAME = "bridge" + + +class _VLANConfig(XMLBuilder): + _XML_ROOT_NAME = "vlan" + + class Interface(XMLBuilder): """ Base class for building any libvirt interface object. @@ -115,24 +127,30 @@ class Interface(XMLBuilder): "arp_target", "arp_validate_mode", "mii_frequency", "mii_downdelay", "mii_updelay", "mii_carrier_mode", "tag", "parent_interface", - "protocols", "interfaces"] + "protocols", "_bond", "_bridge", "_vlan"] - ################## - # Child handling # - ################## + ###################### + # Interface handling # + ###################### + + # The recursive nature of nested interfaces complicates things here, + # which is why this is strange. See bottom of the file for more + # weirdness + + _bond = XMLChildProperty(_BondConfig, is_single=True) + _bridge = XMLChildProperty(_BridgeConfig, is_single=True) + _vlan = XMLChildProperty(_VLANConfig, is_single=True) def add_interface(self, obj): - self.add_child(obj) + getattr(self, "_" + self.type).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 + getattr(self, "_" + self.type).remove_child(obj) - def add_protocol(self, obj): - self.add_child(obj) - def remove_protocol(self, obj): - self.remove_child(obj) - protocols = XMLChildProperty(InterfaceProtocol) + @property + def interfaces(self): + if self.type != "ethernet": + return getattr(self, "_" + self.type).interfaces + return [] ###################### @@ -167,6 +185,12 @@ class Interface(XMLBuilder): macaddr = XMLProperty("./mac/@address", validate_cb=_validate_mac) + def add_protocol(self, obj): + self.add_child(obj) + def remove_protocol(self, obj): + self.remove_child(obj) + protocols = XMLChildProperty(InterfaceProtocol) + ################# # Bridge params # @@ -241,5 +265,9 @@ class Interface(XMLBuilder): return iface -Interface.interfaces = XMLChildProperty(Interface, - relative_xpath="./%(type)s") + +# Interface can recursively have child interfaces which we can't define +# inline in the class config, hence this hackery +_BondConfig.interfaces = XMLChildProperty(Interface) +_BridgeConfig.interfaces = XMLChildProperty(Interface) +_VLANConfig.interfaces = XMLChildProperty(Interface) diff --git a/virtinst/xmlbuilder.py b/virtinst/xmlbuilder.py index 657427b4..614d5018 100644 --- a/virtinst/xmlbuilder.py +++ b/virtinst/xmlbuilder.py @@ -63,14 +63,15 @@ class XMLChildProperty(property): @child_class: XMLBuilder class this property is tracking. So for guest.devices.disk this is DeviceDisk @relative_xpath: Relative location where the class is rooted compared - to its _XML_ROOT_PATH. So interface xml can have nested - interfaces rooted at /interface/bridge/interface, so we pass - ./bridge/interface here for example. + to its xmlbuilder root path. So if xmlbuilder is ./foo and we + want to track ./foo/bar/baz instances, set relative_xpath=./bar + @is_single: If True, this represents an XML node that is only expected + to appear once, like """ def __init__(self, child_class, relative_xpath=".", is_single=False): self.child_class = child_class - self.relative_xpath = relative_xpath self.is_single = is_single + self.relative_xpath = relative_xpath self._propname = None property.__init__(self, self._fget) @@ -115,17 +116,8 @@ class XMLChildProperty(property): def set(self, xmlbuilder, obj): xmlbuilder._propstore[self._findpropname(xmlbuilder)] = obj - def get_prop_xpath(self, xmlbuilder, obj): - relative_xpath = self.relative_xpath + "/" + obj._XML_ROOT_NAME - - match = re.search("%\((.*)\)", self.relative_xpath) - if match: - valuedict = {} - for paramname in match.groups(): - valuedict[paramname] = getattr(xmlbuilder, paramname) - relative_xpath = relative_xpath % valuedict - - return relative_xpath + def get_prop_xpath(self, _xmlbuilder, obj): + return self.relative_xpath + "/" + obj._XML_ROOT_NAME class XMLProperty(property):