source: fedd/deter/topdl.py @ 6a50b78

compt_changes
Last change on this file since 6a50b78 was 6a50b78, checked in by Ted Faber <faber@…>, 12 years ago

Initial benito plug in. Fixed bug pickling topdl as well

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