[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-API] [PATCH 26 of 33] interface-reconfigure: Move DatabaseCache object to utility module



Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx>

diff -r adca5858776b -r f45285e6fbe3 scripts/InterfaceReconfigure.py
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/InterfaceReconfigure.py   Fri Dec 18 14:16:32 2009 +0000
@@ -0,0 +1,406 @@
+import syslog
+
+from xml.dom.minidom import getDOMImplementation
+from xml.dom.minidom import parse as parseXML
+
+#
+# Logging.
+#
+
+def log(s):
+    syslog.syslog(s)
+
+#
+# Exceptions.
+#
+
+class Error(Exception):
+    def __init__(self, msg):
+        Exception.__init__(self)
+        self.msg = msg
+
+#
+# Helper functions for encoding/decoding database attributes to/from XML.
+#
+
+def _str_to_xml(xml, parent, tag, val):
+    e = xml.createElement(tag)
+    parent.appendChild(e)
+    v = xml.createTextNode(val)
+    e.appendChild(v)
+def _str_from_xml(n):
+    def getText(nodelist):
+        rc = ""
+        for node in nodelist:
+            if node.nodeType == node.TEXT_NODE:
+                rc = rc + node.data
+        return rc
+    return getText(n.childNodes).strip()
+
+def _bool_to_xml(xml, parent, tag, val):
+    if val:
+        _str_to_xml(xml, parent, tag, "True")
+    else:
+        _str_to_xml(xml, parent, tag, "False")
+def _bool_from_xml(n):
+    s = _str_from_xml(n)
+    if s == "True":
+        return True
+    elif s == "False":
+        return False
+    else:
+        raise Error("Unknown boolean value %s" % s)
+
+def _strlist_to_xml(xml, parent, ltag, itag, val):
+    e = xml.createElement(ltag)
+    parent.appendChild(e)
+    for v in val:
+        c = xml.createElement(itag)
+        e.appendChild(c)
+        cv = xml.createTextNode(v)
+        c.appendChild(cv)
+def _strlist_from_xml(n, ltag, itag):
+    ret = []
+    for n in n.childNodes:
+        if n.nodeName == itag:
+            ret.append(_str_from_xml(n))
+    return ret
+
+def _otherconfig_to_xml(xml, parent, val, attrs):
+    otherconfig = xml.createElement("other_config")
+    parent.appendChild(otherconfig)
+    for n,v in val.items():
+        if not n in attrs:
+            raise Error("Unknown other-config attribute: %s" % n)
+        _str_to_xml(xml, otherconfig, n, v)
+def _otherconfig_from_xml(n, attrs):
+    ret = {}
+    for n in n.childNodes:
+        if n.nodeName in attrs:
+            ret[n.nodeName] = _str_from_xml(n)
+    return ret
+
+#
+# Definitions of the database objects (and their attributes) used by 
interface-reconfigure.
+#
+# Each object is defined by a dictionary mapping an attribute name in
+# the xapi database to a tuple containing two items:
+#  - a function which takes this attribute and encodes it as XML.
+#  - a function which takes XML and decocdes it into a value.
+#
+# other-config attributes are specified as a simple array of strings
+
+_PIF_XML_TAG = "pif"
+_VLAN_XML_TAG = "vlan"
+_BOND_XML_TAG = "bond"
+_NETWORK_XML_TAG = "network"
+
+_ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 
'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ]
+
+_PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 
'static-routes' ] + \
+                        [ 'bond-%s' % x for x in 'mode', 'miimon', 
'downdelay', 'updelay', 'use_carrier' ] + \
+                        _ETHTOOL_OTHERCONFIG_ATTRS
+
+_PIF_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
+               'management': (_bool_to_xml,_bool_from_xml),
+               'network': (_str_to_xml,_str_from_xml),
+               'device': (_str_to_xml,_str_from_xml),
+               'bond_master_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 
'bond_master_of', 'slave', v),
+                                  lambda n: _strlist_from_xml(n, 
'bond_master_of', 'slave')),
+               'bond_slave_of': (_str_to_xml,_str_from_xml),
+               'VLAN': (_str_to_xml,_str_from_xml),
+               'VLAN_master_of': (_str_to_xml,_str_from_xml),
+               'VLAN_slave_of': (lambda x, p, t, v: _strlist_to_xml(x, p, 
'VLAN_slave_of', 'master', v),
+                                 lambda n: _strlist_from_xml(n, 
'VLAN_slave_Of', 'master')),
+               'ip_configuration_mode': (_str_to_xml,_str_from_xml),
+               'IP': (_str_to_xml,_str_from_xml),
+               'netmask': (_str_to_xml,_str_from_xml),
+               'gateway': (_str_to_xml,_str_from_xml),
+               'DNS': (_str_to_xml,_str_from_xml),
+               'MAC': (_str_to_xml,_str_from_xml),
+               'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, p, 
v, _PIF_OTHERCONFIG_ATTRS),
+                                lambda n: _otherconfig_from_xml(n, 
_PIF_OTHERCONFIG_ATTRS)),
+
+               # Special case: We write the current value
+               # PIF.currently-attached to the cache but since it will
+               # not be valid when we come to use the cache later
+               # (i.e. after a reboot) we always read it as False.
+               'currently_attached': (_bool_to_xml, lambda n: False),
+             }
+
+_VLAN_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
+                'tagged_PIF': (_str_to_xml,_str_from_xml),
+                'untagged_PIF': (_str_to_xml,_str_from_xml),
+              }
+
+_BOND_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
+               'master': (_str_to_xml,_str_from_xml),
+               'slaves': (lambda x, p, t, v: _strlist_to_xml(x, p, 'slaves', 
'slave', v),
+                          lambda n: _strlist_from_xml(n, 'slaves', 'slave')),
+              }
+
+_NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + 
_ETHTOOL_OTHERCONFIG_ATTRS
+
+_NETWORK_ATTRS = { 'uuid': (_str_to_xml,_str_from_xml),
+                   'bridge': (_str_to_xml,_str_from_xml),
+                   'PIFs': (lambda x, p, t, v: _strlist_to_xml(x, p, 'PIFs', 
'PIF', v),
+                            lambda n: _strlist_from_xml(n, 'PIFs', 'PIF')),
+                   'other_config': (lambda x, p, t, v: _otherconfig_to_xml(x, 
p, v, _NETWORK_OTHERCONFIG_ATTRS),
+                                    lambda n: _otherconfig_from_xml(n, 
_NETWORK_OTHERCONFIG_ATTRS)),
+                 }
+
+#
+# Database Cache object
+#
+
+_db = None
+
+def db():
+    assert(_db is not None)
+    return _db
+
+def db_init_from_cache(cache):
+    global _db
+    assert(_db is None)
+    _db = DatabaseCache(cache_file=cache)
+    
+def db_init_from_xenapi(session):
+    global _db 
+    assert(_db is None)
+    _db  = DatabaseCache(session_ref=session)
+    
+class DatabaseCache(object):
+    def __read_xensource_inventory(self):
+        filename = "/etc/xensource-inventory"
+        f = open(filename, "r")
+        lines = [x.strip("\n") for x in f.readlines()]
+        f.close()
+
+        defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
+        defs = [ (a, b.strip("'")) for (a,b) in defs ]
+
+        return dict(defs)
+    def __pif_on_host(self,pif):
+        return self.__pifs.has_key(pif)
+
+    def __get_pif_records_from_xapi(self, session, host):
+        self.__pifs = {}
+        for (p,rec) in session.xenapi.PIF.get_all_records().items():
+            if rec['host'] != host:
+                continue
+            self.__pifs[p] = {}
+            for f in _PIF_ATTRS:
+                self.__pifs[p][f] = rec[f]
+            self.__pifs[p]['other_config'] = {}
+            for f in _PIF_OTHERCONFIG_ATTRS:
+                if not rec['other_config'].has_key(f): continue
+                self.__pifs[p]['other_config'][f] = rec['other_config'][f]
+
+    def __get_vlan_records_from_xapi(self, session):
+        self.__vlans = {}
+        for v in session.xenapi.VLAN.get_all():
+            rec = session.xenapi.VLAN.get_record(v)
+            if not self.__pif_on_host(rec['untagged_PIF']):
+                continue
+            self.__vlans[v] = {}
+            for f in _VLAN_ATTRS:
+                self.__vlans[v][f] = rec[f]
+
+    def __get_bond_records_from_xapi(self, session):
+        self.__bonds = {}
+        for b in session.xenapi.Bond.get_all():
+            rec = session.xenapi.Bond.get_record(b)
+            if not self.__pif_on_host(rec['master']):
+                continue
+            self.__bonds[b] = {}
+            for f in _BOND_ATTRS:
+                self.__bonds[b][f] = rec[f]
+
+    def __get_network_records_from_xapi(self, session):
+        self.__networks = {}
+        for n in session.xenapi.network.get_all():
+            rec = session.xenapi.network.get_record(n)
+            self.__networks[n] = {}
+            for f in _NETWORK_ATTRS:
+                if f == "PIFs":
+                    # drop PIFs on other hosts
+                    self.__networks[n][f] = [p for p in rec[f] if 
self.__pif_on_host(p)]
+                else:
+                    self.__networks[n][f] = rec[f]
+            self.__networks[n]['other_config'] = {}
+            for f in _NETWORK_OTHERCONFIG_ATTRS:
+                if not rec['other_config'].has_key(f): continue
+                self.__networks[n]['other_config'][f] = rec['other_config'][f]
+
+    def __to_xml(self, xml, parent, key, ref, rec, attrs):
+        """Encode a database object as XML"""
+        e = xml.createElement(key)
+        parent.appendChild(e)
+        if ref:
+            e.setAttribute('ref', ref)
+
+        for n,v in rec.items():
+            if attrs.has_key(n):
+                h,_ = attrs[n]
+                h(xml, e, n, v)
+            else:
+                raise Error("Unknown attribute %s" % n)
+    def __from_xml(self, e, attrs):
+        """Decode a database object from XML"""
+        ref = e.attributes['ref'].value
+        rec = {}
+        for n in e.childNodes:
+            if n.nodeName in attrs:
+                _,h = attrs[n.nodeName]
+                rec[n.nodeName] = h(n)
+        return (ref,rec)
+
+    def __init__(self, session_ref=None, cache_file=None):
+        if session_ref and cache_file:
+            raise Error("can't specify session reference and cache file")
+        if cache_file == None:
+            import XenAPI
+            session = XenAPI.xapi_local()
+
+            if not session_ref:
+                log("No session ref given on command line, logging in.")
+                session.xenapi.login_with_password("root", "")
+            else:
+                session._session = session_ref
+
+            try:
+
+                inventory = self.__read_xensource_inventory()
+                assert(inventory.has_key('INSTALLATION_UUID'))
+                log("host uuid is %s" % inventory['INSTALLATION_UUID'])
+
+                host = 
session.xenapi.host.get_by_uuid(inventory['INSTALLATION_UUID'])
+
+                self.__get_pif_records_from_xapi(session, host)
+
+                self.__get_vlan_records_from_xapi(session)
+                self.__get_bond_records_from_xapi(session)
+                self.__get_network_records_from_xapi(session)
+            finally:
+                if not session_ref:
+                    session.xenapi.session.logout()
+        else:
+            log("Loading xapi database cache from %s" % cache_file)
+
+            xml = parseXML(cache_file)
+
+            self.__pifs = {}
+            self.__bonds = {}
+            self.__vlans = {}
+            self.__networks = {}
+
+            assert(len(xml.childNodes) == 1)
+            toplevel = xml.childNodes[0]
+
+            assert(toplevel.nodeName == "xenserver-network-configuration")
+
+            for n in toplevel.childNodes:
+                if n.nodeName == "#text":
+                    pass
+                elif n.nodeName == _PIF_XML_TAG:
+                    (ref,rec) = self.__from_xml(n, _PIF_ATTRS)
+                    self.__pifs[ref] = rec
+                elif n.nodeName == _BOND_XML_TAG:
+                    (ref,rec) = self.__from_xml(n, _BOND_ATTRS)
+                    self.__bonds[ref] = rec
+                elif n.nodeName == _VLAN_XML_TAG:
+                    (ref,rec) = self.__from_xml(n, _VLAN_ATTRS)
+                    self.__vlans[ref] = rec
+                elif n.nodeName == _NETWORK_XML_TAG:
+                    (ref,rec) = self.__from_xml(n, _NETWORK_ATTRS)
+                    self.__networks[ref] = rec
+                else:
+                    raise Error("Unknown XML element %s" % n.nodeName)
+
+    def save(self, cache_file):
+
+        xml = getDOMImplementation().createDocument(
+            None, "xenserver-network-configuration", None)
+        for (ref,rec) in self.__pifs.items():
+            self.__to_xml(xml, xml.documentElement, _PIF_XML_TAG, ref, rec, 
_PIF_ATTRS)
+        for (ref,rec) in self.__bonds.items():
+            self.__to_xml(xml, xml.documentElement, _BOND_XML_TAG, ref, rec, 
_BOND_ATTRS)
+        for (ref,rec) in self.__vlans.items():
+            self.__to_xml(xml, xml.documentElement, _VLAN_XML_TAG, ref, rec, 
_VLAN_ATTRS)
+        for (ref,rec) in self.__networks.items():
+            self.__to_xml(xml, xml.documentElement, _NETWORK_XML_TAG, ref, rec,
+                          _NETWORK_ATTRS)
+
+        f = open(cache_file, 'w')
+        f.write(xml.toprettyxml())
+        f.close()
+
+    def get_pif_by_uuid(self, uuid):
+        pifs = map(lambda (ref,rec): ref,
+                  filter(lambda (ref,rec): uuid == rec['uuid'],
+                         self.__pifs.items()))
+        if len(pifs) == 0:
+            raise Error("Unknown PIF \"%s\"" % uuid)
+        elif len(pifs) > 1:
+            raise Error("Non-unique PIF \"%s\"" % uuid)
+
+        return pifs[0]
+
+    def get_pifs_by_device(self, device):
+        return map(lambda (ref,rec): ref,
+                   filter(lambda (ref,rec): rec['device'] == device,
+                          self.__pifs.items()))
+
+    def get_pif_by_bridge(self, bridge):
+        networks = map(lambda (ref,rec): ref,
+                       filter(lambda (ref,rec): rec['bridge'] == bridge,
+                              self.__networks.items()))
+        if len(networks) == 0:
+            raise Error("No matching network \"%s\"" % bridge)
+
+        answer = None
+        for network in networks:
+            nwrec = self.get_network_record(network)
+            for pif in nwrec['PIFs']:
+                pifrec = self.get_pif_record(pif)
+                if answer:
+                    raise Error("Multiple PIFs on host for network %s" % 
(bridge))
+                answer = pif
+        if not answer:
+            raise Error("No PIF on host for network %s" % (bridge))
+        return answer
+
+    def get_pif_record(self, pif):
+        if self.__pifs.has_key(pif):
+            return self.__pifs[pif]
+        raise Error("Unknown PIF \"%s\"" % pif)
+    def get_all_pifs(self):
+        return self.__pifs
+    def pif_exists(self, pif):
+        return self.__pifs.has_key(pif)
+
+    def get_management_pif(self):
+        """ Returns the management pif on host
+        """
+        all = self.get_all_pifs()
+        for pif in all:
+            pifrec = self.get_pif_record(pif)
+            if pifrec['management']: return pif
+        return None
+
+    def get_network_record(self, network):
+        if self.__networks.has_key(network):
+            return self.__networks[network]
+        raise Error("Unknown network \"%s\"" % network)
+
+    def get_bond_record(self, bond):
+        if self.__bonds.has_key(bond):
+            return self.__bonds[bond]
+        else:
+            return None
+
+    def get_vlan_record(self, vlan):
+        if self.__vlans.has_key(vlan):
+            return self.__vlans[vlan]
+        else:
+            return None
diff -r adca5858776b -r f45285e6fbe3 scripts/OMakefile
--- a/scripts/OMakefile Fri Dec 18 14:16:32 2009 +0000
+++ b/scripts/OMakefile Fri Dec 18 14:16:32 2009 +0000
@@ -68,6 +68,7 @@
        $(IPROG) qemu-dm-wrapper vncterm-wrapper upload-wrapper logs-download 
$(LIBEXEC)/
        mkdir -p $(DIST)/staging/opt/xensource/packages/iso #omg XXX
        $(IPROG) interface-reconfigure $(LIBEXEC)
+       $(IPROG) InterfaceReconfigure.py $(LIBEXEC)
        $(IPROG) rewrite-management-interface $(LIBEXEC)
        $(IPROG) interface-visualise $(LIBEXEC)
        $(IPROG) logrotate.sh $(LIBEXEC)
diff -r adca5858776b -r f45285e6fbe3 scripts/interface-reconfigure
--- a/scripts/interface-reconfigure     Fri Dec 18 14:16:32 2009 +0000
+++ b/scripts/interface-reconfigure     Fri Dec 18 14:16:32 2009 +0000
@@ -41,17 +41,15 @@
 # 3. A network may have an associated bridge, allowing vifs to be attached
 # 4. A network may be bridgeless (there's no point having a bridge over a 
storage pif)
 
-import XenAPI
+from InterfaceReconfigure import *
+
 import os, sys, getopt
 import syslog
 import traceback
 import time
 import re
 import random
-from xml.dom.minidom import getDOMImplementation
-from xml.dom.minidom import parse as parseXML
 
-db = None
 management_pif = None
 
 sysfs_bonding_masters = "/sys/class/net/bonding_masters"
@@ -61,11 +59,8 @@
 # Logging.
 #
 
-def log(s):
-    syslog.syslog(s)
-
 def log_pif_action(action, pif):
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
     rec = {}
     rec['uuid'] = pifrec['uuid']
     rec['ip_configuration_mode'] = pifrec['ip_configuration_mode']
@@ -91,11 +86,6 @@
 #
 
 class Usage(Exception):
-    def __init__(self, msg):
-        Exception.__init__(self)
-        self.msg = msg
-
-class Error(Exception):
     def __init__(self, msg):
         Exception.__init__(self)
         self.msg = msg
@@ -228,7 +218,7 @@
         self.__state = self.__STATE['COMMITTED']
 
 def open_pif_ifcfg(pif):
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     interface = pif_netdev_name(pif)
     log("Configuring %s (%s)" % (interface, pifrec['MAC']))
@@ -244,375 +234,6 @@
     return f
 
 #
-# Helper functions for encoding/decoding database attributes to/from XML.
-#
-
-def str_to_xml(xml, parent, tag, val):
-    e = xml.createElement(tag)
-    parent.appendChild(e)
-    v = xml.createTextNode(val)
-    e.appendChild(v)
-def str_from_xml(n):
-    def getText(nodelist):
-        rc = ""
-        for node in nodelist:
-            if node.nodeType == node.TEXT_NODE:
-                rc = rc + node.data
-        return rc
-    return getText(n.childNodes).strip()
-
-def bool_to_xml(xml, parent, tag, val):
-    if val:
-        str_to_xml(xml, parent, tag, "True")
-    else:
-        str_to_xml(xml, parent, tag, "False")
-def bool_from_xml(n):
-    s = str_from_xml(n)
-    if s == "True":
-        return True
-    elif s == "False":
-        return False
-    else:
-        raise Error("Unknown boolean value %s" % s)
-
-def strlist_to_xml(xml, parent, ltag, itag, val):
-    e = xml.createElement(ltag)
-    parent.appendChild(e)
-    for v in val:
-        c = xml.createElement(itag)
-        e.appendChild(c)
-        cv = xml.createTextNode(v)
-        c.appendChild(cv)
-def strlist_from_xml(n, ltag, itag):
-    ret = []
-    for n in n.childNodes:
-        if n.nodeName == itag:
-            ret.append(str_from_xml(n))
-    return ret
-
-def otherconfig_to_xml(xml, parent, val, attrs):
-    otherconfig = xml.createElement("other_config")
-    parent.appendChild(otherconfig)
-    for n,v in val.items():
-        if not n in attrs:
-            raise Error("Unknown other-config attribute: %s" % n)
-        str_to_xml(xml, otherconfig, n, v)
-def otherconfig_from_xml(n, attrs):
-    ret = {}
-    for n in n.childNodes:
-        if n.nodeName in attrs:
-            ret[n.nodeName] = str_from_xml(n)
-    return ret
-
-#
-# Definitions of the database objects (and their attributes) used by 
interface-reconfigure.
-#
-# Each object is defined by a dictionary mapping an attribute name in
-# the xapi database to a tuple containing two items:
-#  - a function which takes this attribute and encodes it as XML.
-#  - a function which takes XML and decocdes it into a value.
-#
-# other-config attributes are specified as a simple array of strings
-
-PIF_XML_TAG = "pif"
-VLAN_XML_TAG = "vlan"
-BOND_XML_TAG = "bond"
-NETWORK_XML_TAG = "network"
-
-ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 
'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ]
-
-PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 
'static-routes' ] + \
-                        [ 'bond-%s' % x for x in 'mode', 'miimon', 
'downdelay', 'updelay', 'use_carrier' ] + \
-                        ETHTOOL_OTHERCONFIG_ATTRS
-
-PIF_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-              'management': (bool_to_xml,bool_from_xml),
-              'network': (str_to_xml,str_from_xml),
-              'device': (str_to_xml,str_from_xml),
-              'bond_master_of': (lambda x, p, t, v: strlist_to_xml(x, p, 
'bond_master_of', 'slave', v),
-                                 lambda n: strlist_from_xml(n, 
'bond_master_of', 'slave')),
-              'bond_slave_of': (str_to_xml,str_from_xml),
-              'VLAN': (str_to_xml,str_from_xml),
-              'VLAN_master_of': (str_to_xml,str_from_xml),
-              'VLAN_slave_of': (lambda x, p, t, v: strlist_to_xml(x, p, 
'VLAN_slave_of', 'master', v),
-                                lambda n: strlist_from_xml(n, 'VLAN_slave_Of', 
'master')),
-              'ip_configuration_mode': (str_to_xml,str_from_xml),
-              'IP': (str_to_xml,str_from_xml),
-              'netmask': (str_to_xml,str_from_xml),
-              'gateway': (str_to_xml,str_from_xml),
-              'DNS': (str_to_xml,str_from_xml),
-              'MAC': (str_to_xml,str_from_xml),
-              'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, 
PIF_OTHERCONFIG_ATTRS),
-                               lambda n: otherconfig_from_xml(n, 
PIF_OTHERCONFIG_ATTRS)),
-
-              # Special case: We write the current value
-              # PIF.currently-attached to the cache but since it will
-              # not be valid when we come to use the cache later
-              # (i.e. after a reboot) we always read it as False.
-              'currently_attached': (bool_to_xml, lambda n: False),
-            }
-
-VLAN_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-               'tagged_PIF': (str_to_xml,str_from_xml),
-               'untagged_PIF': (str_to_xml,str_from_xml),
-             }
-
-BOND_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-               'master': (str_to_xml,str_from_xml),
-               'slaves': (lambda x, p, t, v: strlist_to_xml(x, p, 'slaves', 
'slave', v),
-                          lambda n: strlist_from_xml(n, 'slaves', 'slave')),
-             }
-
-NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + 
ETHTOOL_OTHERCONFIG_ATTRS
-
-NETWORK_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
-                  'bridge': (str_to_xml,str_from_xml),
-                  'PIFs': (lambda x, p, t, v: strlist_to_xml(x, p, 'PIFs', 
'PIF', v),
-                           lambda n: strlist_from_xml(n, 'PIFs', 'PIF')),
-                  'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, 
v, NETWORK_OTHERCONFIG_ATTRS),
-                                   lambda n: otherconfig_from_xml(n, 
NETWORK_OTHERCONFIG_ATTRS)),
-                }
-
-#
-# Database Cache object
-#
-
-class DatabaseCache(object):
-    def __read_xensource_inventory(self):
-        filename = "/etc/xensource-inventory"
-        f = open(filename, "r")
-        lines = [x.strip("\n") for x in f.readlines()]
-        f.close()
-
-        defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
-        defs = [ (a, b.strip("'")) for (a,b) in defs ]
-
-        return dict(defs)
-    def __pif_on_host(self,pif):
-        return self.__pifs.has_key(pif)
-
-    def __get_pif_records_from_xapi(self, session, host):
-        self.__pifs = {}
-        for (p,rec) in session.xenapi.PIF.get_all_records().items():
-            if rec['host'] != host:
-                continue
-            self.__pifs[p] = {}
-            for f in PIF_ATTRS:
-                self.__pifs[p][f] = rec[f]
-            self.__pifs[p]['other_config'] = {}
-            for f in PIF_OTHERCONFIG_ATTRS:
-                if not rec['other_config'].has_key(f): continue
-                self.__pifs[p]['other_config'][f] = rec['other_config'][f]
-
-    def __get_vlan_records_from_xapi(self, session):
-        self.__vlans = {}
-        for v in session.xenapi.VLAN.get_all():
-            rec = session.xenapi.VLAN.get_record(v)
-            if not self.__pif_on_host(rec['untagged_PIF']):
-                continue
-            self.__vlans[v] = {}
-            for f in VLAN_ATTRS:
-                self.__vlans[v][f] = rec[f]
-
-    def __get_bond_records_from_xapi(self, session):
-        self.__bonds = {}
-        for b in session.xenapi.Bond.get_all():
-            rec = session.xenapi.Bond.get_record(b)
-            if not self.__pif_on_host(rec['master']):
-                continue
-            self.__bonds[b] = {}
-            for f in BOND_ATTRS:
-                self.__bonds[b][f] = rec[f]
-
-    def __get_network_records_from_xapi(self, session):
-        self.__networks = {}
-        for n in session.xenapi.network.get_all():
-            rec = session.xenapi.network.get_record(n)
-            self.__networks[n] = {}
-            for f in NETWORK_ATTRS:
-                if f == "PIFs":
-                    # drop PIFs on other hosts
-                    self.__networks[n][f] = [p for p in rec[f] if 
self.__pif_on_host(p)]
-                else:
-                    self.__networks[n][f] = rec[f]
-            self.__networks[n]['other_config'] = {}
-            for f in NETWORK_OTHERCONFIG_ATTRS:
-                if not rec['other_config'].has_key(f): continue
-                self.__networks[n]['other_config'][f] = rec['other_config'][f]
-
-    def __to_xml(self, xml, parent, key, ref, rec, attrs):
-        """Encode a database object as XML"""
-        e = xml.createElement(key)
-        parent.appendChild(e)
-        if ref:
-            e.setAttribute('ref', ref)
-
-        for n,v in rec.items():
-            if attrs.has_key(n):
-                h,_ = attrs[n]
-                h(xml, e, n, v)
-            else:
-                raise Error("Unknown attribute %s" % n)
-    def __from_xml(self, e, attrs):
-        """Decode a database object from XML"""
-        ref = e.attributes['ref'].value
-        rec = {}
-        for n in e.childNodes:
-            if n.nodeName in attrs:
-                _,h = attrs[n.nodeName]
-                rec[n.nodeName] = h(n)
-        return (ref,rec)
-
-    def __init__(self, session_ref=None, cache_file=None):
-        if session_ref and cache_file:
-            raise Error("can't specify session reference and cache file")
-        if cache_file == None:
-            session = XenAPI.xapi_local()
-
-            if not session_ref:
-                log("No session ref given on command line, logging in.")
-                session.xenapi.login_with_password("root", "")
-            else:
-                session._session = session_ref
-
-            try:
-
-                inventory = self.__read_xensource_inventory()
-                assert(inventory.has_key('INSTALLATION_UUID'))
-                log("host uuid is %s" % inventory['INSTALLATION_UUID'])
-
-                host = 
session.xenapi.host.get_by_uuid(inventory['INSTALLATION_UUID'])
-
-                self.__get_pif_records_from_xapi(session, host)
-
-                self.__get_vlan_records_from_xapi(session)
-                self.__get_bond_records_from_xapi(session)
-                self.__get_network_records_from_xapi(session)
-            finally:
-                if not session_ref:
-                    session.xenapi.session.logout()
-        else:
-            log("Loading xapi database cache from %s" % cache_file)
-
-            xml = parseXML(cache_file)
-
-            self.__pifs = {}
-            self.__bonds = {}
-            self.__vlans = {}
-            self.__networks = {}
-
-            assert(len(xml.childNodes) == 1)
-            toplevel = xml.childNodes[0]
-
-            assert(toplevel.nodeName == "xenserver-network-configuration")
-
-            for n in toplevel.childNodes:
-                if n.nodeName == "#text":
-                    pass
-                elif n.nodeName == PIF_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, PIF_ATTRS)
-                    self.__pifs[ref] = rec
-                elif n.nodeName == BOND_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, BOND_ATTRS)
-                    self.__bonds[ref] = rec
-                elif n.nodeName == VLAN_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, VLAN_ATTRS)
-                    self.__vlans[ref] = rec
-                elif n.nodeName == NETWORK_XML_TAG:
-                    (ref,rec) = self.__from_xml(n, NETWORK_ATTRS)
-                    self.__networks[ref] = rec
-                else:
-                    raise Error("Unknown XML element %s" % n.nodeName)
-
-    def save(self, cache_file):
-
-        xml = getDOMImplementation().createDocument(
-            None, "xenserver-network-configuration", None)
-        for (ref,rec) in self.__pifs.items():
-            self.__to_xml(xml, xml.documentElement, PIF_XML_TAG, ref, rec, 
PIF_ATTRS)
-        for (ref,rec) in self.__bonds.items():
-            self.__to_xml(xml, xml.documentElement, BOND_XML_TAG, ref, rec, 
BOND_ATTRS)
-        for (ref,rec) in self.__vlans.items():
-            self.__to_xml(xml, xml.documentElement, VLAN_XML_TAG, ref, rec, 
VLAN_ATTRS)
-        for (ref,rec) in self.__networks.items():
-            self.__to_xml(xml, xml.documentElement, NETWORK_XML_TAG, ref, rec,
-                          NETWORK_ATTRS)
-
-        f = open(cache_file, 'w')
-        f.write(xml.toprettyxml())
-        f.close()
-
-    def get_pif_by_uuid(self, uuid):
-        pifs = map(lambda (ref,rec): ref,
-                  filter(lambda (ref,rec): uuid == rec['uuid'],
-                         self.__pifs.items()))
-        if len(pifs) == 0:
-            raise Error("Unknown PIF \"%s\"" % uuid)
-        elif len(pifs) > 1:
-            raise Error("Non-unique PIF \"%s\"" % uuid)
-
-        return pifs[0]
-
-    def get_pifs_by_device(self, device):
-        return map(lambda (ref,rec): ref,
-                   filter(lambda (ref,rec): rec['device'] == device,
-                          self.__pifs.items()))
-
-    def get_pif_by_bridge(self, bridge):
-        networks = map(lambda (ref,rec): ref,
-                       filter(lambda (ref,rec): rec['bridge'] == bridge,
-                              self.__networks.items()))
-        if len(networks) == 0:
-            raise Error("No matching network \"%s\"" % bridge)
-
-        answer = None
-        for network in networks:
-            nwrec = self.get_network_record(network)
-            for pif in nwrec['PIFs']:
-                pifrec = self.get_pif_record(pif)
-                if answer:
-                    raise Error("Multiple PIFs on host for network %s" % 
(bridge))
-                answer = pif
-        if not answer:
-            raise Error("No PIF on host for network %s" % (bridge))
-        return answer
-
-    def get_pif_record(self, pif):
-        if self.__pifs.has_key(pif):
-            return self.__pifs[pif]
-        raise Error("Unknown PIF \"%s\"" % pif)
-    def get_all_pifs(self):
-        return self.__pifs
-    def pif_exists(self, pif):
-        return self.__pifs.has_key(pif)
-
-    def get_management_pif(self):
-        """ Returns the management pif on host
-        """
-        all = self.get_all_pifs()
-        for pif in all:
-            pifrec = self.get_pif_record(pif)
-            if pifrec['management']: return pif
-        return None
-
-    def get_network_record(self, network):
-        if self.__networks.has_key(network):
-            return self.__networks[network]
-        raise Error("Unknown network \"%s\"" % network)
-
-    def get_bond_record(self, bond):
-        if self.__bonds.has_key(bond):
-            return self.__bonds[bond]
-        else:
-            return None
-
-    def get_vlan_record(self, vlan):
-        if self.__vlans.has_key(vlan):
-            return self.__vlans[vlan]
-        else:
-            return None
-
-#
 # Boot from Network filesystem or device.
 #
 
@@ -622,7 +243,7 @@
     Used to prevent system PIFs (such as network root disk) from being 
interfered with.
     """
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
     try:
         f = open("/proc/ardence")
         macline = filter(lambda x: x.startswith("HWaddr:"), f.readlines())
@@ -646,7 +267,7 @@
 def pif_netdev_name(pif):
     """Get the netdev name for a PIF."""
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     if pif_is_vlan(pif):
         return "%(device)s.%(VLAN)s" % pifrec
@@ -710,7 +331,7 @@
         if not run_command(['/sbin/ip', 'link', 'set', old_name, 'name', 
new_name]):
             raise Error("Could not rename %s to %s" % (old_name, new_name))
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
     device = pifrec['device']
     mac = pifrec['MAC']
 
@@ -745,8 +366,8 @@
 
 def pif_ipdev_name(pif):
     """Return the ipdev name associated with pif"""
-    pifrec = db.get_pif_record(pif)
-    nwrec = db.get_network_record(pifrec['network'])
+    pifrec = db().get_pif_record(pif)
+    nwrec = db().get_network_record(pifrec['network'])
 
     if nwrec['bridge']:
         # TODO: sanity check that nwrec['bridgeless'] != 'true'
@@ -771,8 +392,8 @@
 #
 
 def pif_is_bridged(pif):
-    pifrec = db.get_pif_record(pif)
-    nwrec = db.get_network_record(pifrec['network'])
+    pifrec = db().get_pif_record(pif)
+    nwrec = db().get_network_record(pifrec['network'])
 
     if nwrec['bridge']:
         # TODO: sanity check that nwrec['bridgeless'] != 'true'
@@ -785,9 +406,9 @@
     """Return the bridge name of a pif.
 
     PIF must be a bridged PIF."""
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
-    nwrec = db.get_network_record(pifrec['network'])
+    nwrec = db().get_network_record(pifrec['network'])
 
     if nwrec['bridge']:
         return nwrec['bridge']
@@ -861,7 +482,7 @@
 def destroy_bond_device(pif):
     """No, Mr. Bond, I expect you to die."""
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     if not pif_is_bond(pif):
         return
@@ -883,7 +504,7 @@
     Returns the open file handle for the interface configuration file.
     """
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     f = open_pif_ifcfg(pif)
 
@@ -953,14 +574,14 @@
 # Bonded PIFs
 #
 def pif_is_bond(pif):
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     return len(pifrec['bond_master_of']) > 0
 
 def pif_get_bond_masters(pif):
     """Returns a list of PIFs which are bond masters of this PIF"""
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     bso = pifrec['bond_slave_of']
 
@@ -972,7 +593,7 @@
     elif not type(bso) == list:
         bso = [bso]
 
-    bondrecs = [db.get_bond_record(bond) for bond in bso]
+    bondrecs = [db().get_bond_record(bond) for bond in bso]
     bondrecs = [rec for rec in bondrecs if rec]
 
     return [bond['master'] for bond in bondrecs]
@@ -980,7 +601,7 @@
 def pif_get_bond_slaves(pif):
     """Returns a list of PIFs which make up the given bonded pif."""
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     bmo = pifrec['bond_master_of']
     if len(bmo) > 1:
@@ -989,7 +610,7 @@
     if len(bmo) == 0:
         return []
 
-    bondrec = db.get_bond_record(bmo[0])
+    bondrec = db().get_bond_record(bmo[0])
     if not bondrec:
         raise Error("No bond record for bond master PIF")
 
@@ -1002,7 +623,7 @@
     try:
         attached_slaves = open("/sys/class/net/%s/bonding/slaves" % 
pifrec['device']).readline().split()
         for slave in attached_slaves:
-            pifs = [p for p in db.get_pifs_by_device(slave) if not 
pif_is_vlan(p)]
+            pifs = [p for p in db().get_pifs_by_device(slave) if not 
pif_is_vlan(p)]
             slave_pif = pifs[0]
             slave_pifs.remove(slave_pif)
             slave_pifs.insert(0, slave_pif)
@@ -1022,7 +643,7 @@
     file.
     """
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     f = open_pif_ifcfg(pif)
 
@@ -1073,20 +694,20 @@
 #
 
 def pif_is_vlan(pif):
-    return db.get_pif_record(pif)['VLAN'] != '-1'
+    return db().get_pif_record(pif)['VLAN'] != '-1'
 
 def pif_get_vlan_slave(pif):
     """Find the PIF which is the VLAN slave of pif.
 
 Returns the 'physical' PIF underneath the a VLAN PIF @pif."""
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     vlan = pifrec['VLAN_master_of']
     if not vlan or vlan == "OpaqueRef:NULL":
         raise Error("PIF is not a VLAN master")
 
-    vlanrec = db.get_vlan_record(vlan)
+    vlanrec = db().get_vlan_record(vlan)
     if not vlanrec:
         raise Error("No VLAN record found for PIF")
 
@@ -1095,9 +716,9 @@
 def pif_get_vlan_masters(pif):
     """Returns a list of PIFs which are VLANs on top of the given pif."""
 
-    pifrec = db.get_pif_record(pif)
-    vlans = [db.get_vlan_record(v) for v in pifrec['VLAN_slave_of']]
-    return [v['untagged_PIF'] for v in vlans if v and 
db.pif_exists(v['untagged_PIF'])]
+    pifrec = db().get_pif_record(pif)
+    vlans = [db().get_vlan_record(v) for v in pifrec['VLAN_slave_of']]
+    return [v['untagged_PIF'] for v in vlans if v and 
db().pif_exists(v['untagged_PIF'])]
 
 def configure_vlan_interface(pif):
     """Write the configuration for a VLAN interface.
@@ -1112,7 +733,7 @@
 
     slave = configure_pif(pif_get_vlan_slave(pif))
 
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     f = open_pif_ifcfg(pif)
     f.write("VLAN=yes\n")
@@ -1204,12 +825,12 @@
             return
 
         slave = pif_get_vlan_slave(pif)
-        if db.get_pif_record(slave)['currently_attached']:
+        if db().get_pif_record(slave)['currently_attached']:
             log("bring_down_interface: vlan slave is currently attached")
             return
 
         masters = pif_get_vlan_masters(slave)
-        masters = [m for m in masters if m != pif and 
db.get_pif_record(m)['currently_attached']]
+        masters = [m for m in masters if m != pif and 
db().get_pif_record(m)['currently_attached']]
         if len(masters) > 0:
             log("bring_down_interface: vlan slave has other masters")
             return
@@ -1218,8 +839,8 @@
         pif = slave
     else:
         vlan_masters = pif_get_vlan_masters(pif)
-        log("vlan masters of %s - %s" % (db.get_pif_record(pif)['device'], 
[pif_netdev_name(m) for m in vlan_masters]))
-        if len([m for m in vlan_masters if 
db.get_pif_record(m)['currently_attached']]) > 0:
+        log("vlan masters of %s - %s" % (db().get_pif_record(pif)['device'], 
[pif_netdev_name(m) for m in vlan_masters]))
+        if len([m for m in vlan_masters if 
db().get_pif_record(m)['currently_attached']]) > 0:
             log("Leaving %s up due to currently attached VLAN masters" % 
pif_netdev_name(pif))
             return
 
@@ -1228,10 +849,10 @@
     # Need to bring down bond slaves first since the bond device
     # must be up to enslave/unenslave.
     bond_slaves = pif_get_bond_slaves(pif)
-    log("bond slaves of %s - %s" % (db.get_pif_record(pif)['device'], 
[pif_netdev_name(s) for s in bond_slaves]))
+    log("bond slaves of %s - %s" % (db().get_pif_record(pif)['device'], 
[pif_netdev_name(s) for s in bond_slaves]))
     for slave in bond_slaves:
         slave_interface = pif_netdev_name(slave)
-        if db.get_pif_record(slave)['currently_attached']:
+        if db().get_pif_record(slave)['currently_attached']:
             log("leave bond slave %s up (currently attached)" % 
slave_interface)
             continue
         log("bring down bond slave %s" % slave_interface)
@@ -1345,8 +966,8 @@
         pif:  Opaque_ref of pif
     """
 
-    pifrec = db.get_pif_record(pif)
-    nwrec = db.get_network_record(pifrec['network'])
+    pifrec = db().get_pif_record(pif)
+    nwrec = db().get_network_record(pifrec['network'])
 
     ipdev = pif_ipdev_name(pif)
 
@@ -1416,7 +1037,7 @@
     # because when we are called to bring up an interface with a bond
     # master, it is implicit that we should bring down that master.
 
-    pifs_on_host = [p for p in db.get_all_pifs() if not p in 
pif_get_bond_masters(pif)]
+    pifs_on_host = [p for p in db().get_all_pifs() if not p in 
pif_get_bond_masters(pif)]
 
     # loop through all the pifs on this host looking for one with
     #   other-config:peerdns = true, and one with
@@ -1424,20 +1045,20 @@
     peerdns_pif = None
     defaultroute_pif = None
     for __pif in pifs_on_host:
-        __pifrec = db.get_pif_record(__pif)
+        __pifrec = db().get_pif_record(__pif)
         __oc = __pifrec['other_config']
         if __oc.has_key('peerdns') and __oc['peerdns'] == 'true':
             if peerdns_pif == None:
                 peerdns_pif = __pif
             else:
                 log('Warning: multiple pifs with "peerdns=true" - choosing %s 
and ignoring %s' % \
-                        (db.get_pif_record(peerdns_pif)['device'], 
__pifrec['device']))
+                        (db().get_pif_record(peerdns_pif)['device'], 
__pifrec['device']))
         if __oc.has_key('defaultroute') and __oc['defaultroute'] == 'true':
             if defaultroute_pif == None:
                 defaultroute_pif = __pif
             else:
                 log('Warning: multiple pifs with "defaultroute=true" - 
choosing %s and ignoring %s' % \
-                        (db.get_pif_record(defaultroute_pif)['device'], 
__pifrec['device']))
+                        (db().get_pif_record(defaultroute_pif)['device'], 
__pifrec['device']))
 
     # If no pif is explicitly specified then use the mgmt pif for
     # peerdns/defaultroute.
@@ -1480,8 +1101,8 @@
 The datapath name is the bridge name.
 For a VLAN PIF, the datapath name is the bridge name for the PIF's VLAN slave.
 """
-    pifrec = db.get_pif_record(pif)
-    nwrec = db.get_network_record(pifrec['network'])
+    pifrec = db().get_pif_record(pif)
+    nwrec = db().get_network_record(pifrec['network'])
     if not nwrec['bridge']:
         return None
     else:
@@ -1493,7 +1114,7 @@
 #
 
 def action_up(pif, force):
-    pifrec = db.get_pif_record(pif)
+    pifrec = db().get_pif_record(pif)
 
     ipdev = pif_ipdev_name(pif)
     dp = pif_datapath(pif)
@@ -1542,7 +1163,7 @@
         ifup(ipdev)
 
         # Bring back any currently-attached VLAN masters (brought down above)
-        for master in [v for v in pif_get_vlan_masters(pif) if 
db.get_pif_record(v)['currently_attached']]:
+        for master in [v for v in pif_get_vlan_masters(pif) if 
db().get_pif_record(v)['currently_attached']]:
             name = pif_netdev_name(master)
             log("action_up: bring up %s" % (name))
             netdev_up(name)
@@ -1746,9 +1367,9 @@
             if action == "rewrite":
                 action_force_rewrite(force_interface, force_rewrite_config)
             elif action in ["up", "down"]:
-                db = DatabaseCache(cache_file=dbcache_file)
-                pif = db.get_pif_by_bridge(force_interface)
-                management_pif = db.get_management_pif()
+                db_init_from_cache(dbcache_file)
+                pif = db().get_pif_by_bridge(force_interface)
+                management_pif = db().get_management_pif()
 
                 if action == "up":
                     action_up(pif, True)
@@ -1757,10 +1378,10 @@
             else:
                 raise Error("Unknown action %s"  % action)
         else:
-            db = DatabaseCache(session_ref=session)
+            db_init_from_xenapi(session)
 
             if pif_uuid:
-                pif = db.get_pif_by_uuid(pif_uuid)
+                pif = db().get_pif_by_uuid(pif_uuid)
 
             if action == "rewrite":
                 pass
@@ -1774,8 +1395,8 @@
                 else:
                     # pif is not going to be the management pif.
                     # Search DB cache for pif on same host with management=true
-                    pifrec = db.get_pif_record(pif)
-                    management_pif = db.get_management_pif()
+                    pifrec = db().get_pif_record(pif)
+                    management_pif = db().get_management_pif()
 
                 log_pif_action(action, pif)
 
@@ -1790,7 +1411,7 @@
                     raise Error("Unknown action %s"  % action)
 
             # Save cache.
-            db.save(dbcache_file)
+            db().save(dbcache_file)
 
     except Usage, err:
         print >>sys.stderr, err.msg

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.