source: fedd/deter/topdl.py @ ad4b25a

Last change on this file since ad4b25a was a183a42, checked in by Ted Faber <faber@…>, 10 years ago

Allow data to work w/o full fedid support

  • Property mode set to 100644
File size: 33.7 KB
Line 
1#!/usr/local/bin/python
2
3import re
4import xml.parsers.expat
5from xml.sax.saxutils import escape
6from base64 import b64encode
7from string import join
8
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
23
24class base:
25    @staticmethod
26    def init_class(c, arg):
27        if isinstance(arg, dict):
28            try:
29                return c(**arg)
30            except:
31                print "%s" % arg
32                raise
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
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
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
62    def get_attribute(self, key):
63        rv = None
64        attrs = getattr(self, 'attribute', None)
65        if attrs:
66            for a in attrs:
67                if a.attribute == key:
68                    rv = a.value
69                    break
70        return rv
71
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))
82
83class ConsistencyError(RuntimeError): pass
84class NamespaceError(RuntimeError): pass
85
86class Attribute(base):
87    def __init__(self, attribute, value):
88        self.attribute = self.init_string(attribute)
89        self.value = self.init_string(value)
90
91    def clone(self):
92        return Attribute(attribute=self.attribute, value=self.value)
93
94    def to_dict(self):
95        return { 'attribute': self.attribute, 'value': self.value }
96    def to_xml(self):
97        return "<attribute>%s</attribute><value>%s</value>" % \
98                (escape(self.attribute), escape(self.value))
99
100class Capacity(base):
101    def __init__(self, rate, kind):
102        self.rate = float(rate)
103        self.kind = self.init_string(kind)
104
105    def clone(self):
106        return Capacity(rate=self.rate, kind=self.kind)
107
108    def to_dict(self):
109        return { 'rate': float(self.rate), 'kind': self.kind }
110
111    def to_xml(self):
112        return "<rate>%f</rate><kind>%s</kind>" % (self.rate, self.kind)
113
114class Latency(base):
115    def __init__(self, time, kind):
116        self.time = float(time)
117        self.kind = self.init_string(kind)
118
119    def clone(self):
120        return Latency(time=self.time, kind=self.kind)
121
122    def to_dict(self):
123        return { 'time': float(self.time), 'kind': self.kind }
124
125    def to_xml(self):
126        return "<time>%f</time><kind>%s</kind>" % (self.time, self.kind)
127
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:
183            rv += join(['<param>%s</param>' % p.to_xml() \
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
191class Substrate(base):
192    def __init__(self, name, capacity=None, latency=None, attribute=[],
193            localname=[], status=None, service=[], operation=[]):
194        self.name = self.init_string(name)
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) ]
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)]
206        self.interfaces = [ ]
207
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,
218                attribute = [a.clone() for a in self.attribute],
219                localname = [ ln for ln in self.localname],
220                status = self.status,
221                service = [ s.clone() for s in self.service],
222                operation=[ op for op in self.operation])
223
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 ]
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]
240        return rv
241
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], "")
252        if self.localname:
253            rv += join(['<localname>%s</localname>' % ln \
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], '')
263        return rv
264
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
276class CPU(base):
277    def __init__(self, type, attribute=[]):
278        self.type = self.init_string(type)
279        self.attribute = [ self.init_class(Attribute, a) for a in \
280                self.make_list(attribute) ]
281
282    def clone(self):
283        return CPU(type=self.type,
284                attribute = [a.clone() for a in self.attribute])
285
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
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
300class Storage(base):
301    def __init__(self, amount, persistence, attribute=[]):
302        self.amount = float(amount)
303        self.persistence = self.init_string(persistence)
304        self.attribute = [ self.init_class(Attribute, a) \
305                for a in self.make_list(attribute) ]
306
307    def clone(self):
308        return Storage(amount=self.amount, persistence=self.persistence, 
309                attribute = [a.clone() for a in self.attribute])
310
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
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
326class OperatingSystem(base):
327    def __init__(self, name=None, version=None, distribution=None,
328            distributionversion=None, attribute=[]):
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)
333        self.attribute = [ self.init_class(Attribute, a) \
334                for a in self.make_list(attribute) ]
335
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
343    def to_dict(self):
344        rv = { }
345        if self.name: rv['name'] = self.name
346        if self.version: rv['version'] = self.version
347        if self.distribution: rv['distribution'] = self.distribution
348        if self.distributionversion: 
349            rv['distributionversion'] = self.distributionversion
350        if self.attribute:
351            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
352        return rv
353
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
370class Software(base):
371    def __init__(self, location, install=None, attribute=[]):
372        self.location = self.init_string(location)
373        self.install = self.init_string(install)
374        self.attribute = [ self.init_class(Attribute, a)\
375                for a in self.make_list(attribute) ]
376
377    def clone(self):
378        return Software(location=self.location, install=self.install, 
379                attribute=[a.clone() for a in self.attribute])
380
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
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
397class Interface(base):
398    def __init__(self, substrate, name=None, capacity=None, latency=None,
399            attribute=[], element=None):
400        self.name = self.init_string(name)
401
402        self.substrate = self.make_list(substrate)
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
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
417        return Interface(substrate=[s for s in self.substrate], name=self.name,
418                capacity=c, latency=l,
419                attribute = [ a.clone() for a in self.attribute])
420
421    def to_dict(self):
422        rv = { 'substrate': self.substrate, 'name': self.name }
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
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
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
455
456class ID(base):
457    def __init__(self, fedid=None, uuid=None, uri=None, localname=None,
458            kerberosUsername=None):
459        self.fedid=fedid_class(hexstr="%s" % fedid)
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)
464
465    def clone(self):
466        return ID(self.fedid, self.uuid, self.uri, self.localname,
467                self.kerberosUsername)
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
478    def to_xml(self):
479        if self.uuid: rv = "<uuid>%s</uuid>" % b64encode(self.uuid)
480        elif self.fedid: rv = "<fedid>%s</fedid>" % \
481                b64encode(self.fedid.get_bits())
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
490class Computer(base):
491    def __init__(self, name, cpu=[], os=[], software=[], storage=[],
492            interface=[], attribute=[], localname=[], status=None, service=[],
493            operation=[]):
494        def assign_element(i):
495            i.element = self
496
497        self.name = self.init_string(name)
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) ]
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)]
516        map(assign_element, self.interface)
517
518    def clone(self):
519        # Copy the list of names
520        return Computer(name=self.name,
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],
526                attribute=[x.clone() for x in self.attribute],
527                localname =[ ln for ln in self.localname],
528                status = self.status,
529                service = [s.clone() for s in self.service],
530                operation = [op for op in self.operation])
531
532    def to_dict(self):
533        rv = { }
534        if self.name:
535            rv['name'] = self.name
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:
543            rv['storage'] = [ s.to_dict() for s in self.storage ]
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 ]
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]
556        return { 'computer': rv }
557
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:
568            rv += join(["<storage>%s</storage>" % s.to_xml() \
569                    for s in self.storage], "")
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], "")
576        if self.localname:
577            rv += join(['<localname>%s</localname>' % ln \
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], '')
587        return "<computer>%s</computer>" % rv
588
589
590
591class Testbed(base):
592    def __init__(self, uri, type, interface=[], attribute=[], localname=[],
593            status=None, service=[], operation=[]):
594        self.uri = self.init_string(uri)
595        self.type = self.init_string(type)
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) ]
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)]
607
608    def clone(self):
609        return Testbed(self.uri, self.type,
610                interface=[i.clone() for i in self.interface],
611                attribute=[a.clone() for a in self.attribute],
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 ])
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]
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]
633        return { 'testbed': rv }
634
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], "")
644        if self.localname:
645            rv += join(['<localname>%s</localname>' % ln \
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], '')
655        return "<testbed>%s</testbed>" % rv
656
657       
658
659class Segment(base):
660    def __init__(self, id, type, uri, interface=[], attribute=[]):
661        self.id = self.init_class(ID, id)
662        self.type = self.init_string(type)
663        self.uri = self.init_string(uri)
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], 
672                attribute=[a.clone() for a in self.attribute])
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
685    def to_xml(self):
686        rv = "<id>%s</id><uri>%s</uri><type>%s</type>" % \
687                (self.id.to_xml(), escape(self.uri), escape(self.type))
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
695
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
703    def clone(self):
704        return Other(interface=[i.clone() for i in self.interface], 
705                attribute=[a.clone() for a in attribute])
706
707    def to_dict(self):
708        rv = {}
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 ]
713        return {'other': rv }
714
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
724
725class Topology(base):
726    version = "1.0"
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,
737                'testbed': Testbed,
738                'segment': Segment,
739                'other': Other,
740            }
741
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
748
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
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) ]
759        self.attribute = [ self.init_class(Attribute, c) \
760                for c in self.make_list(attribute) ]
761        self.incorporate_elements()
762
763    @staticmethod
764    def name_element_interfaces(e):
765        names = set([i.name for i in e.interface if i.name])
766        inum = 0
767        for i in [ i for i in e.interface if not i.name]:
768            while inum < 1000:
769                n = "inf%03d" % inum
770                inum += 1
771                if n not in names:
772                    i.name = n
773                    break
774            else:
775                raise NamespaceError("Cannot make new interface name")
776
777
778
779    def name_interfaces(self):
780        """
781        For any interface without a name attribute, assign a unique one within
782        its element.
783        """
784
785        for e in self.elements:
786            self.name_element_interfaces(e)
787
788
789    def incorporate_elements(self):
790
791        # Could to this init in one gulp, but we want to look for duplicate
792        # substrate names
793        substrate_map = { }
794        for s in self.substrates:
795            s.interfaces = [ ]
796            if not substrate_map.has_key(s.name):
797                substrate_map[s.name] = s
798            else:
799                raise ConsistencyError("Duplicate substrate name %s" % s.name)
800
801        for e in self.elements:
802            self.name_element_interfaces(e)
803            for i in e.interface:
804                i.element = e
805                i.subs = [ ]
806                for sn in i.substrate:
807                    # NB, interfaces have substrate names in their substrate
808                    # attribute.
809                    if substrate_map.has_key(sn):
810                        sub = substrate_map[sn]
811                        i.subs.append(sub)
812                        sub.interfaces.append(i)
813                    else:
814                        raise ConsistencyError("No such substrate for %s" % sn)
815
816    def clone(self):
817        return Topology(substrates=[s.clone() for s in self.substrates], 
818                elements=[e.clone() for e in self.elements],
819                attribute=[a.clone() for a in self.attribute],
820                version=self.version)
821
822
823    def make_indices(self):
824        sub_index = dict([(s.name, s) for s in self.substrates])
825        elem_index = dict([(n, e) for e in self.elements for n in e.name])
826
827    def to_dict(self):
828        rv = { }
829        rv['version'] = self.version
830        if self.substrates:
831            rv['substrates'] = [ s.to_dict() for s in self.substrates ]
832        if self.elements:
833            rv['elements'] = [ s.to_dict() for s in self.elements ]
834        if self.attribute:
835            rv['attribute'] = [ s.to_dict() for s in self.attribute]
836        return rv
837
838    def to_xml(self):
839        rv = "<version>%s</version>" % escape(self.version)
840        if self.substrates:
841            rv += join(["<substrates>%s</substrates>" % s.to_xml() \
842                    for s in self.substrates], "")
843        if self.elements:
844            rv += join(["<elements>%s</elements>" % e.to_xml() \
845                    for e in self.elements], "")
846        if self.attribute:
847            rv += join(["<attribute>%s</attribute>" % a.to_xml() \
848                    for a in self.attribute], "")
849        return rv
850
851    def __setstate__(self, d):
852        # Import everything from the pickle dict and call incorporate to
853        # connect them.
854        self.__dict__.update(d)
855        self.incorporate_elements()
856
857
858def topology_from_xml(string=None, file=None, filename=None, top="topology"):
859    class parser:
860        def __init__(self, top):
861            self.stack = [ ]
862            self.chars = ""
863            self.key = ""
864            self.have_chars = False
865            self.current = { }
866            self.in_cdata = False
867            self.in_top = False
868            self.top = top
869       
870        def start_element(self, name, attrs):
871            self.chars = ""
872            self.have_chars = False
873            self.key = str(name)
874
875            if name == self.top:
876                self.in_top = True
877
878            if self.in_top:
879                self.stack.append((self.current, self.key))
880                self.current = { }
881
882        def end_element(self, name):
883            if self.in_top:
884                if self.have_chars:
885                    self.chars = self.chars.strip()
886                    if len(self.chars) >0:
887                        addit = self.chars
888                    else:
889                        addit = self.current
890                else:
891                    addit = self.current
892
893                parent, key = self.stack.pop()
894                if parent.has_key(key):
895                    if isinstance(parent[key], list):
896                        parent[key].append(addit)
897                    else:
898                        parent[key] = [parent[key], addit]
899                else:
900                    parent[key] = addit
901                self.current = parent
902                self.key = key
903
904            self.chars = ""
905            self.have_chars = False
906
907            if name == self.top:
908                self.in_top= False
909
910        def char_data(self, data):
911            if self.in_top:
912                self.have_chars = True
913                self.chars += data
914
915    p = parser(top=top)
916    xp = xml.parsers.expat.ParserCreate()
917
918    xp.StartElementHandler = p.start_element
919    xp.EndElementHandler = p.end_element
920    xp.CharacterDataHandler = p.char_data
921
922    num_set = len([ x for x in (string, filename, file)\
923            if x is not None ])
924
925    if num_set != 1:
926        raise RuntimeError("Exactly one one of file, filename and string " + \
927                "must be set")
928    elif filename:
929        f = open(filename, "r")
930        xp.ParseFile(f)
931        f.close()
932    elif file:
933        xp.ParseFile(file)
934    elif string:
935        xp.Parse(string, True)
936    else:
937        return None
938
939    return Topology(**p.current[top])
940
941def topology_from_startsegment(req):
942    """
943    Generate a topology from a StartSegment request to an access controller.
944    This is a little helper to avoid some gross looking syntax.  It accepts
945    either a request enclosed in the StartSegmentRequestBody, or one with that
946    outer dict removed.
947    """
948
949    if 'StartSegmentRequestBody' in req: r = req['StartSegmentRequestBody']
950    else: r = req
951   
952    if 'segmentdescription' in r and \
953            'topdldescription' in r['segmentdescription']:
954        return Topology(**r['segmentdescription']['topdldescription'])
955    else:
956        return None
957
958def topology_to_xml(t, top=None):
959    """
960    Print the topology as XML, recursively using the internal classes to_xml()
961    methods.
962    """
963
964    if top: return "<%s>%s</%s>" % (top, t.to_xml(), top)
965    else: return t.to_xml()
966
967def topology_to_vtopo(t):
968    nodes = [ ]
969    lans = [ ]
970
971    for eidx, e in enumerate(t.elements):
972        if isinstance(e, Computer):
973            if e.name: name = e.name
974            else: name = "unnamed_node%d" % eidx
975           
976            ips = [ ]
977            for idx, i in enumerate(e.interface):
978                ip = i.get_attribute('ip4_address')
979                ips.append(ip)
980                port = "%s:%d" % (name, idx)
981                for idx, s in enumerate(i.subs):
982                    bw = 100000
983                    delay = 0.0
984                    if s.capacity:
985                        bw = s.capacity.rate
986                    if i.capacity:
987                        bw = i.capacity.rate
988
989                    if s.latency:
990                        delay = s.latency.time
991                    if i.latency:
992                        bw = i.latency.time
993
994                    lans.append({
995                        'member': port,
996                        'vname': s.name,
997                        'ip': ip,
998                        'vnode': name,
999                        'delay': delay,
1000                        'bandwidth': bw,
1001                        })
1002            nodes.append({
1003                'ips': ":".join(ips),
1004                'vname': name,
1005                })
1006
1007    return { 'node': nodes, 'lan': lans }
1008
1009def to_tcl_name(n):
1010    t = re.sub('-(\d+)', '(\\1)', n)
1011    return t
1012
1013def generate_portal_command_filter(cmd, add_filter=None, suffix=''):
1014    def rv(e):
1015        s =""
1016        if isinstance(e, Computer):
1017            gw = e.get_attribute('portal')
1018            if add_filter and callable(add_filter):
1019                add = add_filter(e)
1020            else:
1021                add = True
1022            if gw and add:
1023                s = "%s ${%s} %s\n" % (cmd, to_tcl_name(e.name), suffix)
1024        return s
1025    return rv
1026
1027def generate_portal_image_filter(image):
1028    def rv(e):
1029        s =""
1030        if isinstance(e, Computer):
1031            gw = e.get_attribute('portal')
1032            if gw:
1033                s = "tb-set-node-os ${%s} %s\n" % (to_tcl_name(e.name), image)
1034        return s
1035    return rv
1036
1037def generate_portal_hardware_filter(type):
1038    def rv(e):
1039        s =""
1040        if isinstance(e, Computer):
1041            gw = e.get_attribute('portal')
1042            if gw:
1043                s = "tb-set-hardware ${%s} %s\n" % (to_tcl_name(e.name), type)
1044        return s
1045    return rv
1046
1047
1048def topology_to_ns2(t, filters=[], routing="Manual"):
1049    out = """
1050set ns [new Simulator]
1051source tb_compat.tcl
1052
1053"""
1054
1055    for e in t.elements:
1056        rpms = ""
1057        tarfiles = ""
1058        if isinstance(e, Computer):
1059            name = to_tcl_name(e.name)
1060            out += "set %s [$ns node]\n" % name
1061            if e.os and len(e.os) == 1:
1062                osid = e.os[0].get_attribute('osid')
1063                if osid:
1064                    out += "tb-set-node-os ${%s} %s\n" % (name, osid)
1065            hw = e.get_attribute('type')
1066            if hw:
1067                out += "tb-set-hardware ${%s} %s\n" % (name, hw)
1068            for s in e.software:
1069                if s.install:
1070                    tarfiles += "%s %s " % (s.install, s.location)
1071                else:
1072                    rpms += "%s " % s.location
1073            if rpms:
1074                out += "tb-set-node-rpms ${%s} %s\n" % (name, rpms)
1075            if tarfiles:
1076                out += "tb-set-node-tarfiles ${%s} %s\n" % (name, tarfiles)
1077            startcmd = e.get_attribute('startup')
1078            if startcmd:
1079                out+= 'tb-set-node-startcmd ${%s} "%s"\n' % (name, startcmd)
1080            for f in filters:
1081                out += f(e)
1082            out+= "\n"
1083   
1084    for idx, s in enumerate(t.substrates):
1085        if len(s.interfaces) < 2: continue
1086        loss = s.get_attribute('loss')
1087        if s.latency: delay = s.latency.time
1088        else: delay = 0
1089
1090        if s.capacity: rate = s.capacity.rate
1091        else: rate = 100000
1092        name = to_tcl_name(s.name or "sub%d" % idx)
1093
1094        # Lan
1095        members = [ to_tcl_name("${%s}") % i.element.name \
1096                for i in s.interfaces]
1097        out += 'set %s [$ns make-lan "%s" %fkb %fms ]\n' % \
1098                (name, " ".join([to_tcl_name(m) for m in members]),
1099                        rate, 2 * delay)
1100        if loss:
1101            "tb-set-lan-loss ${%s} %f\n" % (name, float(loss))
1102
1103        for i in s.interfaces:
1104            e = i.element
1105            ip = i.get_attribute("ip4_address")
1106            if ip:
1107                out += "tb-set-ip-lan ${%s} ${%s} %s\n" % \
1108                        (to_tcl_name(e.name), name, ip)
1109            if i.capacity :
1110                out += "tb-set-node-lan-bandwidth ${%s} ${%s} %fkb\n" % \
1111                        (to_tcl_name(e.name), name, i.capacity.rate)
1112            if i.latency :
1113                out += "tb-set-node-lan-delay ${%s} ${%s} %fms\n" % \
1114                        (to_tcl_name(e.name), name, i.latency.time)
1115            iloss = i.get_attribute('loss')
1116            if loss and iloss != loss :
1117                out += "tb-set-node-lan-loss ${%s} ${%s} %f\n" % \
1118                        (to_tcl_name(e.name), name, float(loss))
1119        out+= "\n"
1120        for f in filters:
1121            out+= f(s)
1122    out+="$ns rtproto %s" % routing
1123    out+="""
1124$ns run
1125"""
1126    return out
1127
1128def topology_to_rspec(t, filters=[]):
1129    out = '<?xml version="1.0" encoding="UTF-8"?>\n' + \
1130        '<rspec xmlns="http://www.protogeni.net/resources/rspec/0.1"\n' + \
1131        '\txmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\n' + \
1132        '\txsi:schemaLocation="http://www.protogeni.net/resources/rspec/0.1 '+ \
1133        'http://www.protogeni.net/resources/rspec/0.1/request.xsd"\n' + \
1134        '\ttype="request" >\n'
1135
1136    ifname = { }
1137    ifnode = { }
1138
1139    for e in [e for e in t.elements if isinstance(e, Computer)]:
1140        name = e.name
1141        virt_type = e.get_attribute("virtualization_type") or "emulab-vnode"
1142        exclusive = e.get_attribute("exclusive") or "1"
1143        hw = e.get_attribute("type") or "pc";
1144        slots = e.get_attribute("slots") or "1";
1145        startup = e.get_attribute("startup")
1146
1147        extras = ""
1148        if startup: extras += '\t\tstartup_command="%s"\n' % startup
1149        out += '\t<node virtual_id="%s"\n\t\tvirtualization_type="%s"\n' % \
1150                (name, virt_type)
1151        out += '\t\texclusive="%s"' % exclusive
1152        if extras: out += '\n%s' % extras
1153        out += '>\n'
1154        out += '\t\t<node_type type_name="%s" slots="%s"/>\n' % (hw, slots)
1155        for i, ii in enumerate(e.interface):
1156            out += '\t\t<interface virtual_id="%s"/>\n' % ii.name
1157            ifnode[ii] = name
1158        for f in filters:
1159            out += f(e)
1160        out += '\t</node>\n'
1161
1162    for i, s in enumerate(t.substrates):
1163        if len(s.interfaces) == 0: 
1164            continue
1165        out += '\t<link virtual_id="%s" link_type="ethernet">\n' % s.name
1166        if s.capacity and s.capacity.kind == "max":
1167            bwout = True
1168            out += '\t\t<bandwidth>%d</bandwidth>\n' % s.capacity.rate
1169        else:
1170            bwout = False
1171        if s.latency and s.latency.kind == "max":
1172            out += '\t\t<latency>%d</latency>\n' % s.latency.time
1173        elif bwout:
1174            out += '\t\t<latency>0</latency>\n'
1175        for ii in s.interfaces:
1176            out += ('\t\t<interface_ref virtual_node_id="%s" ' + \
1177                    'virtual_interface_id="%s"/>\n') % (ifnode[ii], ii.name)
1178        for f in filters:
1179            out += f(s)
1180        out += '\t</link>\n'
1181    out += '</rspec>\n'
1182    return out
1183
Note: See TracBrowser for help on using the repository browser.