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

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

Short term fix to ignore unknown elements (like regions)

  • Property mode set to 100644
File size: 33.8 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        #Weed out unknown elements
760        self.elements = [ e for e in self.elements if e is not None ]
761        self.attribute = [ self.init_class(Attribute, c) \
762                for c in self.make_list(attribute) ]
763        self.incorporate_elements()
764
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
791    def incorporate_elements(self):
792
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:
797            s.interfaces = [ ]
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:
804            self.name_element_interfaces(e)
805            for i in e.interface:
806                i.element = e
807                i.subs = [ ]
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
818    def clone(self):
819        return Topology(substrates=[s.clone() for s in self.substrates], 
820                elements=[e.clone() for e in self.elements],
821                attribute=[a.clone() for a in self.attribute],
822                version=self.version)
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
829    def to_dict(self):
830        rv = { }
831        rv['version'] = self.version
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 ]
836        if self.attribute:
837            rv['attribute'] = [ s.to_dict() for s in self.attribute]
838        return rv
839
840    def to_xml(self):
841        rv = "<version>%s</version>" % escape(self.version)
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
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
859
860def topology_from_xml(string=None, file=None, filename=None, top="topology"):
861    class parser:
862        def __init__(self, top):
863            self.stack = [ ]
864            self.chars = ""
865            self.key = ""
866            self.have_chars = False
867            self.current = { }
868            self.in_cdata = False
869            self.in_top = False
870            self.top = top
871       
872        def start_element(self, name, attrs):
873            self.chars = ""
874            self.have_chars = False
875            self.key = str(name)
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 = { }
883
884        def end_element(self, name):
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
892                else:
893                    addit = self.current
894
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]
901                else:
902                    parent[key] = addit
903                self.current = parent
904                self.key = key
905
906            self.chars = ""
907            self.have_chars = False
908
909            if name == self.top:
910                self.in_top= False
911
912        def char_data(self, data):
913            if self.in_top:
914                self.have_chars = True
915                self.chars += data
916
917    p = parser(top=top)
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
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")
932        xp.ParseFile(f)
933        f.close()
934    elif file:
935        xp.ParseFile(file)
936    elif string:
937        xp.Parse(string, True)
938    else:
939        return None
940    return Topology(**p.current[top])
941
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
959def topology_to_xml(t, top=None):
960    """
961    Print the topology as XML, recursively using the internal classes to_xml()
962    methods.
963    """
964
965    if top: return "<%s>%s</%s>" % (top, t.to_xml(), top)
966    else: return t.to_xml()
967
968def topology_to_vtopo(t):
969    nodes = [ ]
970    lans = [ ]
971
972    for eidx, e in enumerate(t.elements):
973        if isinstance(e, Computer):
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                })
1007
1008    return { 'node': nodes, 'lan': lans }
1009
1010def to_tcl_name(n):
1011    t = re.sub('-(\d+)', '(\\1)', n)
1012    return t
1013
1014def generate_portal_command_filter(cmd, add_filter=None, suffix=''):
1015    def rv(e):
1016        s =""
1017        if isinstance(e, Computer):
1018            gw = e.get_attribute('portal')
1019            if add_filter and callable(add_filter):
1020                add = add_filter(e)
1021            else:
1022                add = True
1023            if gw and add:
1024                s = "%s ${%s} %s\n" % (cmd, to_tcl_name(e.name), suffix)
1025        return s
1026    return rv
1027
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:
1034                s = "tb-set-node-os ${%s} %s\n" % (to_tcl_name(e.name), image)
1035        return s
1036    return rv
1037
1038def generate_portal_hardware_filter(type):
1039    def rv(e):
1040        s =""
1041        if isinstance(e, Computer):
1042            gw = e.get_attribute('portal')
1043            if gw:
1044                s = "tb-set-hardware ${%s} %s\n" % (to_tcl_name(e.name), type)
1045        return s
1046    return rv
1047
1048
1049def topology_to_ns2(t, filters=[], routing="Manual"):
1050    out = """
1051set ns [new Simulator]
1052source tb_compat.tcl
1053
1054"""
1055
1056    for e in t.elements:
1057        rpms = ""
1058        tarfiles = ""
1059        if isinstance(e, Computer):
1060            name = to_tcl_name(e.name)
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:
1065                    out += "tb-set-node-os ${%s} %s\n" % (name, osid)
1066            hw = e.get_attribute('type')
1067            if hw:
1068                out += "tb-set-hardware ${%s} %s\n" % (name, hw)
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:
1075                out += "tb-set-node-rpms ${%s} %s\n" % (name, rpms)
1076            if tarfiles:
1077                out += "tb-set-node-tarfiles ${%s} %s\n" % (name, tarfiles)
1078            startcmd = e.get_attribute('startup')
1079            if startcmd:
1080                out+= 'tb-set-node-startcmd ${%s} "%s"\n' % (name, startcmd)
1081            for f in filters:
1082                out += f(e)
1083            out+= "\n"
1084   
1085    for idx, s in enumerate(t.substrates):
1086        if len(s.interfaces) < 2: continue
1087        loss = s.get_attribute('loss')
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
1093        name = to_tcl_name(s.name or "sub%d" % idx)
1094
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"
1121        for f in filters:
1122            out+= f(s)
1123    out+="$ns rtproto %s" % routing
1124    out+="""
1125$ns run
1126"""
1127    return out
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)]:
1141        name = e.name
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):
1157            out += '\t\t<interface virtual_id="%s"/>\n' % ii.name
1158            ifnode[ii] = name
1159        for f in filters:
1160            out += f(e)
1161        out += '\t</node>\n'
1162
1163    for i, s in enumerate(t.substrates):
1164        if len(s.interfaces) == 0: 
1165            continue
1166        out += '\t<link virtual_id="%s" link_type="ethernet">\n' % s.name
1167        if s.capacity and s.capacity.kind == "max":
1168            bwout = True
1169            out += '\t\t<bandwidth>%d</bandwidth>\n' % s.capacity.rate
1170        else:
1171            bwout = False
1172        if s.latency and s.latency.kind == "max":
1173            out += '\t\t<latency>%d</latency>\n' % s.latency.time
1174        elif bwout:
1175            out += '\t\t<latency>0</latency>\n'
1176        for ii in s.interfaces:
1177            out += ('\t\t<interface_ref virtual_node_id="%s" ' + \
1178                    'virtual_interface_id="%s"/>\n') % (ifnode[ii], ii.name)
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.