#!/usr/local/bin/python class base: @staticmethod def init_class(c, arg): if isinstance(arg, dict): return c(**arg) elif isinstance(arg, c): return arg else: return None @staticmethod def make_list(a): if isinstance(a, basestring) or isinstance(a, dict): return [ a ] elif getattr(a, '__iter__', None): return a else: return [ a ] class ConsistencyError(RuntimeError): pass class Attribute(base): def __init__(self, attribute, value): self.attribute = attribute self.value = value def to_dict(self): return { 'attribute': self.attribute, 'value': self.value } class Capacity(base): def __init__(self, rate, kind): self.rate = rate self.kind = kind def to_dict(self): return { 'rate': self.rate, 'kind': self.kind } class Latency(base): def __init__(self, time, kind): self.time = time self.kind = kind def to_dict(self): return { 'time': self.time, 'kind': self.kind } class Substrate(base): def __init__(self, name, capacity=None, latency=None, attribute=[]): self.name = name self.capacity = self.init_class(Capacity, capacity) self.latency = self.init_class(Latency, latency) self.attribute = [ self.init_class(Attribute, a) \ for a in self.make_list(attribute) ] self.interfaces = [ ] def to_dict(self): rv = { 'name': self.name } if self.capacity: rv['capacity'] = self.capacity.to_dict() if self.latency: rv['latency'] = self.latency.to_dict() if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] return rv class CPU(base): def __init__(self, type, attribute=[]): self.type = type self.attribute = [ self.init_class(Attribute, a) for a in \ self.make_list(attribute) ] def to_dict(self): rv = { 'type': self.type} if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] return rv class Storage(base): def __init__(self, amount, persistence, attribute=[]): if isinstance(amount, basestring): self.amount = float(amount) else: self.amount = amount self.presistence = persistence self.attribute = [ self.init_class(Attribute, a) \ for a in self.make_list(attribute) ] def to_dict(self): rv = { 'amount': float(self.amount), 'persistence': self.persistence } if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] return rv class OperatingSystem(base): def __init__(self, name, version=None, distribution=None, distributionversion=None, attribute=[]): self.name = name self.version = version self.distribution = distribution self.distributionversion = distributionversion self.attribute = [ self.init_class(Attribute, a) \ for a in self.make_list(attribute) ] def to_dict(self): rv = { 'name': self.name } if self.version: rv['version'] = self.version if self.distribution: rv['version'] = self.distribution if self.distributionversion: rv['version'] = self.distributionversion if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] return rv class Software(base): def __init__(self, location, install=None, attribute=[]): self.location = location self.install = install self.attribute = [ self.init_class(Attribute, a)\ for a in self.make_list(attribute) ] def to_dict(self): rv = { 'location': self.location } if self.install: rv['install'] = self.install if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] return rv class Interface(base): def __init__(self, substrate, capacity=None, latency=None, attribute=[], element=None): if isinstance(substrate, basestring): self.substrate = [ substrate ] else: self.substrate = substrate self.capacity = self.init_class(Capacity, capacity) self.latency = self.init_class(Latency, latency) self.attribute = [ self.init_class(Attribute, a) \ for a in self.make_list(attribute) ] self.element = element self.subs = [ ] def to_dict(self): rv = { 'substrate': self.substrate } if self.capacity: rv['capacity'] = self.capacity.to_dict() if self.latency: rv['latency'] = self.latency.to_dict() if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] return rv class Computer(base): def __init__(self, cpu=[], os=[], software=[], storage=[], interface=[], attribute=[]): def assign_element(i): i.element = self self.cpu = [ self.init_class(CPU, c) for c in self.make_list(cpu) ] self.os = [ self.init_class(OperatingSystem, c) \ for c in self.make_list(os) ] self.software = [ self.init_class(Software, c) \ for c in self.make_list(software) ] self.storage = [ self.init_class(Storage, c) \ for c in self.make_list(storage) ] self.interface = [ self.init_class(Interface, c) \ for c in self.make_list(interface) ] self.attribute = [ self.init_class(Attribute, a) \ for a in self.make_list(attribute) ] map(assign_element, self.interface) def to_dict(self): rv = { } if self.cpu: rv['cpu'] = [ c.to_dict() for c in self.cpu ] if self.os: rv['os'] = [ o.to_dict() for o in self.os ] if self.software: rv['software'] = [ s.to_dict() for s in self.software ] if self.storage: rv['storage'] = [ s.to_dict for s in self.storage ] if self.interface: rv['interface'] = [ i.to_dict() for i in self.interface ] if self.attribute: rv['attribute'] = [ i.to_dict() for i in self.attribute ] return rv class Other(base): def __init__(self, interface=[], attribute=[]): self.interface = [ self.init_class(Interface, c) \ for c in self.make_list(interface) ] self.attribute = [ self.init_class(Attribute, c) \ for c in self.make_list(attribute) ] def to_dict(self): if self.interface: rv['interface'] = [ i.to_dict() for i in self.interface ] if self.attribute: rv['attribute'] = [ a.to_dict() for a in self.attribute ] class Topology(base): @staticmethod def init_element(e): """ e should be of the form { typename: args } where args is a dict full of the right parameters to initialize the element. e should have only one key, but we walk e's keys in an arbitrary order and instantiate the first key we know how to. """ classmap = { 'computer': Computer, 'other': Other, } for k in e.keys(): cl = classmap.get(k, None) if cl: return cl(**e[k]) def __init__(self, substrates=[], elements=[]): self.substrates = [ self.init_class(Substrate, s) \ for s in self.make_list(substrates) ] self.elements = [ self.init_element(e) \ for e in self.make_list(elements) ] # Could to this init in one gulp, but we want to look for duplicate # substrate names substrate_map = { } for s in self.substrates: if not substrate_map.has_key(s.name): substrate_map[s.name] = s else: raise ConsistencyError("Duplicate substrate name %s" % s.name) substrate_map = dict([ (s.name, s) for s in self.substrates ]) for e in self.elements: for i in e.interface: for sn in i.substrate: # NB, interfaces have substrate names in their substrate # attribute. if substrate_map.has_key(sn): sub = substrate_map[sn] i.subs.append(sub) sub.interfaces.append(i) else: raise ConsistencyError("No such substrate for %s" % sn) def to_dict(self): rv = { } if self.substrates: rv['substrates'] = [ s.to_dict() for s in self.substrates ] if self.elements: rv['elements'] = [ s.to_dict() for s in self.elements ] return rv def topology_from_xml(file=None, top="topology"): import xml.parsers.expat class parser: def __init__(self): self.stack = [ ] self.chars = "" self.key = "" self.have_chars = False self.current = { } self.in_cdata = False def start_element(self, name, attrs): self.chars = "" self.have_chars = False self.key = str(name) self.stack.append((self.current, self.key)) self.current = { } def end_element(self, name): if self.have_chars: self.chars = self.chars.strip() if len(self.chars) >0: addit = self.chars else: addit = self.current else: addit = self.current parent, key = self.stack.pop() if parent.has_key(key): if isinstance(parent[key], list): parent[key].append(addit) else: parent[key] = [parent[key], addit] else: parent[key] = addit self.current = parent self.key = key self.chars = "" self.have_chars = False def char_data(self, data): self.have_chars = True self.chars += data p = parser() xp = xml.parsers.expat.ParserCreate() xp.StartElementHandler = p.start_element xp.EndElementHandler = p.end_element xp.CharacterDataHandler = p.char_data f = open(file, "r") xp.ParseFile(f) return Topology(**p.current[top]) def topology_to_xml(t, top=None): """ Print the topology as XML. This is quick and dirty, but should work for many purposes. Convert the topology to a dict and print it recursively. """ from xml.sax.saxutils import escape def dict_to_xml(e, top=None): if top: rv = "<%s>" % top else: rv = "" for k in e.keys(): if isinstance(e[k], (basestring, int, float, long)): rv += "<%s>%s" % (k, escape(e[k]), k) elif isinstance(e[k], dict): rv += "<%s>%s" % (k, dict_to_xml(e[k]), k) elif getattr(e[k], '__iter__', None): for ee in e[k]: if isinstance(ee, dict): rv += "<%s>%s" % (k, dict_to_xml(ee), k) else: rv += "<%s>%s" % (k, escape(ee), k) else: raise ConsistencyError("What is this?? %s %s" % (k, e[k])) if top: rv += "" % top return rv return dict_to_xml(t.to_dict(), top)