source: fedd/federation/topdl.py @ 0fb2973

compt_changesinfo-ops
Last change on this file since 0fb2973 was 0fb2973, checked in by Ted Faber <faber@…>, 12 years ago

Last commit didn't really get tested. Whoops.

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