source: fedd/deter/topdl.py @ 59c56fa

Last change on this file since 59c56fa was 59c56fa, checked in by Ted Faber <faber@…>, 9 years ago

Short term fix to ignore unknown elements (like regions)

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