source: fedd/federation/topdl.py @ cc8d8e9

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

checkpoint

  • Property mode set to 100644
File size: 15.7 KB
Line 
1#!/usr/local/bin/python
2
3class base:
4    @staticmethod
5    def init_class(c, arg):
6        if isinstance(arg, dict):
7            try:
8                return c(**arg)
9            except:
10                print "%s" % arg
11                raise
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
23    def get_attribute(self, key):
24        rv = None
25        attrs = getattr(self, 'attribute', None)
26        if attrs:
27            for a in attrs:
28                if a.attribute == key:
29                    rv = a.value
30                    break
31        return rv
32
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
42    def clone(self):
43        return Attribute(attribute=self.attribute, value=self.value)
44
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 = float(rate)
51        self.kind = kind
52
53    def clone(self):
54        return Capacity(rate=self.rate, kind=self.kind)
55
56    def to_dict(self):
57        return { 'rate': float(self.rate), 'kind': self.kind }
58
59class Latency(base):
60    def __init__(self, time, kind):
61        self.time = float(time)
62        self.kind = kind
63
64    def clone(self):
65        return Latency(time=self.time, kind=self.kind)
66
67    def to_dict(self):
68        return { 'time': float(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
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
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
107    def clone(self):
108        return CPU(type=self.type,
109                attribute = [a.clone() for a in self.attribute])
110
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        self.amount = float(amount)
120        self.presistence = persistence
121        self.attribute = [ self.init_class(Attribute, a) \
122                for a in self.make_list(attribute) ]
123
124    def clone(self):
125        return Storage(amount=self.amount, persistence=self.persistence, 
126                attribute = [a.clone() for a in self.attribute])
127
128    def to_dict(self):
129        rv = { 'amount': float(self.amount), 'persistence': self.persistence }
130        if self.attribute:
131            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
132        return rv
133
134class OperatingSystem(base):
135    def __init__(self, name=None, version=None, distribution=None,
136            distributionversion=None, attribute=[]):
137        self.name = name
138        self.version = version
139        self.distribution = distribution
140        self.distributionversion = distributionversion
141        self.attribute = [ self.init_class(Attribute, a) \
142                for a in self.make_list(attribute) ]
143
144    def clone(self):
145        return OperatingSystem(name=self.name,
146                version=self.version,
147                distribution=self.distribution,
148                distributionversion=self.distributionversion,
149                attribute = [ a.clone() for a in self.attribute])
150
151    def to_dict(self):
152        rv = { }
153        if self.name: rv['name'] = self.name
154        if self.version: rv['version'] = self.version
155        if self.distribution: rv['version'] = self.distribution
156        if self.distributionversion: rv['version'] = self.distributionversion
157        if self.attribute:
158            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
159        return rv
160
161class Software(base):
162    def __init__(self, location, install=None, attribute=[]):
163        self.location = location
164        self.install = install
165        self.attribute = [ self.init_class(Attribute, a)\
166                for a in self.make_list(attribute) ]
167
168    def clone(self):
169        return Software(location=self.location, install=self.install, 
170                attribute=[a.clone() for a in self.attribute])
171
172    def to_dict(self):
173        rv = { 'location': self.location }
174        if self.install: rv['install'] = self.install
175        if self.attribute:
176            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
177        return rv
178
179class Interface(base):
180    def __init__(self, substrate, capacity=None, latency=None, attribute=[],
181            element=None):
182        self.substrate = self.make_list(substrate)
183        self.capacity = self.init_class(Capacity, capacity)
184        self.latency = self.init_class(Latency, latency)
185        self.attribute = [ self.init_class(Attribute, a) \
186                for a in self.make_list(attribute) ]
187        self.element = element
188        self.subs = [ ]
189
190    def clone(self):
191        if self.capacity: c = self.capacity.clone()
192        else: c = None
193
194        if self.latency: l = self.latency.clone()
195        else: l = None
196
197        return Interface(substrate=self.substrate,
198                capacity=c, latency=l,
199                attribute = [ a.clone() for a in self.attribute])
200
201    def to_dict(self):
202        rv = { 'substrate': self.substrate }
203        if self.capacity:
204            rv['capacity'] = self.capacity.to_dict()
205        if self.latency:
206            rv['latency'] = self.latency.to_dict()
207        if self.attribute:
208            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
209        return rv
210
211class Computer(base):
212    def __init__(self, name=[], cpu=[], os=[], software=[], storage=[],
213            interface=[], attribute=[]):
214        def assign_element(i):
215            i.element = self
216
217        self.name = self.make_list(name)
218        self.cpu = [ self.init_class(CPU, c)  for c in self.make_list(cpu) ]
219        self.os = [ self.init_class(OperatingSystem, c) \
220                for c in self.make_list(os) ]
221        self.software = [ self.init_class(Software, c) \
222                for c in self.make_list(software) ]
223        self.storage = [ self.init_class(Storage, c) \
224                for c in self.make_list(storage) ]
225        self.interface = [ self.init_class(Interface, c) \
226                for c in self.make_list(interface) ]
227        self.attribute = [ self.init_class(Attribute, a) \
228                for a in self.make_list(attribute) ]
229        map(assign_element, self.interface)
230
231    def clone(self):
232        return Computer(name=self.name,
233                cpu=[x.clone() for x in self.cpu],
234                os=[x.clone() for x in self.os],
235                software=[x.clone() for x in self.software],
236                storage=[x.clone() for x in self.storage],
237                interface=[x.clone() for x in self.interface],
238                attribute=[x.clone() for x in self.attribute])
239
240    def to_dict(self):
241        rv = { }
242        if self.name:
243            rv['name'] = self.name
244        if self.cpu:
245            rv['cpu'] = [ c.to_dict() for  c in self.cpu ]
246        if self.os:
247            rv['os'] = [ o.to_dict() for o in self.os ]
248        if self.software:
249            rv['software'] = [ s.to_dict() for s in self.software ]
250        if self.storage:
251            rv['storage'] = [ s.to_dict for s in self.storage ]
252        if self.interface:
253            rv['interface'] = [ i.to_dict() for i in self.interface ]
254        if self.attribute:
255            rv['attribute'] = [ i.to_dict() for i in self.attribute ]
256        return { 'computer': rv }
257
258class Other(base):
259    def __init__(self, interface=[], attribute=[]):
260        self.interface = [ self.init_class(Interface, c) \
261                for c in self.make_list(interface) ]
262        self.attribute = [ self.init_class(Attribute, c) \
263                for c in self.make_list(attribute) ]
264
265    def clone(self):
266        return Other(interface=[i.clone() for i in self.interface], 
267                attribute=[a.clone() for a in attribute])
268
269    def to_dict(self):
270        if self.interface:
271            rv['interface'] = [ i.to_dict() for i in self.interface ]
272        if self.attribute:
273            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
274
275
276class Topology(base):
277    @staticmethod
278    def init_element(e):
279        """
280        e should be of the form { typename: args } where args is a dict full of
281        the right parameters to initialize the element.  e should have only one
282        key, but we walk e's keys in an arbitrary order and instantiate the
283        first key we know how to.
284        """
285        classmap = {
286                'computer': Computer,
287                'other': Other,
288            }
289
290        if isinstance(e, dict):
291            for k in e.keys():
292                cl = classmap.get(k, None)
293                if cl: return cl(**e[k])
294        else:
295            return e
296
297    def __init__(self, substrates=[], elements=[]):
298        self.substrates = [ self.init_class(Substrate, s) \
299                for s in self.make_list(substrates) ]
300        self.elements = [ self.init_element(e) \
301                for e in self.make_list(elements) ]
302        self.incorporate_elements()
303
304    def incorporate_elements(self):
305
306        # Could to this init in one gulp, but we want to look for duplicate
307        # substrate names
308        substrate_map = { }
309        for s in self.substrates:
310            s.interfaces = [ ]
311            if not substrate_map.has_key(s.name):
312                substrate_map[s.name] = s
313            else:
314                raise ConsistencyError("Duplicate substrate name %s" % s.name)
315
316        for e in self.elements:
317            for i in e.interface:
318                i.element = e
319                i.subs = [ ]
320                for sn in i.substrate:
321                    # NB, interfaces have substrate names in their substrate
322                    # attribute.
323                    if substrate_map.has_key(sn):
324                        sub = substrate_map[sn]
325                        i.subs.append(sub)
326                        sub.interfaces.append(i)
327                    else:
328                        raise ConsistencyError("No such substrate for %s" % sn)
329
330    def clone(self):
331        return Topology(substrates=[s.clone() for s in self.substrates], 
332                elements=[e.clone() for e in self.elements])
333
334
335    def make_indices(self):
336        sub_index = dict([(s.name, s) for s in self.substrates])
337        elem_index = dict([(n, e) for e in self.elements for n in e.name])
338
339    def to_dict(self):
340        rv = { }
341        if self.substrates:
342            rv['substrates'] = [ s.to_dict() for s in self.substrates ]
343        if self.elements:
344            rv['elements'] = [ s.to_dict() for s in self.elements ]
345        return rv
346
347def topology_from_xml(string=None, file=None, filename=None, top="topology"):
348    import xml.parsers.expat
349
350    class parser:
351        def __init__(self):
352            self.stack = [ ]
353            self.chars = ""
354            self.key = ""
355            self.have_chars = False
356            self.current = { }
357            self.in_cdata = False
358       
359        def start_element(self, name, attrs):
360            self.chars = ""
361            self.have_chars = False
362            self.key = str(name)
363            self.stack.append((self.current, self.key))
364            self.current = { }
365
366        def end_element(self, name):
367            if self.have_chars:
368                self.chars = self.chars.strip()
369                if len(self.chars) >0:
370                    addit = self.chars
371                else:
372                    addit = self.current
373            else:
374                addit = self.current
375
376            parent, key = self.stack.pop()
377            if parent.has_key(key):
378                if isinstance(parent[key], list):
379                    parent[key].append(addit)
380                else:
381                    parent[key] = [parent[key], addit]
382            else:
383                parent[key] = addit
384            self.current = parent
385            self.key = key
386
387            self.chars = ""
388            self.have_chars = False
389
390        def char_data(self, data):
391            self.have_chars = True
392            self.chars += data
393
394    p = parser()
395    xp = xml.parsers.expat.ParserCreate()
396
397    xp.StartElementHandler = p.start_element
398    xp.EndElementHandler = p.end_element
399    xp.CharacterDataHandler = p.char_data
400
401    num_set = len([ x for x in (string, filename, file)\
402            if x is not None ])
403
404    if num_set != 1:
405        raise RuntimeError("Exactly one one of file, filename and string " + \
406                "must be set")
407    elif filename:
408        f = open(filename, "r")
409        xp.ParseFile(f)
410        f.close()
411    elif file:
412        xp.ParseFile(file)
413    elif string:
414        xp.Parse(string, isfinal=True)
415    else:
416        return None
417
418    return Topology(**p.current[top])
419
420def topology_to_xml(t, top=None):
421    """
422    Print the topology as XML.  This is quick and dirty, but should work for
423    many purposes.  Convert the topology to a dict and print it recursively.
424    """
425    from xml.sax.saxutils import escape
426
427    def dict_to_xml(e, top=None):
428        if top: rv = "<%s>" % top
429        else: rv = ""
430
431        for k in e.keys():
432            if isinstance(e[k], (basestring, int, float, long)):
433                rv += "<%s>%s</%s>" % (k, escape(e[k]), k)
434            elif isinstance(e[k], dict):
435                rv += "<%s>%s</%s>" % (k, dict_to_xml(e[k]), k)
436            elif getattr(e[k], '__iter__', None):
437                for ee in e[k]:
438                    if isinstance(ee, dict):
439                        rv += "<%s>%s</%s>" % (k, dict_to_xml(ee), k)
440                    else:
441                        rv += "<%s>%s</%s>" % (k, escape(ee), k)
442            else:
443                raise ConsistencyError("What is this?? %s %s" % (k, e[k]))
444        if top: rv += "</%s>" % top
445        return rv
446
447    return dict_to_xml(t.to_dict(), top)
448
449
450def topology_to_vtopo(t):
451    nodes = [ ]
452    lans = [ ]
453
454    for eidx, e in enumerate(t.elements):
455        if e.name: name = e.name[0]
456        else: name = "unnamed_node%d" % eidx
457       
458        ips = [ ]
459        for idx, i in enumerate(e.interface):
460            ip = i.get_attribute('ip4_address')
461            ips.append(ip)
462            port = "%s:%d" % (name, idx)
463            for idx, s in enumerate(i.subs):
464                bw = 100000
465                delay = 0.0
466                if s.capacity:
467                    bw = s.capacity.rate
468                if i.capacity:
469                    bw = i.capacity.rate
470
471                if s.latency:
472                    delay = s.latency.time
473                if i.latency:
474                    bw = i.latency.time
475
476                lans.append({
477                    'member': port,
478                    'vname': s.name,
479                    'ip': ip,
480                    'vnode': name,
481                    'delay': delay,
482                    'bandwidth': bw,
483                    })
484        nodes.append({
485            'ips': ":".join(ips),
486            'vname': name,
487            })
488
489    return { 'node': nodes, 'lan': lans }
490
491def topology_to_ns2(t):
492    out = """
493set ns [new Simulator]
494source tb_compat.tcl
495
496"""
497    for e in t.elements:
498        rpms = ""
499        tarfiles = ""
500        if isinstance(e, Computer):
501            name = e.name[0]
502            out += "set %s [$ns node]\n" % name
503            if e.os and len(e.os) == 1:
504                osid = e.os[0].get_attribute('osid')
505                if osid:
506                    out += "tb-set-node-os $%s %s\n" % (name, osid)
507            for s in e.software:
508                if s.install:
509                    tarfiles += "%s %s " % (s.install, s.location)
510                else:
511                    rpms += "%s " % s.location
512            if rpms:
513                out += "tb-set-node-rpms $%s %s\n" % (name, rpms)
514            if tarfiles:
515                out += "tb-set-node-tarfiles $%s %s\n" % (name, tarfiles)
516            startcmd = e.get_attribute('startup')
517            if startcmd:
518                out+= 'tb-set-node-startcmd $%s "%s"\n' % (name, startcmd)
519            out+= "\n"
520   
521    for idx, s in enumerate(t.substrates):
522        loss = s.get_attribute('loss')
523        if s.latency:
524            delay = s.latency.time
525        else:
526            delay = 0
527        name = s.name or "sub%d" % idx
528
529        if len(s.interfaces) > 2:
530            # Lan
531            members = [ i.element.name[0] for i in s.interfaces]
532            out += 'set %s [$ns make-lan "%s" %f %fms ]\n' % \
533                    (name, " ".join(members), s.capacity.rate, delay)
534            if loss:
535                "tb-set-lan-loss $%s %f\n" % (name, float(loss))
536
537            for i in s.interfaces:
538                e = i.element
539                ip = e.get_attribute("ip4_address")
540                if ip:
541                    out += "tb-set-ip-lan $%s $%s %s\n" % (e.name, name, ip)
542                if i.capacity and i.capacity.rate != s.capacity.rate:
543                    out += "tb-set-node-lan-bandwidth $%s $%s %f\n" % \
544                            (e.name[0], name, i.capacity.rate)
545                if i.latency and i.latency.time != delay:
546                    out += "tb-set-node-lan-delay $%s $%s %fms\n" % \
547                            (e.name[0], name, i.latency.time)
548                iloss = i.get_attribute('loss')
549                if loss and iloss != loss :
550                    out += "tb-set-node-lan-loss $%s $%s %f" % \
551                            (e.name[0], name, float(loss))
552            out+= "\n"
553        elif len(s.interfaces) == 2:
554            f = s.interfaces[0]
555            t = s.interfaces[1]
556
557            out += "set %s [$ns duplex-link $%s $%s %f %fms DropTail]\n" %\
558                    (name, f.element.name[0], t.element.name[0],
559                            s.capacity.rate, delay)
560            if loss:
561                out += "tb-set-link-loss $%s %f\n" % (name, float(loss))
562
563            for i in s.interfaces:
564                lloss = i.get_attribute("loss")
565                cap_override = i.capacity and \
566                        i.capacity.rate != s.capacity.rate
567                delay_override = i.latency and \
568                        i.latency.time != delay
569                loss_override = lloss and lloss != loss
570                if cap_override or delay_override or loss_override:
571                    if i.capacity: cap = i.capacity.rate
572                    else: cap = s.capacity.rate
573
574                    if i.latency: delay = i.latency.time
575
576                    if lloss: loss = lloss
577                    else: loss = loss or 0.0
578
579                    out += "tb-set-link-simplex-params $%s $%s %fms %f %f\n" % \
580                            (name, i.element.name[0], delay, cap, loss)
581            out+= "\n"
582    out+="""
583$ns run
584"""
585    return out
Note: See TracBrowser for help on using the repository browser.