6da07db7ffefce531a567a7e0bf7369a4ba85216
[nepi.git] / src / nepi / util / parser / base.py
1 # -*- coding: utf-8 -*-
2
3 import sys
4
5 class ExperimentData(object):
6     def __init__(self):
7         self.data = dict()
8     
9     def __repr__(self):
10         return "%s(%r)" % (self.__class__, self.data)
11     
12     def __str__(self):
13         from pprint import pformat
14         return "%s:%s" % (self.__class__, pformat(self.data))
15
16     @property
17     def guids(self):
18         return self.data.keys()
19
20     def add_testbed_data(self, guid, testbed_id, testbed_version):
21         testbed_data = dict()
22         testbed_data["testbed_id"] = testbed_id
23         testbed_data["testbed_version"] = testbed_version
24         self.data[guid] = testbed_data
25
26     def add_box_data(self, guid, testbed_guid, factory_id):
27         box_data = dict()
28         box_data["testbed_guid"] = testbed_guid
29         box_data["factory_id"] = factory_id
30         self.data[guid] = box_data
31
32     def add_graphical_info_data(self, guid, x, y, width, height):
33         data = self.data[guid]
34         if not "graphical_info" in data:
35             data["graphical_info"] = dict()
36         graphical_info_data = data["graphical_info"]
37         graphical_info_data["x"] = x
38         graphical_info_data["y"] = y
39         graphical_info_data["width"] = width
40         graphical_info_data["height"] = height
41
42     def add_factory_attribute_data(self, guid, name, value):
43         data = self.data[guid]
44         if not "factory_attributes" in data:
45             data["factory_attributes"] = dict()
46         factory_attributes_data = data["factory_attributes"]
47         factory_attributes_data[name] = value
48
49     def add_attribute_data(self, guid, name, value):
50         data = self.data[guid]
51         if not "attributes" in data:
52             data["attributes"] = dict()
53         attributes_data = data["attributes"]
54         attributes_data[name] = value
55
56     def add_trace_data(self, guid, trace_name):
57         data = self.data[guid]
58         if not "traces" in data:
59             data["traces"] = list()
60         traces_data = data["traces"]
61         traces_data.append(trace_name)
62
63     def add_connection_data(self, guid, connector_type_name, other_guid,
64             other_connector_type_name):
65         data = self.data[guid]
66         if not "connections" in data:
67             data["connections"] = dict()
68         connections_data = data["connections"]
69         if not connector_type_name in connections_data:
70             connections_data[connector_type_name] = dict()
71         connection_data = connections_data[connector_type_name]
72         connection_data[other_guid] = other_connector_type_name
73
74     def add_address_data(self, guid, address, netprefix, 
75             broadcast):
76         data = self.data[guid]
77         if not "addresses" in data:
78             data["addresses"] = list()
79         addresses_data = data["addresses"]
80         address_data = dict()
81         if address:
82             address_data["Address"] = address
83         address_data["NetPrefix"] = netprefix
84         if broadcast:
85             address_data["Broadcast"] = broadcast
86         addresses_data.append(address_data)
87
88     def add_route_data(self, guid, destination, netprefix, nexthop, metric):
89         data = self.data[guid]
90         if not "routes" in data:
91             data["routes"] = list()
92         routes_data = data["routes"]
93         route_data = dict({
94             "Destination": destination,
95             "NetPrefix": netprefix, 
96             "NextHop": nexthop, 
97             "Metric": metric
98             })
99         routes_data.append(route_data)
100
101     def is_testbed_data(self, guid):
102         return True if "testbed_id" in self.data[guid] else None
103
104     def get_testbed_data(self, guid):
105         testbed_data = self.data[guid]
106         return (testbed_data["testbed_id"], testbed_data["testbed_version"])
107
108     def get_box_data(self, guid):
109         box_data = self.data[guid]
110         return (box_data["testbed_guid"], box_data["factory_id"])
111
112     def get_graphical_info_data(self, guid):
113         data = self.data[guid]
114         if not "graphical_info" in data:
115             return (0, 0, 0, 0, "") 
116         graphical_info_data = data["graphical_info"]
117         return (graphical_info_data["x"],
118                 graphical_info_data["y"],
119                 graphical_info_data["width"],
120                 graphical_info_data["height"])
121
122     def get_factory_attribute_data(self, guid):
123         data = self.data[guid]
124         if not "factory_attributes" in data:
125             return []
126         factory_attributes_data = data["factory_attributes"]
127         return [(name, value) for name, value \
128                 in factory_attributes_data.iteritems()]
129
130     def get_attribute_data(self, guid, attribute=None, default=None):
131         data = self.data[guid]
132         if not "attributes" in data:
133             if attribute is None:
134                 return []
135             else:
136                 return None
137         attributes_data = data["attributes"]
138         if attribute is None:
139             return [(name, value) for name, value \
140                     in attributes_data.iteritems()]
141         else:
142             return attributes_data.get(attribute, default)
143
144     def set_attribute_data(self, guid, attribute, value):
145         data = self.data[guid]
146         if not "attributes" in data:
147             raise KeyError, "No attributes in reference OBJECT %r" % (guid,)
148         attributes_data = data["attributes"]
149         attributes_data[attribute] = value
150
151     def get_trace_data(self, guid):
152         data = self.data[guid]
153         if not "traces" in data:
154             return []
155         return data["traces"]
156
157     def get_connection_data(self, guid):
158         data = self.data[guid]
159         if not "connections" in data:
160             return []
161         connections_data = data["connections"]
162         return [(connector_type_name, other_guid, other_connector_type_name) \
163                     for connector_type_name, connection_data \
164                         in connections_data.iteritems() \
165                             for other_guid, other_connector_type_name \
166                                 in connection_data.iteritems()]
167
168     def get_address_data(self, guid):
169         data = self.data[guid]
170         if not "addresses" in data:
171             return []
172         addresses_data = data["addresses"]
173         return [(data["Address"] if "Address" in data else None,
174                  data["NetPrefix"] if "NetPrefix" in data else None,
175                  data["Broadcast"] if "Broadcast" in data else None) \
176                  for data in addresses_data]
177
178     def get_route_data(self, guid):
179         data = self.data[guid]
180         if not "routes" in data:
181             return []
182         routes_data = data["routes"]
183         return [(data["Destination"],
184                  data["NetPrefix"],
185                  data["NextHop"],
186                  data["Metric"]) \
187                          for data in routes_data]
188
189 class ExperimentParser(object):
190     def to_data(self, experiment_description):
191         data = ExperimentData()
192         for testbed_description in experiment_description.testbed_descriptions:
193             guid = testbed_description.guid
194             testbed_id = testbed_description.provider.testbed_id
195             testbed_version = testbed_description.provider.testbed_version
196             data.add_testbed_data(guid, testbed_id, testbed_version)
197             self.graphical_info_to_data(data, guid, 
198                     testbed_description.graphical_info)
199             self.attributes_to_data(data, guid, testbed_description.attributes)
200             for box in testbed_description.boxes:
201                 data.add_box_data(box.guid, guid, box.factory_id)
202                 self.graphical_info_to_data(data, box.guid, box.graphical_info)
203                 self.factory_attributes_to_data(data, box.guid, 
204                         box.factory_attributes)
205                 self.attributes_to_data(data, box.guid, box.attributes)
206                 self.traces_to_data(data, box.guid, box.traces)
207                 self.connections_to_data(data, box.guid, box.connectors)
208                 if hasattr(box, "addresses"):
209                     self.addresses_to_data(data, box.guid, box.addresses)
210                 if hasattr(box, "routes"):
211                     self.routes_to_data(data, box.guid, box.routes)
212         return data
213
214     def graphical_info_to_data(self, data, guid, g_info):
215         data.add_graphical_info_data(guid, g_info.x, g_info.y, g_info.width, 
216                 g_info.height)
217
218     def factory_attributes_to_data(self, data, guid, factory_attributes):
219         factory_attributes = factory_attributes or dict()
220         for name, value in factory_attributes.iteritems():
221             data.add_factory_attribute_data(guid, name, value)
222
223     def attributes_to_data(self, data, guid, attributes):
224         for attribute in attributes:
225             if attribute.modified or attribute.has_no_default_value:
226                 data.add_attribute_data(guid, attribute.name, attribute.value)
227
228     def traces_to_data(self, data, guid, traces):
229         for trace in traces:
230             if trace.enabled:
231                 data.add_trace_data(guid, trace.name)
232
233     def connections_to_data(self, data, guid, connectors):
234         for connector in connectors:
235             connector_type_name = connector.connector_type.name
236             for other_connector in connector.connections:
237                 other_guid = other_connector.box.guid
238                 other_connector_type_name = other_connector.connector_type.name
239                 data.add_connection_data(guid, connector_type_name, other_guid,
240                         other_connector_type_name)
241
242     def addresses_to_data(self, data, guid, addresses):
243         for addr in addresses:
244              address = addr.get_attribute_value("Address")
245              netprefix = addr.get_attribute_value("NetPrefix")
246              broadcast = addr.get_attribute_value("Broadcast") \
247                     if addr.has_attribute("Broadcast") and \
248                     addr.is_attribute_modified("Broadcast") else None
249              data.add_address_data(guid, address, netprefix, broadcast)
250
251     def routes_to_data(self, data, guid, routes):
252         for route in routes:
253              destination = route.get_attribute_value("Destination")
254              netprefix = route.get_attribute_value("NetPrefix")
255              nexthop = route.get_attribute_value("NextHop")
256              metric = route.get_attribute_value("Metric")
257              data.add_route_data(guid, destination, netprefix, nexthop, metric)
258
259     def from_data(self, experiment_description, data):
260         box_guids = list()
261         for guid in sorted(data.guids):
262             if data.is_testbed_data(guid):
263                 self.testbed_from_data(experiment_description, guid, data)
264             else:
265                 self.box_from_data(experiment_description, guid, data)
266                 box_guids.append(guid)
267         self.connections_from_data(experiment_description, box_guids, data)
268
269     def testbed_from_data(self, experiment_description, guid, data):
270         from nepi.core.design import FactoriesProvider
271         (testbed_id, testbed_version) = data.get_testbed_data(guid)
272         provider = FactoriesProvider(testbed_id)
273         if provider.testbed_version != testbed_version:
274             raise RuntimeError("Bad testbed version on testbed %s. Asked for %s, got %s" % \
275                     (testbed_id, testbed_version, provider.testbed_version))
276         experiment_description.add_testbed_description(provider, guid)
277         testbed_description = experiment_description.testbed_description(guid)
278         self.graphical_info_from_data(testbed_description, data)
279         self.attributes_from_data(testbed_description, data)
280
281     def box_from_data(self, experiment_description, guid, data):
282         (testbed_guid, factory_id) = data.get_box_data(guid)
283         testbed_description = experiment_description.testbed_description(
284                 testbed_guid)
285         self.factory_attributes_from_data(testbed_description, factory_id,
286                 guid, data)
287         box = testbed_description.create(factory_id, guid)
288
289         self.graphical_info_from_data(box, data)
290         self.attributes_from_data(box, data)
291         self.traces_from_data(box, data)
292         self.addresses_from_data(box, data)
293         self.routes_from_data(box, data)
294
295     def graphical_info_from_data(self, element, data):
296         (x, y, width, height) =  data.get_graphical_info_data(
297                 element.guid)
298         element.graphical_info.x = x
299         element.graphical_info.y = y
300         element.graphical_info.width = width
301         element.graphical_info.height = height
302
303     def factory_attributes_from_data(self, testbed_description, factory_id, 
304             guid, data):
305         factory = testbed_description.provider.factory(factory_id)
306         for (name, value) in data.get_factory_attribute_data(guid):
307             factory.set_attribute_value(name, value)
308
309     def attributes_from_data(self, element, data):
310         for name, value in data.get_attribute_data(element.guid):
311             element.set_attribute_value(name, value)
312
313     def traces_from_data(self, box, data):
314         for name in data.get_trace_data(box.guid):
315             box.enable_trace(name)
316
317     def addresses_from_data(self, box, data):
318         for (address, netprefix, broadcast) in data.get_address_data(box.guid):
319             addr = box.add_address()
320             if address:
321                 addr.set_attribute_value("Address", address)
322             if netprefix != None:
323                 addr.set_attribute_value("NetPrefix", netprefix)
324             if broadcast:
325                 addr.set_attribute_value("Broadcast", broadcast)
326
327     def routes_from_data(self, box, data):
328          for (destination, netprefix, nexthop, metric) \
329                  in data.get_route_data(box.guid):
330             addr = box.add_route()
331             addr.set_attribute_value("Destination", destination)
332             addr.set_attribute_value("NetPrefix", netprefix)
333             addr.set_attribute_value("NextHop", nexthop)
334             addr.set_attribute_value("Metric", metric)
335
336     def connections_from_data(self, experiment_description, guids, data):
337         for guid in guids:
338             box = experiment_description.box(guid)
339             for (connector_type_name, other_guid, other_connector_type_name) \
340                     in data.get_connection_data(guid):
341                     other_box = experiment_description.box(other_guid)
342                     connector = box.connector(connector_type_name)
343                     other_connector = other_box.connector(
344                             other_connector_type_name)
345                     if not connector.is_connected(other_connector):
346                         connector.connect(other_connector)
347