#!/usr/local/bin/python class base: @staticmethod def init_class(c, arg): if isinstance(arg, dict): try: return c(**arg) except: print "%s" % arg raise 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 ] def get_attribute(self, key): rv = None attrs = getattr(self, 'attribute', None) if attrs: for a in attrs: if a.attribute == key: rv = a.value break return rv class ConsistencyError(RuntimeError): pass class Attribute(base): def __init__(self, attribute, value): self.attribute = attribute self.value = value def clone(self): return Attribute(attribute=self.attribute, value=self.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 clone(self): return Capacity(rate=self.rate, kind=self.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 clone(self): return Latency(time=self.time, kind=self.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 clone(self): if self.capacity: c = self.capacity.clone() else: c = None if self.latency: l = self.latency.clone() else: l = None return Substrate(name=self.name, capacity=c, latency=l, attribute = [a.clone() for a in self.attribute]) 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 clone(self): return CPU(type=self.type, attribute = [a.clone() for a in self.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 clone(self): return Storage(amount=self.amount, persistence=self.persistence, attribute = [a.clone() for a in self.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=None, 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 clone(self): return OperatingSystem(name=self.name, version=self.version, distribution=self.distribution, distributionversion=self.distributionversion, attribute = [ a.clone() for a in self.attribute]) def to_dict(self): rv = { } if self.name: 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 clone(self): return Software(location=self.location, install=self.install, attribute=[a.clone() for a in self.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): self.substrate = self.make_list(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 clone(self): if self.capacity: c = self.capacity.clone() else: c = None if self.latency: l = self.latency.clone() else: l = None return Interface(substrate=self.substrate, capacity=c, latency=l, attribute = [ a.clone() for a in self.attribute]) 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, name=[], cpu=[], os=[], software=[], storage=[], interface=[], attribute=[]): def assign_element(i): i.element = self self.name = self.make_list(name) 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 clone(self): return Computer(name=self.name, cpu=[x.clone() for x in self.cpu], os=[x.clone() for x in self.os], software=[x.clone() for x in self.software], storage=[x.clone() for x in self.storage], interface=[x.clone() for x in self.interface], attribute=[x.clone() for x in self.attribute]) def to_dict(self): rv = { } if self.name: rv['name'] = self.name 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 { 'computer': 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 clone(self): return Other(interface=[i.clone() for i in self.interface], attribute=[a.clone() for a in 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, } if isinstance(e, dict): for k in e.keys(): cl = classmap.get(k, None) if cl: return cl(**e[k]) else: return e 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) ] self.incorporate_elements() def incorporate_elements(self): # Could to this init in one gulp, but we want to look for duplicate # substrate names substrate_map = { } for s in self.substrates: s.interfaces = [ ] if not substrate_map.has_key(s.name): substrate_map[s.name] = s else: raise ConsistencyError("Duplicate substrate name %s" % s.name) for e in self.elements: for i in e.interface: i.element = e i.subs = [ ] 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 clone(self): return Topology(substrates=[s.clone() for s in self.substrates], elements=[e.clone() for e in self.elements]) def make_indices(self): sub_index = dict([(s.name, s) for s in self.substrates]) elem_index = dict([(n, e) for e in self.elements for n in e.name]) 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(string=None, file=None, filename=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 num_set = len([ x for x in (string, filename, file)\ if x is not None ]) if num_set != 1: raise RuntimeError("Exactly one one of file, filename and string " + \ "must be set") elif filename: f = open(filename, "r") xp.ParseFile(f) elif file: xp.ParseFile(file) elif string: xp.Parse(string, isfinal=True) else: return None 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) def topology_to_vtopo(t): nodes = [ ] lans = [ ] for eidx, e in enumerate(t.elements): n = { } if e.name: name = e.name[0] else: name = "unnamed_node%d" % eidx ips = [ ] for i in e.interfaces: ip = i.get_attribute('ip4_address') ips.append(ip) port = "%s:%d" % (name, idx) for idx, s in enumerate(i.subs): bw = 100000 delay = 0.0 if s.capacity: bw = s.capacity.rate if i.capacity: bw = i.capacity.rate if s.latency: delay = s.latency.time if i.latency: bw = i.latency.time lans.append({ 'member': port, 'vname': s.name, 'ip': ip, 'vnode': name, 'delay': delay, 'bandwidth': bw, }) nodes.append({ 'ips': ":".join(ips), 'vname': name, }) nodes.append(n) return { 'vtopo': { 'node': node, 'lan': lan } }