source: fedd/federation/topdl.py @ eec716b

axis_examplecompt_changesinfo-opsversion-2.00version-3.01version-3.02
Last change on this file since eec716b was eec716b, checked in by Ted Faber <faber@…>, 15 years ago

Add topology description

  • Property mode set to 100644
File size: 9.5 KB
Line 
1#!/usr/local/bin/python
2
3class base:
4    @staticmethod
5    def init_class(c, arg):
6        if isinstance(arg, dict):
7            return c(**arg)
8        elif isinstance(arg, c):
9            return arg
10        else:
11            return None
12
13    @staticmethod
14    def make_list(a):
15        if isinstance(a, basestring) or isinstance(a, dict): return [ a ]
16        elif getattr(a, '__iter__', None): return a
17        else: return [ a ]
18
19
20
21class ConsistencyError(RuntimeError): pass
22
23class Attribute(base):
24    def __init__(self, attribute, value):
25        self.attribute = attribute
26        self.value = value
27
28    def to_dict(self):
29        return { 'attribute': self.attribute, 'value': self.value }
30
31class Capacity(base):
32    def __init__(self, rate, kind):
33        self.rate = rate
34        self.kind = kind
35
36    def to_dict(self):
37        return { 'rate': self.rate, 'kind': self.kind }
38
39class Latency(base):
40    def __init__(self, time, kind):
41        self.time = time
42        self.kind = kind
43
44    def to_dict(self):
45        return { 'time': self.time, 'kind': self.kind }
46
47class Substrate(base):
48    def __init__(self, name, capacity=None, latency=None, attribute=[]):
49        self.name = name
50        self.capacity = self.init_class(Capacity, capacity)
51        self.latency = self.init_class(Latency, latency)
52        self.attribute = [ self.init_class(Attribute, a) \
53                for a in self.make_list(attribute) ]
54        self.interfaces = [ ]
55
56    def to_dict(self):
57        rv = { 'name': self.name }
58        if self.capacity:
59            rv['capacity'] = self.capacity.to_dict()
60        if self.latency:
61            rv['latency'] = self.latency.to_dict()
62        if self.attribute:
63            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
64        return rv
65
66class CPU(base):
67    def __init__(self, type, attribute=[]):
68        self.type = type
69        self.attribute = [ self.init_class(Attribute, a) for a in \
70                self.make_list(attribute) ]
71
72    def to_dict(self):
73        rv = { 'type': self.type}
74        if self.attribute:
75            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
76        return rv
77
78class Storage(base):
79    def __init__(self, amount, persistence, attribute=[]):
80        if isinstance(amount, basestring):
81            self.amount = float(amount)
82        else:
83            self.amount = amount
84        self.presistence = persistence
85        self.attribute = [ self.init_class(Attribute, a) \
86                for a in self.make_list(attribute) ]
87
88    def to_dict(self):
89        rv = { 'amount': float(self.amount), 'persistence': self.persistence }
90        if self.attribute:
91            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
92        return rv
93
94class OperatingSystem(base):
95    def __init__(self, name, version=None, distribution=None,
96            distributionversion=None, attribute=[]):
97        self.name = name
98        self.version = version
99        self.distribution = distribution
100        self.distributionversion = distributionversion
101        self.attribute = [ self.init_class(Attribute, a) \
102                for a in self.make_list(attribute) ]
103
104    def to_dict(self):
105        rv = { 'name': self.name }
106        if self.version: rv['version'] = self.version
107        if self.distribution: rv['version'] = self.distribution
108        if self.distributionversion: rv['version'] = self.distributionversion
109        if self.attribute:
110            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
111        return rv
112
113class Software(base):
114    def __init__(self, location, install=None, attribute=[]):
115        self.location = location
116        self.install = install
117        self.attribute = [ self.init_class(Attribute, a)\
118                for a in self.make_list(attribute) ]
119
120    def to_dict(self):
121        rv = { 'location': self.location }
122        if self.install: rv['install'] = self.install
123        if self.attribute:
124            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
125        return rv
126
127class Interface(base):
128    def __init__(self, substrate, capacity=None, latency=None, attribute=[],
129            element=None):
130        if isinstance(substrate, basestring):
131            self.substrate = [ substrate ]
132        else:
133            self.substrate = substrate
134        self.capacity = self.init_class(Capacity, capacity)
135        self.latency = self.init_class(Latency, latency)
136        self.attribute = [ self.init_class(Attribute, a) \
137                for a in self.make_list(attribute) ]
138        self.element = element
139        self.subs = [ ]
140
141    def to_dict(self):
142        rv = { 'substrate': self.substrate }
143        if self.capacity:
144            rv['capacity'] = self.capacity.to_dict()
145        if self.latency:
146            rv['latency'] = self.latency.to_dict()
147        if self.attribute:
148            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
149        return rv
150
151class Computer(base):
152    def __init__(self, cpu=[], os=[], software=[], storage=[], interface=[],
153            attribute=[]):
154        def assign_element(i):
155            i.element = self
156
157        self.cpu = [ self.init_class(CPU, c)  for c in self.make_list(cpu) ]
158        self.os = [ self.init_class(OperatingSystem, c) \
159                for c in self.make_list(os) ]
160        self.software = [ self.init_class(Software, c) \
161                for c in self.make_list(software) ]
162        self.storage = [ self.init_class(Storage, c) \
163                for c in self.make_list(storage) ]
164        self.interface = [ self.init_class(Interface, c) \
165                for c in self.make_list(interface) ]
166        self.attribute = [ self.init_class(Attribute, a) \
167                for a in self.make_list(attribute) ]
168        map(assign_element, self.interface)
169
170    def to_dict(self):
171        rv = { }
172        if self.cpu:
173            rv['cpu'] = [ c.to_dict() for  c in self.cpu ]
174        if self.os:
175            rv['os'] = [ o.to_dict() for o in self.os ]
176        if self.software:
177            rv['software'] = [ s.to_dict() for s in self.software ]
178        if self.storage:
179            rv['storage'] = [ s.to_dict for s in self.storage ]
180        if self.interface:
181            rv['interface'] = [ i.to_dict() for i in self.interface ]
182        if self.attribute:
183            rv['attribute'] = [ i.to_dict() for i in self.attribute ]
184        return rv
185
186class Other(base):
187    def __init__(self, interface=[], attribute=[]):
188        self.interface = [ self.init_class(Interface, c) \
189                for c in self.make_list(interface) ]
190        self.attribute = [ self.init_class(Attribute, c) \
191                for c in self.make_list(attribute) ]
192
193    def to_dict(self):
194        if self.interface:
195            rv['interface'] = [ i.to_dict() for i in self.interface ]
196        if self.attribute:
197            rv['attribute'] = [ a.to_dict() for a in self.attribute ]
198
199
200class Topology(base):
201    @staticmethod
202    def init_element(e):
203        """
204        e should be of the form { typename: args } where args is a dict full of
205        the right parameters to initialize the element.  e should have only one
206        key, but we walk e's keys in an arbitrary order and instantiate the
207        first key we know how to.
208        """
209        classmap = {
210                'computer': Computer,
211                'other': Other,
212            }
213
214        for k in e.keys():
215            cl = classmap.get(k, None)
216            if cl: return cl(**e[k])
217
218    def __init__(self, substrates=[], elements=[]):
219        self.substrates = [ self.init_class(Substrate, s) \
220                for s in self.make_list(substrates) ]
221        self.elements = [ self.init_element(e) \
222                for e in self.make_list(elements) ]
223        # Could to this init in one gulp, but we want to look for duplicate
224        # substrate names
225        substrate_map = { }
226        for s in self.substrates:
227            if not substrate_map.has_key(s.name):
228                substrate_map[s.name] = s
229            else:
230                raise ConsistencyError("Duplicate substrate name %s" % s.name)
231
232        substrate_map = dict([ (s.name, s) for s in self.substrates ])
233        for e in self.elements:
234            for i in e.interface:
235                for sn in i.substrate:
236                    # NB, interfaces have substrate names in their substrate
237                    # attribute.
238                    if substrate_map.has_key(sn):
239                        sub = substrate_map[sn]
240                        i.subs.append(sub)
241                        sub.interfaces.append(i)
242                    else:
243                        raise ConsistencyError("No such substrate for %s" % sn)
244
245    def to_dict(self):
246        rv = { }
247        if self.substrates:
248            rv['substrates'] = [ s.to_dict() for s in self.substrates ]
249        if self.elements:
250            rv['elements'] = [ s.to_dict() for s in self.elements ]
251        return rv
252
253def topology_from_xml(file=None, top="topology"):
254    import xml.parsers.expat
255
256    class parser:
257        def __init__(self):
258            self.stack = [ ]
259            self.chars = ""
260            self.key = ""
261            self.have_chars = False
262            self.current = { }
263            self.in_cdata = False
264       
265        def start_element(self, name, attrs):
266            self.chars = ""
267            self.have_chars = False
268            self.key = str(name)
269            self.stack.append((self.current, self.key))
270            self.current = { }
271
272        def end_element(self, name):
273            if self.have_chars:
274                self.chars = self.chars.strip()
275                if len(self.chars) >0:
276                    addit = self.chars
277                else:
278                    addit = self.current
279            else:
280                addit = self.current
281
282            parent, key = self.stack.pop()
283            if parent.has_key(key):
284                if isinstance(parent[key], list):
285                    parent[key].append(addit)
286                else:
287                    parent[key] = [parent[key], addit]
288            else:
289                parent[key] = addit
290            self.current = parent
291            self.key = key
292
293            self.chars = ""
294            self.have_chars = False
295
296        def char_data(self, data):
297            self.have_chars = True
298            self.chars += data
299
300    p = parser()
301    xp = xml.parsers.expat.ParserCreate()
302
303    xp.StartElementHandler = p.start_element
304    xp.EndElementHandler = p.end_element
305    xp.CharacterDataHandler = p.char_data
306
307    f = open(file, "r")
308
309    xp.ParseFile(f)
310
311    return Topology(**p.current[top])
312
313def topology_to_xml(t, top=None):
314    """
315    Print the topology as XML.  This is quick and dirty, but should work for
316    many purposes.  Convert the topology to a dict and print it recursively.
317    """
318    from xml.sax.saxutils import escape
319
320    def dict_to_xml(e, top=None):
321        if top: rv = "<%s>" % top
322        else: rv = ""
323
324        for k in e.keys():
325            if isinstance(e[k], (basestring, int, float, long)):
326                rv += "<%s>%s</%s>" % (k, escape(e[k]), k)
327            elif isinstance(e[k], dict):
328                rv += "<%s>%s</%s>" % (k, dict_to_xml(e[k]), k)
329            elif getattr(e[k], '__iter__', None):
330                for ee in e[k]:
331                    if isinstance(ee, dict):
332                        rv += "<%s>%s</%s>" % (k, dict_to_xml(ee), k)
333                    else:
334                        rv += "<%s>%s</%s>" % (k, escape(ee), k)
335            else:
336                raise ConsistencyError("What is this?? %s %s" % (k, e[k]))
337        if top: rv += "</%s>" % top
338        return rv
339
340    return dict_to_xml(t.to_dict(), top)
341
342
343
Note: See TracBrowser for help on using the repository browser.