WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-api

[Xen-API] [PATCH 26 of 33] interface-reconfigure: Move DatabaseCache obj

To: xen-api@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-API] [PATCH 26 of 33] interface-reconfigure: Move DatabaseCache object to utility module
From: Ian Campbell <ian.campbell@xxxxxxxxxx>
Date: Fri, 18 Dec 2009 14:17:21 +0000
Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
Delivery-date: Fri, 18 Dec 2009 06:22:49 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <patchbomb.1261145815@xxxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-api-request@lists.xensource.com?subject=help>
List-id: Discussion of API issues surrounding Xen <xen-api.lists.xensource.com>
List-post: <mailto:xen-api@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-api>, <mailto:xen-api-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-api>, <mailto:xen-api-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-api-bounces@xxxxxxxxxxxxxxxxxxx
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

<Prev in Thread] Current Thread [Next in Thread>