#!/usr/bin/python -tt # Some code for parsing libvirt's capabilities XML # # Copyright 2007 Red Hat, Inc. # Mark McLoughlin # # This software may be freely redistributed under the terms of the GNU # general public license. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import libxml2 class CapabilitiesParserException(Exception): def __init__(self, msg): Exception.__init__(self, msg) FEATURE_ACPI = 0x01 FEATURE_APIC = 0x02 FEATURE_PAE = 0x04 FEATURE_NONPAE = 0x08 FEATURE_VMX = 0x10 FEATURE_SVM = 0x20 FEATURE_IA64_BE = 0x40 features_map = { "acpi" : FEATURE_ACPI, "apic" : FEATURE_APIC, "pae" : FEATURE_PAE, "nonpae" : FEATURE_NONPAE, "vmx" : FEATURE_VMX, "svm" : FEATURE_SVM, "ia64_be" : FEATURE_IA64_BE } NUM_FEATURES = len(features_map) def _parse_features(self, node): features = 0 child = node.children while child: if child.name in features_map: features |= features_map[child.name] child = child.next return features class Host(object): ARCHES = [ "i686", "x86_64" ] def __init__(self, node = None): self._arch = None self._features = 0 if not node is None: self.parseXML(node) def get_arch(self): return self._arch def set_arch(self, arch): if not arch in self.ARCHES: raise CapabilitiesParserException("'%s' is not a supported architecture" % arch) self._arch = arch arch = property(get_arch, set_arch) def get_features(self): return self._features def set_features(self, features): if (features >> NUM_FEATURES) != 0: raise CapabilitiesParserException("Invalid feature set '0x%x'" % features) self._features = features features = property(get_features, set_features) def parseXML(self, node): child = node.children while child: if child.name != "cpu": child = child.next continue n = child.children while n: if n.name == "arch": self.arch = n.content elif n.name == "features": self.features |= _parse_features(self, n) n = n.next child = child.next class Guest(object): OS_TYPES = [ "xen", "hvm" ] DOMAIN_TYPES = [ "xen", "qemu", "kqemu", "kvm" ] ARCHES = [ "i686", "x86_64", "mips", "mipsel", "sparc", "ppc" ] def __init__(self, node = None): self._os_type = None self._domain_type = None self._arch = None self._features = 0 if not node is None: self.parseXML(node) def get_os_type(self): return self._os_type def set_os_type(self, os_type): if not os_type in self.OS_TYPES: raise CapabilitiesParserException("'%s' is not a supported OS type" % os_type) self._os_type = os_type os_type = property(get_os_type, set_os_type) def get_domain_type(self): return self._domain_type def set_domain_type(self, domain_type): if not domain_type in self.DOMAIN_TYPES: raise CapabilitiesParserException("'%s' is not a supported domain type" % domain_type) self._domain_type = domain_type domain_type = property(get_domain_type, set_domain_type) def get_arch(self): return self._arch def set_arch(self, arch): if not arch in self.ARCHES: raise CapabilitiesParserException("'%s' is not a supported architecture" % arch) self._arch = arch arch = property(get_arch, set_arch) def get_features(self): return self._features def set_features(self, features): if (features >> NUM_FEATURES) != 0: raise CapabilitiesParserException("Invalid feature set '0x%x'" % features) self._features = features features = property(get_features, set_features) def parseXML(self, node): child = node.children while child: if child.name == "os_type": self.os_type = child.content elif child.name == "arch": # NB. for now, ignoring the rest of arch e.g. wordsize etc. self.arch = child.prop("name") elif child.name == "features": self.features |= _parse_features(self, child) child = child.next class Capabilities(object): def __init__(self, node = None): self._host = None self.guests = [] if not node is None: self.parseXML(node) def get_host(self): return self._host def set_host(self, host): if not self._host is None: raise CapabilitiesParserException("Only a single element is allowed") self._host = host host = property(get_host, set_host) def parseXML(self, node): child = node.children while child: if child.name == "host": self.host = Host(child) elif child.name == "guest": self.guests.append(Guest(child)) child = child.next def parse(xml): class ErrorHandler: def __init__(self): self.msg = "" def handler(self, ctx, str): self.msg += str error = ErrorHandler() libxml2.registerErrorHandler(error.handler, None) try: doc = libxml2.readMemory(xml, len(xml), None, None, libxml2.XML_PARSE_NOBLANKS) except (libxml2.parserError, libxml2.treeError), e: raise CapabilitiesParserException("%s\n%s" % (e, error.msg)) finally: libxml2.registerErrorHandler(None, None) try: root = doc.getRootElement() if root.name != "capabilities": raise CapabilitiesParserException("Root element is not 'capabilties'") capabilities = Capabilities(root) finally: doc.freeDoc() return capabilities if __name__ == "__main__": import libvirt for uri in (None, "qemu:///system"): cnx = libvirt.open(uri) caps = parse(cnx.getCapabilities()) print "host arch: %s" % caps.host.arch if caps.host.features: print "host features:" for feature in features_map: if caps.host.features & features_map[feature]: print " " + feature for guest in caps.guests: print print "guest arch: %s" % guest.arch print "guest os type: %s" % guest.os_type if guest.features: print "guest features:" for feature in features_map: if guest.features & features_map[feature]: print " " + feature print