2 # -*- coding: utf-8 -*-
4 from nepi.core.attributes import Attribute, AttributesMap
5 from nepi.util import proxy, validation
6 from nepi.util.constants import STATUS_FINISHED
7 from nepi.util.parser._xml import XmlExperimentParser
10 class ConnectorType(object):
11 def __init__(self, testbed_id, factory_id, name, max = -1, min = 0):
12 super(ConnectorType, self).__init__()
17 "The maximum number of connections allowed need to be more than 0")
20 "The minimum number of connections allowed needs to be at least 0")
21 # connector_type_id -- univoquely identifies a connector type
23 self._connector_type_id = (testbed_id.lower(), factory_id.lower(),
25 # name -- display name for the connector type
27 # max -- maximum amount of connections that this type support,
30 # min -- minimum amount of connections required by this type of connector
32 # from_connections -- connections where the other connector is the "From"
33 # to_connections -- connections where the other connector is the "To"
34 # keys in the dictionary correspond to the
35 # connector_type_id for possible connections. The value is a tuple:
36 # (can_cross, connect)
37 # can_cross: indicates if the connection is allowed accros different
39 # code: is the connection function to be invoked when the elements
41 self._from_connections = dict()
42 self._to_connections = dict()
45 def connector_type_id(self):
46 return self._connector_type_id
60 def add_from_connection(self, testbed_id, factory_id, name, can_cross, code):
61 self._from_connections[(testbed_id.lower(), factory_id.lower(),
62 name.lower())] = (can_cross, code)
64 def add_to_connection(self, testbed_id, factory_id, name, can_cross, code):
65 self._to_connections[(testbed_id.lower(), factory_id.lower(),
66 name.lower())] = (can_cross, code)
68 def can_connect(self, testbed_id, factory_id, name, count,
70 connector_type_id = (testbed_id.lower(), factory_id.lower(),
72 if connector_type_id in self._from_connections:
73 (can_cross, code) = self._from_connections[connector_type_id]
74 elif connector_type_id in self._to_connections:
75 (can_cross, code) = self._to_connections[connector_type_id]
78 return not must_cross or can_cross
80 def code_to_connect(self, testbed_id, factory_id, name):
81 connector_type_id = (testbed_id.lower(), factory_id.lower(),
83 if not connector_type_id in self._to_connections.keys():
85 (can_cross, code) = self._to_connections[connector_type_id]
88 # TODO: create_function, start_function, stop_function, status_function
90 class Factory(AttributesMap):
91 def __init__(self, factory_id, create_function, start_function,
92 stop_function, status_function, configure_function,
93 allow_addresses = False, allow_routes = False):
94 super(Factory, self).__init__()
95 self._factory_id = factory_id
96 self._allow_addresses = (allow_addresses == True)
97 self._allow_routes = (allow_routes == True)
98 self._create_function = create_function
99 self._start_function = start_function
100 self._stop_function = stop_function
101 self._status_function = status_function
102 self._configure_function = configure_function
103 self._connector_types = dict()
104 self._traces = list()
105 self._box_attributes = AttributesMap()
108 def factory_id(self):
109 return self._factory_id
112 def allow_addresses(self):
113 return self._allow_addresses
116 def allow_routes(self):
117 return self._allow_routes
120 def box_attributes(self):
121 return self._box_attributes
124 def create_function(self):
125 return self._create_function
128 def start_function(self):
129 return self._start_function
132 def stop_function(self):
133 return self._stop_function
136 def status_function(self):
137 return self._status_function
140 def configure_function(self):
141 return self._configure_function
147 def connector_type(self, name):
148 return self._connector_types[name]
150 def add_connector_type(self, connector_type):
151 self._connector_types[connector_type.name] = connector_type
153 def add_trace(self, trace_id):
154 self._traces.append(trace_id)
156 def add_box_attribute(self, name, help, type, value = None, range = None,
157 allowed = None, flags = Attribute.NoFlags, validation_function = None):
158 self._box_attributes.add_attribute(name, help, type, value, range,
159 allowed, flags, validation_function)
161 class TestbedInstance(object):
162 def __init__(self, testbed_id, testbed_version):
163 self._testbed_id = testbed_id
164 self._testbed_version = testbed_version
168 raise NotImplementedError
170 def configure(self, name, value):
171 """Set a configuartion attribute for the testbed instance"""
172 raise NotImplementedError
174 def create(self, guid, factory_id):
175 """Instructs creation of element """
176 raise NotImplementedError
178 def create_set(self, guid, name, value):
179 """Instructs setting an initial attribute on an element"""
180 raise NotImplementedError
182 def factory_set(self, guid, name, value):
183 """Instructs setting an attribute on a factory"""
184 raise NotImplementedError
186 def connect(self, guid1, connector_type_name1, guid2,
187 connector_type_name2):
188 raise NotImplementedError
190 def cross_connect(self, guid, connector_type_name, cross_guid,
191 cross_testbed_id, cross_factory_id, cross_connector_type_name):
192 raise NotImplementedError
194 def add_trace(self, guid, trace_id):
195 raise NotImplementedError
197 def add_address(self, guid, address, netprefix, broadcast):
198 raise NotImplementedError
200 def add_route(self, guid, destination, netprefix, nexthop):
201 raise NotImplementedError
204 """After do_setup the testbed initial configuration is done"""
205 raise NotImplementedError
208 """After do_create all instructed elements are created and
210 raise NotImplementedError
212 def do_connect(self):
213 """After do_connect all internal connections between testbed elements
215 raise NotImplementedError
217 def do_configure(self):
218 """After do_configure elements are configured"""
219 raise NotImplementedError
221 def do_cross_connect(self):
222 """After do_cross_connect all external connections between different testbed
224 raise NotImplementedError
227 raise NotImplementedError
230 raise NotImplementedError
232 def set(self, time, guid, name, value):
233 raise NotImplementedError
235 def get(self, time, guid, name):
236 raise NotImplementedError
238 def action(self, time, guid, action):
239 raise NotImplementedError
241 def status(self, guid):
242 raise NotImplementedError
244 def trace(self, guid, trace_id):
245 raise NotImplementedError
248 raise NotImplementedError
250 class ExperimentController(object):
251 def __init__(self, experiment_xml):
252 self._experiment_xml = experiment_xml
253 self._testbeds = dict()
254 self._access_config = dict()
257 def experiment_xml(self):
258 return self._experiment_xml
260 def set_access_configuration(self, testbed_guid, access_config):
261 self._access_config[testbed_guid] = access_config
263 def trace(self, testbed_guid, guid, trace_id):
264 return self._testbeds[testbed_guid].trace(guid, trace_id)
267 self._create_testbed_instances()
268 for testbed in self._testbeds.values():
270 for testbed in self._testbeds.values():
273 testbed.do_configure()
274 for testbed in self._testbeds.values():
275 testbed.do_cross_connect()
276 for testbed in self._testbeds.values():
280 for testbed in self._testbeds.values():
283 def is_finished(self, guid):
284 for testbed in self._testbeds.values():
285 for guid_ in testbed.guids:
287 return testbed.status(guid) == STATUS_FINISHED
288 raise RuntimeError("No element exists with guid %d" % guid)
291 for testbed in self._testbeds.values():
294 def _create_testbed_instances(self):
295 parser = XmlExperimentParser()
296 data = parser.from_xml_to_data(self._experiment_xml)
297 element_guids = list()
298 for guid in data.guids:
299 if data.is_testbed_data(guid):
300 (testbed_id, testbed_version) = data.get_testbed_data(guid)
301 access_config = None if guid not in self._access_config else\
302 self._access_config[guid]
303 testbed = proxy.create_testbed_instance(testbed_id,
304 testbed_version, access_config)
305 for (name, value) in data.get_attribute_data(guid):
306 testbed.configure(name, value)
307 self._testbeds[guid] = testbed
309 element_guids.append(guid)
310 self._program_testbed_instances(element_guids, data)
312 def _program_testbed_instances(self, element_guids, data):
313 for guid in element_guids:
314 (testbed_guid, factory_id) = data.get_box_data(guid)
315 testbed = self._testbeds[testbed_guid]
316 testbed.create(guid, factory_id)
317 for (name, value) in data.get_attribute_data(guid):
318 testbed.create_set(guid, name, value)
320 for guid in element_guids:
321 (testbed_guid, factory_id) = data.get_box_data(guid)
322 testbed = self._testbeds[testbed_guid]
323 for (connector_type_name, other_guid, other_connector_type_name) \
324 in data.get_connection_data(guid):
325 (testbed_guid, factory_id) = data.get_box_data(guid)
326 (other_testbed_guid, other_factory_id) = data.get_box_data(
328 if testbed_guid == other_testbed_guid:
329 testbed.connect(guid, connector_type_name, other_guid,
330 other_connector_type_name)
332 testbed.cross_connect(guid, connector_type_name, other_guid,
333 other_testbed_id, other_factory_id, other_connector_type_name)
334 for trace_id in data.get_trace_data(guid):
335 testbed.add_trace(guid, trace_id)
336 for (autoconf, address, netprefix, broadcast) in \
337 data.get_address_data(guid):
339 testbed.add_address(guid, address, netprefix, broadcast)
340 for (destination, netprefix, nexthop) in data.get_route_data(guid):
341 testbed.add_route(guid, destination, netprefix, nexthop)