source: fedd/federation/topdl.py @ ab37086

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

create images from topdl descriptions, a good sign they're coming out right.

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