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
|