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

compt_changesinfo-ops
Last change on this file since 1fed67b was 9252414, checked in by Ted Faber <faber@…>, 14 years ago

Add helper for access controlers to extract topology.

Fixes #5

  • Property mode set to 100644
File size: 28.6 KB
RevLine 
[eec716b]1#!/usr/local/bin/python
2
[6c57fe9]3import re
[f9c2f63]4import xml.parsers.expat
[a914b1b]5from xml.sax.saxutils import escape
6from base64 import b64encode
7from string import join
[6c57fe9]8
[da2208a]9from fedid import fedid as fedid_class
10
[eec716b]11class base:
12    @staticmethod
13    def init_class(c, arg):
14        if isinstance(arg, dict):
[df783c1]15            try:
16                return c(**arg)
17            except:
18                print "%s" % arg
19                raise
[eec716b]20        elif isinstance(arg, c):
21            return arg
22        else:
23            return None
24
25    @staticmethod
26    def make_list(a):
27        if isinstance(a, basestring) or isinstance(a, dict): return [ a ]
28        elif getattr(a, '__iter__', None): return a
29        else: return [ a ]
30
[21b5434]31    @staticmethod
32    def init_string(s):
33        """
34        Force a string coercion for everything but a None.
35        """
36        if s is not None: return "%s" % s
37        else: return None
38
[69692a9]39    def remove_attribute(self, key):
40        to_del = None
41        attrs = getattr(self, 'attribute', [])
42        for i, a in enumerate(attrs):
43            if a.attribute == key:
44                to_del = i
45                break
46       
47        if to_del: del attrs[i]
48
[df783c1]49    def get_attribute(self, key):
50        rv = None
[db6b092]51        attrs = getattr(self, 'attribute', None)
[df783c1]52        if attrs:
53            for a in attrs:
54                if a.attribute == key:
55                    rv = a.value
56                    break
57        return rv
58
[6c57fe9]59    def set_attribute(self, key, value):
60        attrs = getattr(self, 'attribute', None)
61        if attrs is None:
62            return
63        for a in attrs:
64            if a.attribute == key: 
65                a.value = value
66                break
67        else:
68            attrs.append(Attribute(key, value))
[eec716b]69
70class ConsistencyError(RuntimeError): pass
[5b74b63]71class NamespaceError(RuntimeError): pass
[eec716b]72
73class Attribute(base):
74    def __init__(self, attribute, value):
[21b5434]75        self.attribute = self.init_string(attribute)
76        self.value = self.init_string(value)
[eec716b]77
[db6b092]78    def clone(self):
79        return Attribute(attribute=self.attribute, value=self.value)
80
[eec716b]81    def to_dict(self):
82        return { 'attribute': self.attribute, 'value': self.value }
[a914b1b]83    def to_xml(self):
84        return "<attribute>%s</attribute><value>%s</value>" % \
85                (escape(self.attribute), escape(self.value))
[eec716b]86
87class Capacity(base):
88    def __init__(self, rate, kind):
[cc8d8e9]89        self.rate = float(rate)
[21b5434]90        self.kind = self.init_string(kind)
[eec716b]91
[db6b092]92    def clone(self):
93        return Capacity(rate=self.rate, kind=self.kind)
94
[eec716b]95    def to_dict(self):
[cc8d8e9]96        return { 'rate': float(self.rate), 'kind': self.kind }
[eec716b]97
[a914b1b]98    def to_xml(self):
99        return "<rate>%f</rate><kind>%s</kind>" % (self.rate, self.kind)
100
[eec716b]101class Latency(base):
102    def __init__(self, time, kind):
[cc8d8e9]103        self.time = float(time)
[21b5434]104        self.kind = self.init_string(kind)
[eec716b]105
[db6b092]106    def clone(self):
107        return Latency(time=self.time, kind=self.kind)
108
[eec716b]109    def to_dict(self):
[cc8d8e9]110        return { 'time': float(self.time), 'kind': self.kind }
[eec716b]111
[a914b1b]112    def to_xml(self):
113        return "<time>%f</time><kind>%s</kind>" % (self.time, self.kind)
114
[eec716b]115class Substrate(base):
116    def __init__(self, name, capacity=None, latency=None, attribute=[]):
[21b5434]117        self.name = self.init_string(name)
[eec716b]118        self.capacity = self.init_class(Capacity, capacity)
119        self.latency = self.init_class(Latency, latency)
120        self.attribute = [ self.init_class(Attribute, a) \
121                for a in self.make_list(attribute) ]
122        self.interfaces = [ ]
123
[db6b092]124    def clone(self):
125        if self.capacity: c = self.capacity.clone()
126        else: c = None
127
128        if self.latency: l = self.latency.clone()
129        else: l = None
130
131        return Substrate(name=self.name,
132                capacity=c,
133                latency=l,
134                attribute = [a.clone() for a in self.attribute])
135
[eec716b]136    def to_dict(self):
137        rv = { 'name': self.name }
138        if self.capacity:
139            rv['capacity'] = self.capacity.to_dict()
140        if self.latency:
141            rv['latency'] = self.latency.to_dict()
142        if self.attribute:
143            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
144        return rv
145
[a914b1b]146    def to_xml(self):
147        rv = "<name>%s</name>" % escape(self.name)
148        if self.capacity is not None:
149            rv += "<capacity>%s</capacity>" % self.capacity.to_xml()
150        if self.latency is not None:
151            rv += "<latency>%s</latency>" % self.latency.to_xml()
152       
153        if self.attribute:
154            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
155                    for a in self.attribute], "")
156        return rv
157
[eec716b]158class CPU(base):
159    def __init__(self, type, attribute=[]):
[21b5434]160        self.type = self.init_string(type)
[eec716b]161        self.attribute = [ self.init_class(Attribute, a) for a in \
162                self.make_list(attribute) ]
163
[db6b092]164    def clone(self):
165        return CPU(type=self.type,
166                attribute = [a.clone() for a in self.attribute])
167
[eec716b]168    def to_dict(self):
169        rv = { 'type': self.type}
170        if self.attribute:
171            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
172        return rv
173
[a914b1b]174    def to_xml(self):
175        rv = "<type>%s</type>" % escape(self.type)
176        if self.attribute:
177            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
178                    for a in self.attribute], "")
179        return rv
180
181
[eec716b]182class Storage(base):
183    def __init__(self, amount, persistence, attribute=[]):
[cc8d8e9]184        self.amount = float(amount)
[21b5434]185        self.presistence = self.init_string(persistence)
[eec716b]186        self.attribute = [ self.init_class(Attribute, a) \
187                for a in self.make_list(attribute) ]
188
[db6b092]189    def clone(self):
190        return Storage(amount=self.amount, persistence=self.persistence, 
191                attribute = [a.clone() for a in self.attribute])
192
[eec716b]193    def to_dict(self):
194        rv = { 'amount': float(self.amount), 'persistence': self.persistence }
195        if self.attribute:
196            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
197        return rv
198
[a914b1b]199    def to_xml(self):
200        rv = "<amount>%f</amount><persistence>%s</persistence>" % \
201                (self.amount, escape(self.persistence))
202        if self.attribute:
203            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
204                    for a in self.attribute], "")
205        return rv
206
207
[eec716b]208class OperatingSystem(base):
[df783c1]209    def __init__(self, name=None, version=None, distribution=None,
[eec716b]210            distributionversion=None, attribute=[]):
[21b5434]211        self.name = self.init_string(name)
212        self.version = self.init_string(version)
213        self.distribution = self.init_string(distribution)
214        self.distributionversion = self.init_string(distributionversion)
[eec716b]215        self.attribute = [ self.init_class(Attribute, a) \
216                for a in self.make_list(attribute) ]
217
[db6b092]218    def clone(self):
219        return OperatingSystem(name=self.name,
220                version=self.version,
221                distribution=self.distribution,
222                distributionversion=self.distributionversion,
223                attribute = [ a.clone() for a in self.attribute])
224
[eec716b]225    def to_dict(self):
[df783c1]226        rv = { }
227        if self.name: rv['name'] = self.name
[eec716b]228        if self.version: rv['version'] = self.version
[a914b1b]229        if self.distribution: rv['distribution'] = self.distribution
230        if self.distributionversion: 
231            rv['distributionversion'] = self.distributionversion
[eec716b]232        if self.attribute:
233            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
234        return rv
235
[a914b1b]236    def to_xml(self):
237        rv = ""
238        if self.name: rv += "<name>%s</name>" % escape(self.name)
239        if self.version: rv += "<version>%s</version>" % escape(self.version)
240        if self.distribution: 
241            rv += "<distribution>%s</distribution>" % escape(self.distribution)
242        if self.distributionversion: 
243            rv += "<distributionversion>%s</distributionversion>" % \
244                    escape(self.distributionversion)
245       
246        if self.attribute:
247            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
248                    for a in self.attribute], "")
249        return rv
250
251
[eec716b]252class Software(base):
253    def __init__(self, location, install=None, attribute=[]):
[21b5434]254        self.location = self.init_string(location)
255        self.install = self.init_string(install)
[eec716b]256        self.attribute = [ self.init_class(Attribute, a)\
257                for a in self.make_list(attribute) ]
258
[db6b092]259    def clone(self):
260        return Software(location=self.location, install=self.install, 
261                attribute=[a.clone() for a in self.attribute])
262
[eec716b]263    def to_dict(self):
264        rv = { 'location': self.location }
265        if self.install: rv['install'] = self.install
266        if self.attribute:
267            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
268        return rv
269
[a914b1b]270    def to_xml(self):
271        rv = "<location>%s</location>" % escape(self.location)
272        if self.install: rv += "<install>%s</install>" % self.install
273        if self.attribute:
274            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
275                    for a in self.attribute], "")
276        return rv
277
278
[eec716b]279class Interface(base):
[5b74b63]280    def __init__(self, substrate, name=None, capacity=None, latency=None,
281            attribute=[], element=None):
[21b5434]282        self.name = self.init_string(name)
283
[cdb62d9]284        self.substrate = self.make_list(substrate)
[eec716b]285        self.capacity = self.init_class(Capacity, capacity)
286        self.latency = self.init_class(Latency, latency)
287        self.attribute = [ self.init_class(Attribute, a) \
288                for a in self.make_list(attribute) ]
289        self.element = element
290        self.subs = [ ]
291
[db6b092]292    def clone(self):
293        if self.capacity: c = self.capacity.clone()
294        else: c = None
295
296        if self.latency: l = self.latency.clone()
297        else: l = None
298
[d2471df]299        return Interface(substrate=[s for s in self.substrate], name=self.name,
[db6b092]300                capacity=c, latency=l,
301                attribute = [ a.clone() for a in self.attribute])
302
[eec716b]303    def to_dict(self):
[5b74b63]304        rv = { 'substrate': self.substrate, 'name': self.name }
[eec716b]305        if self.capacity:
306            rv['capacity'] = self.capacity.to_dict()
307        if self.latency:
308            rv['latency'] = self.latency.to_dict()
309        if self.attribute:
310            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
311        return rv
312
[a914b1b]313    def to_xml(self):
314        rv = join(["<substrate>%s</substrate>" % escape(s) \
315                for s in self.substrate], "")
316        rv += "<name>%s</name>" % self.name
317        if self.capacity:
318            rv += "<capacity>%s</capacity>" % self.capacity.to_xml()
319        if self.latency:
320            rv += "<latency>%s</latency>" % self.latency.to_xml()
321        if self.attribute:
322            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
323                    for a in self.attribute], "")
324        return rv
325
326
[6c57fe9]327class ID(base):
328    def __init__(self, fedid=None, uuid=None, uri=None, localname=None,
329            kerberosUsername=None):
[da2208a]330        self.fedid=fedid_class(hexstr="%s" % fedid)
[21b5434]331        self.uuid = self.init_string(uuid)
332        self.uri = self.init_string(uri)
333        self.localname =self.init_string( localname)
334        self.kerberosUsername = self.init_string(kerberosUsername)
[6c57fe9]335
336    def clone(self):
337        return ID(self.fedid, self.uuid, self.uri, self.localname,
[ecca6eb]338                self.kerberosUsername)
[6c57fe9]339
340    def to_dict(self):
341        rv = { }
342        if self.fedid: rv['fedid'] = self.fedid
343        if self.uuid: rv['uuid'] = self.uuid
344        if self.uri: rv['uri'] = self.uri
345        if self.localname: rv['localname'] = self.localname
346        if self.kerberosUsername: rv['kerberosUsername'] = self.kerberosUsername
347        return rv
348
[a914b1b]349    def to_xml(self):
350        if self.uuid: rv = "<uuid>%s</uuid>" % b64encode(self.uuid)
351        elif self.fedid: rv = "<fedid>%s</fedid>" % b64encode(self.fedid)
352        elif self.uri: rv = "<uri>%s</uri>" % escape(self.uri)
353        elif self.localname: 
354            rv = "<localname>%s</localname>" % escape(self.localname)
355        elif self.kerberosUsername: 
356            rv = "<kerberosUsername>%s</kerberosUsername>" % \
357                    escape(self.kerberosUsername)
358        return rv
359
[eec716b]360class Computer(base):
[822fd49]361    def __init__(self, name, cpu=[], os=[], software=[], storage=[],
[cdb62d9]362            interface=[], attribute=[]):
[eec716b]363        def assign_element(i):
364            i.element = self
365
[21b5434]366        self.name = self.init_string(name)
[eec716b]367        self.cpu = [ self.init_class(CPU, c)  for c in self.make_list(cpu) ]
368        self.os = [ self.init_class(OperatingSystem, c) \
369                for c in self.make_list(os) ]
370        self.software = [ self.init_class(Software, c) \
371                for c in self.make_list(software) ]
372        self.storage = [ self.init_class(Storage, c) \
373                for c in self.make_list(storage) ]
374        self.interface = [ self.init_class(Interface, c) \
375                for c in self.make_list(interface) ]
376        self.attribute = [ self.init_class(Attribute, a) \
377                for a in self.make_list(attribute) ]
378        map(assign_element, self.interface)
379
[db6b092]380    def clone(self):
[d2471df]381        # Copy the list of names
[1e7f268]382        return Computer(name=self.name,
[db6b092]383                cpu=[x.clone() for x in self.cpu],
384                os=[x.clone() for x in self.os],
385                software=[x.clone() for x in self.software],
386                storage=[x.clone() for x in self.storage],
387                interface=[x.clone() for x in self.interface],
388                attribute=[x.clone() for x in self.attribute])
389
[eec716b]390    def to_dict(self):
391        rv = { }
[db6b092]392        if self.name:
[6d7a024]393            rv['name'] = self.name
[eec716b]394        if self.cpu:
395            rv['cpu'] = [ c.to_dict() for  c in self.cpu ]
396        if self.os:
397            rv['os'] = [ o.to_dict() for o in self.os ]
398        if self.software:
399            rv['software'] = [ s.to_dict() for s in self.software ]
400        if self.storage:
401            rv['storage'] = [ s.to_dict for s in self.storage ]
402        if self.interface:
403            rv['interface'] = [ i.to_dict() for i in self.interface ]
404        if self.attribute:
405            rv['attribute'] = [ i.to_dict() for i in self.attribute ]
[cdb62d9]406        return { 'computer': rv }
[eec716b]407
[a914b1b]408    def to_xml(self):
409        rv = "<name>%s</name>" % escape(self.name)
410        if self.cpu:
411            rv += join(["<cpu>%s</cpu>" % c.to_xml() for c in self.cpu], "")
412        if self.os:
413            rv += join(["<os>%s</os>" % o.to_xml() for o in self.os], "")
414        if self.software:
415            rv += join(["<software>%s</software>" % s.to_xml() \
416                    for s in self.software], "")
417        if self.storage:
418            rv += join(["<stroage>%s</stroage>" % s.to_xml() \
419                    for s in self.stroage], "")
420        if self.interface:
421            rv += join(["<interface>%s</interface>" % i.to_xml() 
422                for i in self.interface], "")
423        if self.attribute:
424            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
425                    for a in self.attribute], "")
426        return "<computer>%s</computer>" % rv
427
428
[6c57fe9]429
430class Testbed(base):
431    def __init__(self, uri, type, interface=[], attribute=[]):
[21b5434]432        self.uri = self.init_string(uri)
433        self.type = self.init_string(type)
[6c57fe9]434        self.interface = [ self.init_class(Interface, c) \
435                for c in self.make_list(interface) ]
436        self.attribute = [ self.init_class(Attribute, c) \
437                for c in self.make_list(attribute) ]
438
439    def clone(self):
440        return Testbed(self.uri, self.type,
441                interface=[i.clone() for i in self.interface],
442                attribute=[a.cone() for a in self.attribute])
443
444    def to_dict(self):
445        rv = { }
446        if self.uri: rv['uri'] = self.uri
447        if self.type: rv['type'] = self.type
448        if self.interface:
449            rv['interface'] = [ i.to_dict() for i in self.interface]
450        if self.attribute:
451            rv['attribute'] = [ a.to_dict() for a in self.attribute]
452        return { 'testbed': rv }
453
[a914b1b]454    def to_xml(self):
455        rv = "<uri>%s</uri><type>%s</type>" % \
456                (escape(self.uri), escape(self.type))
457        if self.interface:
458            rv += join(["<interface>%s</interface>" % i.to_xml() 
459                for i in self.interface], "")
460        if self.attribute:
461            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
462                    for a in self.attribute], "")
463        return "<testbed>%s</testbed>" % rv
464
465       
466
[6c57fe9]467class Segment(base):
468    def __init__(self, id, type, uri, interface=[], attribute=[]):
469        self.id = self.init_class(ID, id)
[21b5434]470        self.type = self.init_string(type)
471        self.uri = self.init_string(uri)
[6c57fe9]472        self.interface = [ self.init_class(Interface, c) \
473                for c in self.make_list(interface) ]
474        self.attribute = [ self.init_class(Attribute, c) \
475                for c in self.make_list(attribute) ]
476
477    def clone(self):
478        return Segment(self.id.clone(), self.type, self.uri, 
479                interface=[i.clone() for i in self.interface], 
[ecca6eb]480                attribute=[a.clone() for a in self.attribute])
[6c57fe9]481
482    def to_dict(self):
483        rv = { }
484        if self.id: rv['id'] = self.id.to_dict()
485        if self.type: rv['type'] = self.type
486        if self.uri: rv['uri'] = self.uri
487        if self.interface:
488            rv['interface'] = [ i.to_dict() for i in self.interface ]
489        if self.attribute:
490            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
491        return { 'segment': rv }
492
[a914b1b]493    def to_xml(self):
494        rv = "<id>%s</id><uri>%s</uri><type>%s</type>" % \
495                (id.to_xml(), escape(self.uri), escape(self.type))
496        if self.interface:
497            rv += join(["<interface>%s</interface>" % i.to_xml() 
498                for i in self.interface], "")
499        if self.attribute:
500            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
501                    for a in self.attribute], "")
502        return "<segment>%s</segment>" % rv
[6c57fe9]503
[eec716b]504class Other(base):
505    def __init__(self, interface=[], attribute=[]):
506        self.interface = [ self.init_class(Interface, c) \
507                for c in self.make_list(interface) ]
508        self.attribute = [ self.init_class(Attribute, c) \
509                for c in self.make_list(attribute) ]
510
[db6b092]511    def clone(self):
512        return Other(interface=[i.clone() for i in self.interface], 
513                attribute=[a.clone() for a in attribute])
514
[eec716b]515    def to_dict(self):
[6c57fe9]516        rv = {}
[eec716b]517        if self.interface:
518            rv['interface'] = [ i.to_dict() for i in self.interface ]
519        if self.attribute:
520            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
[6c57fe9]521        return {'other': rv }
[eec716b]522
[a914b1b]523    def to_xml(self):
524        rv = ""
525        if self.interface:
526            rv += join(["<interface>%s</interface>" % i.to_xml() 
527                for i in self.interface], "")
528        if self.attribute:
529            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
530                    for a in self.attribute], "")
531        return "<other>%s</other>" % rv
[eec716b]532
533class Topology(base):
[d69ce97]534    version = "1.0"
[eec716b]535    @staticmethod
536    def init_element(e):
537        """
538        e should be of the form { typename: args } where args is a dict full of
539        the right parameters to initialize the element.  e should have only one
540        key, but we walk e's keys in an arbitrary order and instantiate the
541        first key we know how to.
542        """
543        classmap = {
544                'computer': Computer,
[6c57fe9]545                'testbed': Testbed,
546                'segment': Segment,
[eec716b]547                'other': Other,
548            }
549
[db6b092]550        if isinstance(e, dict):
551            for k in e.keys():
552                cl = classmap.get(k, None)
553                if cl: return cl(**e[k])
554        else:
555            return e
[eec716b]556
[d69ce97]557    def __init__(self, substrates=[], elements=[], attribute=[], 
558            version=None):
559
560        if version is None: self.version = Topology.version
561        else: self.version = version
562
[eec716b]563        self.substrates = [ self.init_class(Substrate, s) \
564                for s in self.make_list(substrates) ]
565        self.elements = [ self.init_element(e) \
566                for e in self.make_list(elements) ]
[69692a9]567        self.attribute = [ self.init_class(Attribute, c) \
568                for c in self.make_list(attribute) ]
[db6b092]569        self.incorporate_elements()
570
[5b74b63]571    @staticmethod
572    def name_element_interfaces(e):
573        names = set([i.name for i in e.interface if i.name])
574        inum = 0
575        for i in [ i for i in e.interface if not i.name]:
576            while inum < 1000:
577                n = "inf%03d" % inum
578                inum += 1
579                if n not in names:
580                    i.name = n
581                    break
582            else:
583                raise NamespaceError("Cannot make new interface name")
584
585
586
587    def name_interfaces(self):
588        """
589        For any interface without a name attribute, assign a unique one within
590        its element.
591        """
592
593        for e in self.elements:
594            self.name_element_interfaces(e)
595
596
[db6b092]597    def incorporate_elements(self):
598
[eec716b]599        # Could to this init in one gulp, but we want to look for duplicate
600        # substrate names
601        substrate_map = { }
602        for s in self.substrates:
[db6b092]603            s.interfaces = [ ]
[eec716b]604            if not substrate_map.has_key(s.name):
605                substrate_map[s.name] = s
606            else:
607                raise ConsistencyError("Duplicate substrate name %s" % s.name)
608
609        for e in self.elements:
[5b74b63]610            self.name_element_interfaces(e)
[eec716b]611            for i in e.interface:
[db6b092]612                i.element = e
613                i.subs = [ ]
[eec716b]614                for sn in i.substrate:
615                    # NB, interfaces have substrate names in their substrate
616                    # attribute.
617                    if substrate_map.has_key(sn):
618                        sub = substrate_map[sn]
619                        i.subs.append(sub)
620                        sub.interfaces.append(i)
621                    else:
622                        raise ConsistencyError("No such substrate for %s" % sn)
623
[db6b092]624    def clone(self):
625        return Topology(substrates=[s.clone() for s in self.substrates], 
[69692a9]626                elements=[e.clone() for e in self.elements],
[d69ce97]627                attribute=[a.clone() for a in self.attribute],
628                version=self.version)
[db6b092]629
630
631    def make_indices(self):
632        sub_index = dict([(s.name, s) for s in self.substrates])
633        elem_index = dict([(n, e) for e in self.elements for n in e.name])
634
[eec716b]635    def to_dict(self):
636        rv = { }
[d69ce97]637        rv['version'] = self.version
[eec716b]638        if self.substrates:
639            rv['substrates'] = [ s.to_dict() for s in self.substrates ]
640        if self.elements:
641            rv['elements'] = [ s.to_dict() for s in self.elements ]
[69692a9]642        if self.attribute:
643            rv['attribute'] = [ s.to_dict() for s in self.attribute]
[eec716b]644        return rv
645
[a914b1b]646    def to_xml(self):
[d69ce97]647        rv = "<version>%s</version>" % escape(self.version)
[a914b1b]648        if self.substrates:
649            rv += join(["<substrates>%s</substrates>" % s.to_xml() \
650                    for s in self.substrates], "")
651        if self.elements:
652            rv += join(["<elements>%s</elements>" % e.to_xml() \
653                    for e in self.elements], "")
654        if self.attribute:
655            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
656                    for a in self.attribute], "")
657        return rv
658
659
[db6b092]660def topology_from_xml(string=None, file=None, filename=None, top="topology"):
[eec716b]661    class parser:
[f1550c8]662        def __init__(self, top):
[eec716b]663            self.stack = [ ]
664            self.chars = ""
665            self.key = ""
666            self.have_chars = False
667            self.current = { }
668            self.in_cdata = False
[f1550c8]669            self.in_top = False
670            self.top = top
[eec716b]671       
672        def start_element(self, name, attrs):
673            self.chars = ""
674            self.have_chars = False
675            self.key = str(name)
[f1550c8]676
677            if name == self.top:
678                self.in_top = True
679
680            if self.in_top:
681                self.stack.append((self.current, self.key))
682                self.current = { }
[eec716b]683
684        def end_element(self, name):
[f1550c8]685            if self.in_top:
686                if self.have_chars:
687                    self.chars = self.chars.strip()
688                    if len(self.chars) >0:
689                        addit = self.chars
690                    else:
691                        addit = self.current
[eec716b]692                else:
693                    addit = self.current
694
[f1550c8]695                parent, key = self.stack.pop()
696                if parent.has_key(key):
697                    if isinstance(parent[key], list):
698                        parent[key].append(addit)
699                    else:
700                        parent[key] = [parent[key], addit]
[eec716b]701                else:
[f1550c8]702                    parent[key] = addit
703                self.current = parent
704                self.key = key
[eec716b]705
706            self.chars = ""
707            self.have_chars = False
708
[f1550c8]709            if name == self.top:
710                self.in_top= False
711
[eec716b]712        def char_data(self, data):
[f1550c8]713            if self.in_top:
714                self.have_chars = True
715                self.chars += data
[eec716b]716
[f1550c8]717    p = parser(top=top)
[eec716b]718    xp = xml.parsers.expat.ParserCreate()
719
720    xp.StartElementHandler = p.start_element
721    xp.EndElementHandler = p.end_element
722    xp.CharacterDataHandler = p.char_data
723
[db6b092]724    num_set = len([ x for x in (string, filename, file)\
725            if x is not None ])
726
727    if num_set != 1:
728        raise RuntimeError("Exactly one one of file, filename and string " + \
729                "must be set")
730    elif filename:
731        f = open(filename, "r")
[df783c1]732        xp.ParseFile(f)
[cc8d8e9]733        f.close()
[db6b092]734    elif file:
735        xp.ParseFile(file)
[df783c1]736    elif string:
737        xp.Parse(string, isfinal=True)
738    else:
739        return None
[eec716b]740
741    return Topology(**p.current[top])
742
[9252414]743def topology_from_startsegment(req):
744    """
745    Generate a topology from a StartSegment request to an access controller.
746    This is a little helper to avoid some gross looking syntax.  It accepts
747    either a request enclosed in the StartSegmentRequestBody, or one with that
748    outer dict removed.
749    """
750
751    if 'StartSegmentRequestBody' in req: r = req['StartSegmentRequestBody']
752    else: r = req
753   
754    if 'segmentdescription' in r and \
755            'topdldescription' in r['segmentdescription']:
756        return Topology(**r['segmentdescription']['topdldescription'])
757    else:
758        return None
759
[eec716b]760def topology_to_xml(t, top=None):
761    """
[a914b1b]762    Print the topology as XML, recursively using the internal classes to_xml()
763    methods.
[eec716b]764    """
765
[a914b1b]766    if top: return "<%s>%s</%s>" % (top, t.to_xml(), top)
767    else: return t.to_xml()
[eec716b]768
[db6b092]769def topology_to_vtopo(t):
770    nodes = [ ]
771    lans = [ ]
[eec716b]772
[db6b092]773    for eidx, e in enumerate(t.elements):
[4a53c72]774        if e.name: name = e.name
[db6b092]775        else: name = "unnamed_node%d" % eidx
776       
777        ips = [ ]
[cc8d8e9]778        for idx, i in enumerate(e.interface):
[db6b092]779            ip = i.get_attribute('ip4_address')
780            ips.append(ip)
781            port = "%s:%d" % (name, idx)
782            for idx, s in enumerate(i.subs):
783                bw = 100000
784                delay = 0.0
785                if s.capacity:
786                    bw = s.capacity.rate
787                if i.capacity:
788                    bw = i.capacity.rate
789
790                if s.latency:
791                    delay = s.latency.time
792                if i.latency:
793                    bw = i.latency.time
794
795                lans.append({
796                    'member': port,
797                    'vname': s.name,
798                    'ip': ip,
799                    'vnode': name,
800                    'delay': delay,
801                    'bandwidth': bw,
802                    })
803        nodes.append({
804            'ips': ":".join(ips),
805            'vname': name,
806            })
807
[cc8d8e9]808    return { 'node': nodes, 'lan': lans }
809
[6c57fe9]810def to_tcl_name(n):
[8483f24]811    t = re.sub('-(\d+)', '(\\1)', n)
[6c57fe9]812    return t
813
[69692a9]814def generate_portal_command_filter(cmd, add_filter=None):
[ecca6eb]815    def rv(e):
816        s =""
817        if isinstance(e, Computer):
818            gw = e.get_attribute('portal')
[69692a9]819            if add_filter and callable(add_filter):
820                add = add_filter(e)
821            else:
822                add = True
823            if gw and add:
[1e7f268]824                s = "%s ${%s}\n" % (cmd, to_tcl_name(e.name))
[ecca6eb]825        return s
826    return rv
827
[6c57fe9]828def generate_portal_image_filter(image):
829    def rv(e):
830        s =""
831        if isinstance(e, Computer):
832            gw = e.get_attribute('portal')
833            if gw:
[1e7f268]834                s = "tb-set-node-os ${%s} %s\n" % (to_tcl_name(e.name), image)
[6c57fe9]835        return s
836    return rv
837
[ecca6eb]838def generate_portal_hardware_filter(type):
[6c57fe9]839    def rv(e):
840        s =""
841        if isinstance(e, Computer):
842            gw = e.get_attribute('portal')
843            if gw:
[1e7f268]844                s = "tb-set-hardware ${%s} %s\n" % (to_tcl_name(e.name), type)
[6c57fe9]845        return s
846    return rv
847
848
[d46b1d5]849def topology_to_ns2(t, filters=[], routing="Manual"):
[cc8d8e9]850    out = """
851set ns [new Simulator]
852source tb_compat.tcl
853
854"""
[6c57fe9]855
[cc8d8e9]856    for e in t.elements:
857        rpms = ""
858        tarfiles = ""
859        if isinstance(e, Computer):
[1e7f268]860            name = to_tcl_name(e.name)
[cc8d8e9]861            out += "set %s [$ns node]\n" % name
862            if e.os and len(e.os) == 1:
863                osid = e.os[0].get_attribute('osid')
864                if osid:
[d46b1d5]865                    out += "tb-set-node-os ${%s} %s\n" % (name, osid)
[ecca6eb]866            hw = e.get_attribute('type')
867            if hw:
[d46b1d5]868                out += "tb-set-hardware ${%s} %s\n" % (name, hw)
[cc8d8e9]869            for s in e.software:
870                if s.install:
871                    tarfiles += "%s %s " % (s.install, s.location)
872                else:
873                    rpms += "%s " % s.location
874            if rpms:
[d46b1d5]875                out += "tb-set-node-rpms ${%s} %s\n" % (name, rpms)
[cc8d8e9]876            if tarfiles:
[d46b1d5]877                out += "tb-set-node-tarfiles ${%s} %s\n" % (name, tarfiles)
[cc8d8e9]878            startcmd = e.get_attribute('startup')
879            if startcmd:
[d46b1d5]880                out+= 'tb-set-node-startcmd ${%s} "%s"\n' % (name, startcmd)
[6c57fe9]881            for f in filters:
882                out += f(e)
[cc8d8e9]883            out+= "\n"
884   
885    for idx, s in enumerate(t.substrates):
886        loss = s.get_attribute('loss')
[df3179c]887        if s.latency: delay = s.latency.time
888        else: delay = 0
889
890        if s.capacity: rate = s.capacity.rate
891        else: rate = 100000
[6c57fe9]892        name = to_tcl_name(s.name or "sub%d" % idx)
[cc8d8e9]893
894        if len(s.interfaces) > 2:
895            # Lan
[4a53c72]896            members = [ to_tcl_name("${%s}") % i.element.name \
[6c57fe9]897                    for i in s.interfaces]
898            out += 'set %s [$ns make-lan "%s" %fkb %fms ]\n' % \
[5767b20]899                    (name, " ".join([to_tcl_name(m) for m in members]),
900                            rate, delay)
[cc8d8e9]901            if loss:
[d46b1d5]902                "tb-set-lan-loss ${%s} %f\n" % (name, float(loss))
[cc8d8e9]903
904            for i in s.interfaces:
905                e = i.element
[1da6a23]906                ip = i.get_attribute("ip4_address")
[cc8d8e9]907                if ip:
[d46b1d5]908                    out += "tb-set-ip-lan ${%s} ${%s} %s\n" % \
[4a53c72]909                            (to_tcl_name(e.name), name, ip)
[df3179c]910                if i.capacity and i.capacity.rate != rate:
[d46b1d5]911                    out += "tb-set-node-lan-bandwidth ${%s} ${%s} %fkb\n" % \
[4a53c72]912                            (to_tcl_name(e.name), name, i.capacity.rate)
[cc8d8e9]913                if i.latency and i.latency.time != delay:
[d46b1d5]914                    out += "tb-set-node-lan-delay ${%s} ${%s} %fms\n" % \
[4a53c72]915                            (to_tcl_name(e.name), name, i.latency.time)
[cc8d8e9]916                iloss = i.get_attribute('loss')
917                if loss and iloss != loss :
[d46b1d5]918                    out += "tb-set-node-lan-loss ${%s} ${%s} %f\n" % \
[4a53c72]919                            (to_tcl_name(e.name), name, float(loss))
[cc8d8e9]920            out+= "\n"
921        elif len(s.interfaces) == 2:
922            f = s.interfaces[0]
923            t = s.interfaces[1]
924
[d46b1d5]925            out += "set %s [$ns duplex-link ${%s} ${%s} %fkb %fms DropTail]\n" %\
[4a53c72]926                    (name, to_tcl_name(f.element.name), 
[df3179c]927                            to_tcl_name(t.element.name), rate, delay)
[cc8d8e9]928            if loss:
[d46b1d5]929                out += "tb-set-link-loss ${%s} %f\n" % (name, float(loss))
[cc8d8e9]930
931            for i in s.interfaces:
932                lloss = i.get_attribute("loss")
933                cap_override = i.capacity and \
[df3179c]934                        i.capacity.rate != rate
[cc8d8e9]935                delay_override = i.latency and \
936                        i.latency.time != delay
937                loss_override = lloss and lloss != loss
938                if cap_override or delay_override or loss_override:
939                    if i.capacity: cap = i.capacity.rate
[df3179c]940                    else: cap = rate
[cc8d8e9]941
942                    if i.latency: delay = i.latency.time
943
944                    if lloss: loss = lloss
945                    else: loss = loss or 0.0
946
[d46b1d5]947                    out += "tb-set-link-simplex-params ${%s} ${%s} %fms %fkb %f\n"\
[4a53c72]948                            % (name, to_tcl_name(i.element.name),
[6c57fe9]949                                    delay, cap, loss)
[1da6a23]950                ip = i.get_attribute('ip4_address')
951                if ip:
[d46b1d5]952                    out += "tb-set-ip-link ${%s} ${%s} %s\n" % \
[4a53c72]953                            (to_tcl_name(i.element.name), name, ip)
[cc8d8e9]954            out+= "\n"
[6c57fe9]955        for f in filters:
956            out+= f(s)
[1da6a23]957    out+="$ns rtproto %s" % routing
[cc8d8e9]958    out+="""
959$ns run
960"""
961    return out
[2fdf4b3]962
963def topology_to_rspec(t, filters=[]):
964    out = '<?xml version="1.0" encoding="UTF-8"?>\n' + \
965        '<rspec xmlns="http://www.protogeni.net/resources/rspec/0.1"\n' + \
966        '\txmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' + \
967        '\txsi:schemaLocation="http://www.protogeni.net/resources/rspec/0.1 '+ \
968        'http://www.protogeni.net/resources/rspec/0.1/request.xsd"\n' + \
969        '\ttype="request" >\n'
970
971    ifname = { }
972    ifnode = { }
973
974    for e in [e for e in t.elements if isinstance(e, Computer)]:
[1e7f268]975        name = e.name
[2fdf4b3]976        virt_type = e.get_attribute("virtualization_type") or "emulab-vnode"
977        exclusive = e.get_attribute("exclusive") or "1"
978        hw = e.get_attribute("type") or "pc";
979        slots = e.get_attribute("slots") or "1";
980        startup = e.get_attribute("startup")
981
982        extras = ""
983        if startup: extras += '\t\tstartup_command="%s"\n' % startup
984        out += '\t<node virtual_id="%s"\n\t\tvirtualization_type="%s"\n' % \
985                (name, virt_type)
986        out += '\t\texclusive="%s"' % exclusive
987        if extras: out += '\n%s' % extras
988        out += '>\n'
989        out += '\t\t<node_type type_name="%s" slots="%s"/>\n' % (hw, slots)
990        for i, ii in enumerate(e.interface):
[5b74b63]991            out += '\t\t<interface virtual_id="%s"/>\n' % ii.name
[2fdf4b3]992            ifnode[ii] = name
993        for f in filters:
[8aaf8f8]994            out += f(e)
[2fdf4b3]995        out += '\t</node>\n'
996
997    for i, s in enumerate(t.substrates):
[f81aba7]998        if len(s.interfaces) == 0: 
999            continue
1000        out += '\t<link virtual_id="%s" link_type="ethernet">\n' % s.name
[2fdf4b3]1001        if s.capacity and s.capacity.kind == "max":
[f81aba7]1002            bwout = True
1003            out += '\t\t<bandwidth>%d</bandwidth>\n' % s.capacity.rate
1004        else:
1005            bwout = False
[2fdf4b3]1006        if s.latency and s.latency.kind == "max":
[f81aba7]1007            out += '\t\t<latency>%d</latency>\n' % s.latency.time
1008        elif bwout:
1009            out += '\t\t<latency>0</latency>\n'
[2fdf4b3]1010        for ii in s.interfaces:
[6d07908]1011            out += ('\t\t<interface_ref virtual_node_id="%s" ' + \
[5b74b63]1012                    'virtual_interface_id="%s"/>\n') % (ifnode[ii], ii.name)
[2fdf4b3]1013        for f in filters:
1014            out += f(s)
1015        out += '\t</link>\n'
1016    out += '</rspec>\n'
1017    return out
1018
Note: See TracBrowser for help on using the repository browser.