source: fedd/federation/topdl.py @ 1fda364

axis_examplecompt_changesinfo-opsversion-2.00version-3.01version-3.02
Last change on this file since 1fda364 was db6b092, checked in by Ted Faber <faber@…>, 15 years ago

Checkpoint (and whitespace in experiment_control)

  • Property mode set to 100644
File size: 13.0 KB
RevLine 
[eec716b]1#!/usr/local/bin/python
2
3class base:
4    @staticmethod
5    def init_class(c, arg):
6        if isinstance(arg, dict):
[df783c1]7            try:
8                return c(**arg)
9            except:
10                print "%s" % arg
11                raise
[eec716b]12        elif isinstance(arg, c):
13            return arg
14        else:
15            return None
16
17    @staticmethod
18    def make_list(a):
19        if isinstance(a, basestring) or isinstance(a, dict): return [ a ]
20        elif getattr(a, '__iter__', None): return a
21        else: return [ a ]
22
[df783c1]23    def get_attribute(self, key):
24        rv = None
[db6b092]25        attrs = getattr(self, 'attribute', None)
[df783c1]26        if attrs:
27            for a in attrs:
28                if a.attribute == key:
29                    rv = a.value
30                    break
31        return rv
32
[eec716b]33
34
35class ConsistencyError(RuntimeError): pass
36
37class Attribute(base):
38    def __init__(self, attribute, value):
39        self.attribute = attribute
40        self.value = value
41
[db6b092]42    def clone(self):
43        return Attribute(attribute=self.attribute, value=self.value)
44
[eec716b]45    def to_dict(self):
46        return { 'attribute': self.attribute, 'value': self.value }
47
48class Capacity(base):
49    def __init__(self, rate, kind):
50        self.rate = rate
51        self.kind = kind
52
[db6b092]53    def clone(self):
54        return Capacity(rate=self.rate, kind=self.kind)
55
[eec716b]56    def to_dict(self):
57        return { 'rate': self.rate, 'kind': self.kind }
58
59class Latency(base):
60    def __init__(self, time, kind):
61        self.time = time
62        self.kind = kind
63
[db6b092]64    def clone(self):
65        return Latency(time=self.time, kind=self.kind)
66
[eec716b]67    def to_dict(self):
68        return { 'time': self.time, 'kind': self.kind }
69
70class Substrate(base):
71    def __init__(self, name, capacity=None, latency=None, attribute=[]):
72        self.name = name
73        self.capacity = self.init_class(Capacity, capacity)
74        self.latency = self.init_class(Latency, latency)
75        self.attribute = [ self.init_class(Attribute, a) \
76                for a in self.make_list(attribute) ]
77        self.interfaces = [ ]
78
[db6b092]79    def clone(self):
80        if self.capacity: c = self.capacity.clone()
81        else: c = None
82
83        if self.latency: l = self.latency.clone()
84        else: l = None
85
86        return Substrate(name=self.name,
87                capacity=c,
88                latency=l,
89                attribute = [a.clone() for a in self.attribute])
90
[eec716b]91    def to_dict(self):
92        rv = { 'name': self.name }
93        if self.capacity:
94            rv['capacity'] = self.capacity.to_dict()
95        if self.latency:
96            rv['latency'] = self.latency.to_dict()
97        if self.attribute:
98            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
99        return rv
100
101class CPU(base):
102    def __init__(self, type, attribute=[]):
103        self.type = type
104        self.attribute = [ self.init_class(Attribute, a) for a in \
105                self.make_list(attribute) ]
106
[db6b092]107    def clone(self):
108        return CPU(type=self.type,
109                attribute = [a.clone() for a in self.attribute])
110
[eec716b]111    def to_dict(self):
112        rv = { 'type': self.type}
113        if self.attribute:
114            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
115        return rv
116
117class Storage(base):
118    def __init__(self, amount, persistence, attribute=[]):
119        if isinstance(amount, basestring):
120            self.amount = float(amount)
121        else:
122            self.amount = amount
123        self.presistence = persistence
124        self.attribute = [ self.init_class(Attribute, a) \
125                for a in self.make_list(attribute) ]
126
[db6b092]127    def clone(self):
128        return Storage(amount=self.amount, persistence=self.persistence, 
129                attribute = [a.clone() for a in self.attribute])
130
[eec716b]131    def to_dict(self):
132        rv = { 'amount': float(self.amount), 'persistence': self.persistence }
133        if self.attribute:
134            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
135        return rv
136
137class OperatingSystem(base):
[df783c1]138    def __init__(self, name=None, version=None, distribution=None,
[eec716b]139            distributionversion=None, attribute=[]):
140        self.name = name
141        self.version = version
142        self.distribution = distribution
143        self.distributionversion = distributionversion
144        self.attribute = [ self.init_class(Attribute, a) \
145                for a in self.make_list(attribute) ]
146
[db6b092]147    def clone(self):
148        return OperatingSystem(name=self.name,
149                version=self.version,
150                distribution=self.distribution,
151                distributionversion=self.distributionversion,
152                attribute = [ a.clone() for a in self.attribute])
153
[eec716b]154    def to_dict(self):
[df783c1]155        rv = { }
156        if self.name: rv['name'] = self.name
[eec716b]157        if self.version: rv['version'] = self.version
158        if self.distribution: rv['version'] = self.distribution
159        if self.distributionversion: rv['version'] = self.distributionversion
160        if self.attribute:
161            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
162        return rv
163
164class Software(base):
165    def __init__(self, location, install=None, attribute=[]):
166        self.location = location
167        self.install = install
168        self.attribute = [ self.init_class(Attribute, a)\
169                for a in self.make_list(attribute) ]
170
[db6b092]171    def clone(self):
172        return Software(location=self.location, install=self.install, 
173                attribute=[a.clone() for a in self.attribute])
174
[eec716b]175    def to_dict(self):
176        rv = { 'location': self.location }
177        if self.install: rv['install'] = self.install
178        if self.attribute:
179            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
180        return rv
181
182class Interface(base):
183    def __init__(self, substrate, capacity=None, latency=None, attribute=[],
184            element=None):
[cdb62d9]185        self.substrate = self.make_list(substrate)
[eec716b]186        self.capacity = self.init_class(Capacity, capacity)
187        self.latency = self.init_class(Latency, latency)
188        self.attribute = [ self.init_class(Attribute, a) \
189                for a in self.make_list(attribute) ]
190        self.element = element
191        self.subs = [ ]
192
[db6b092]193    def clone(self):
194        if self.capacity: c = self.capacity.clone()
195        else: c = None
196
197        if self.latency: l = self.latency.clone()
198        else: l = None
199
200        return Interface(substrate=self.substrate,
201                capacity=c, latency=l,
202                attribute = [ a.clone() for a in self.attribute])
203
[eec716b]204    def to_dict(self):
205        rv = { 'substrate': self.substrate }
206        if self.capacity:
207            rv['capacity'] = self.capacity.to_dict()
208        if self.latency:
209            rv['latency'] = self.latency.to_dict()
210        if self.attribute:
211            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
212        return rv
213
214class Computer(base):
[cdb62d9]215    def __init__(self, name=[], cpu=[], os=[], software=[], storage=[],
216            interface=[], attribute=[]):
[eec716b]217        def assign_element(i):
218            i.element = self
219
[cdb62d9]220        self.name = self.make_list(name)
[eec716b]221        self.cpu = [ self.init_class(CPU, c)  for c in self.make_list(cpu) ]
222        self.os = [ self.init_class(OperatingSystem, c) \
223                for c in self.make_list(os) ]
224        self.software = [ self.init_class(Software, c) \
225                for c in self.make_list(software) ]
226        self.storage = [ self.init_class(Storage, c) \
227                for c in self.make_list(storage) ]
228        self.interface = [ self.init_class(Interface, c) \
229                for c in self.make_list(interface) ]
230        self.attribute = [ self.init_class(Attribute, a) \
231                for a in self.make_list(attribute) ]
232        map(assign_element, self.interface)
233
[db6b092]234    def clone(self):
235        return Computer(name=self.name,
236                cpu=[x.clone() for x in self.cpu],
237                os=[x.clone() for x in self.os],
238                software=[x.clone() for x in self.software],
239                storage=[x.clone() for x in self.storage],
240                interface=[x.clone() for x in self.interface],
241                attribute=[x.clone() for x in self.attribute])
242
[eec716b]243    def to_dict(self):
244        rv = { }
[db6b092]245        if self.name:
246            rv['name'] = self.name
[eec716b]247        if self.cpu:
248            rv['cpu'] = [ c.to_dict() for  c in self.cpu ]
249        if self.os:
250            rv['os'] = [ o.to_dict() for o in self.os ]
251        if self.software:
252            rv['software'] = [ s.to_dict() for s in self.software ]
253        if self.storage:
254            rv['storage'] = [ s.to_dict for s in self.storage ]
255        if self.interface:
256            rv['interface'] = [ i.to_dict() for i in self.interface ]
257        if self.attribute:
258            rv['attribute'] = [ i.to_dict() for i in self.attribute ]
[cdb62d9]259        return { 'computer': rv }
[eec716b]260
261class Other(base):
262    def __init__(self, interface=[], attribute=[]):
263        self.interface = [ self.init_class(Interface, c) \
264                for c in self.make_list(interface) ]
265        self.attribute = [ self.init_class(Attribute, c) \
266                for c in self.make_list(attribute) ]
267
[db6b092]268    def clone(self):
269        return Other(interface=[i.clone() for i in self.interface], 
270                attribute=[a.clone() for a in attribute])
271
[eec716b]272    def to_dict(self):
273        if self.interface:
274            rv['interface'] = [ i.to_dict() for i in self.interface ]
275        if self.attribute:
276            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
277
278
279class Topology(base):
280    @staticmethod
281    def init_element(e):
282        """
283        e should be of the form { typename: args } where args is a dict full of
284        the right parameters to initialize the element.  e should have only one
285        key, but we walk e's keys in an arbitrary order and instantiate the
286        first key we know how to.
287        """
288        classmap = {
289                'computer': Computer,
290                'other': Other,
291            }
292
[db6b092]293        if isinstance(e, dict):
294            for k in e.keys():
295                cl = classmap.get(k, None)
296                if cl: return cl(**e[k])
297        else:
298            return e
[eec716b]299
300    def __init__(self, substrates=[], elements=[]):
301        self.substrates = [ self.init_class(Substrate, s) \
302                for s in self.make_list(substrates) ]
303        self.elements = [ self.init_element(e) \
304                for e in self.make_list(elements) ]
[db6b092]305        self.incorporate_elements()
306
307    def incorporate_elements(self):
308
[eec716b]309        # Could to this init in one gulp, but we want to look for duplicate
310        # substrate names
311        substrate_map = { }
312        for s in self.substrates:
[db6b092]313            s.interfaces = [ ]
[eec716b]314            if not substrate_map.has_key(s.name):
315                substrate_map[s.name] = s
316            else:
317                raise ConsistencyError("Duplicate substrate name %s" % s.name)
318
319        for e in self.elements:
320            for i in e.interface:
[db6b092]321                i.element = e
322                i.subs = [ ]
[eec716b]323                for sn in i.substrate:
324                    # NB, interfaces have substrate names in their substrate
325                    # attribute.
326                    if substrate_map.has_key(sn):
327                        sub = substrate_map[sn]
328                        i.subs.append(sub)
329                        sub.interfaces.append(i)
330                    else:
331                        raise ConsistencyError("No such substrate for %s" % sn)
332
[db6b092]333    def clone(self):
334        return Topology(substrates=[s.clone() for s in self.substrates], 
335                elements=[e.clone() for e in self.elements])
336
337
338    def make_indices(self):
339        sub_index = dict([(s.name, s) for s in self.substrates])
340        elem_index = dict([(n, e) for e in self.elements for n in e.name])
341
[eec716b]342    def to_dict(self):
343        rv = { }
344        if self.substrates:
345            rv['substrates'] = [ s.to_dict() for s in self.substrates ]
346        if self.elements:
347            rv['elements'] = [ s.to_dict() for s in self.elements ]
348        return rv
349
[db6b092]350def topology_from_xml(string=None, file=None, filename=None, top="topology"):
[eec716b]351    import xml.parsers.expat
352
353    class parser:
354        def __init__(self):
355            self.stack = [ ]
356            self.chars = ""
357            self.key = ""
358            self.have_chars = False
359            self.current = { }
360            self.in_cdata = False
361       
362        def start_element(self, name, attrs):
363            self.chars = ""
364            self.have_chars = False
365            self.key = str(name)
366            self.stack.append((self.current, self.key))
367            self.current = { }
368
369        def end_element(self, name):
370            if self.have_chars:
371                self.chars = self.chars.strip()
372                if len(self.chars) >0:
373                    addit = self.chars
374                else:
375                    addit = self.current
376            else:
377                addit = self.current
378
379            parent, key = self.stack.pop()
380            if parent.has_key(key):
381                if isinstance(parent[key], list):
382                    parent[key].append(addit)
383                else:
384                    parent[key] = [parent[key], addit]
385            else:
386                parent[key] = addit
387            self.current = parent
388            self.key = key
389
390            self.chars = ""
391            self.have_chars = False
392
393        def char_data(self, data):
394            self.have_chars = True
395            self.chars += data
396
397    p = parser()
398    xp = xml.parsers.expat.ParserCreate()
399
400    xp.StartElementHandler = p.start_element
401    xp.EndElementHandler = p.end_element
402    xp.CharacterDataHandler = p.char_data
403
[db6b092]404    num_set = len([ x for x in (string, filename, file)\
405            if x is not None ])
406
407    if num_set != 1:
408        raise RuntimeError("Exactly one one of file, filename and string " + \
409                "must be set")
410    elif filename:
411        f = open(filename, "r")
[df783c1]412        xp.ParseFile(f)
[db6b092]413    elif file:
414        xp.ParseFile(file)
[df783c1]415    elif string:
416        xp.Parse(string, isfinal=True)
417    else:
418        return None
[eec716b]419
420    return Topology(**p.current[top])
421
422def topology_to_xml(t, top=None):
423    """
424    Print the topology as XML.  This is quick and dirty, but should work for
425    many purposes.  Convert the topology to a dict and print it recursively.
426    """
427    from xml.sax.saxutils import escape
428
429    def dict_to_xml(e, top=None):
430        if top: rv = "<%s>" % top
431        else: rv = ""
432
433        for k in e.keys():
434            if isinstance(e[k], (basestring, int, float, long)):
435                rv += "<%s>%s</%s>" % (k, escape(e[k]), k)
436            elif isinstance(e[k], dict):
437                rv += "<%s>%s</%s>" % (k, dict_to_xml(e[k]), k)
438            elif getattr(e[k], '__iter__', None):
439                for ee in e[k]:
440                    if isinstance(ee, dict):
441                        rv += "<%s>%s</%s>" % (k, dict_to_xml(ee), k)
442                    else:
443                        rv += "<%s>%s</%s>" % (k, escape(ee), k)
444            else:
445                raise ConsistencyError("What is this?? %s %s" % (k, e[k]))
446        if top: rv += "</%s>" % top
447        return rv
448
449    return dict_to_xml(t.to_dict(), top)
450
451
[db6b092]452def topology_to_vtopo(t):
453    nodes = [ ]
454    lans = [ ]
[eec716b]455
[db6b092]456    for eidx, e in enumerate(t.elements):
457        n = { }
458        if e.name: name = e.name[0]
459        else: name = "unnamed_node%d" % eidx
460       
461        ips = [ ]
462        for i in e.interfaces:
463            ip = i.get_attribute('ip4_address')
464            ips.append(ip)
465            port = "%s:%d" % (name, idx)
466            for idx, s in enumerate(i.subs):
467                bw = 100000
468                delay = 0.0
469                if s.capacity:
470                    bw = s.capacity.rate
471                if i.capacity:
472                    bw = i.capacity.rate
473
474                if s.latency:
475                    delay = s.latency.time
476                if i.latency:
477                    bw = i.latency.time
478
479                lans.append({
480                    'member': port,
481                    'vname': s.name,
482                    'ip': ip,
483                    'vnode': name,
484                    'delay': delay,
485                    'bandwidth': bw,
486                    })
487        nodes.append({
488            'ips': ":".join(ips),
489            'vname': name,
490            })
491
492        nodes.append(n)
493    return { 'vtopo': { 'node': node, 'lan': lan } }
Note: See TracBrowser for help on using the repository browser.