[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |