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 defer_configure(self, name, value):
171 """Instructs setting a configuartion attribute for the testbed instance"""
172 raise NotImplementedError
174 def defer_create(self, guid, factory_id):
175 """Instructs creation of element """
176 raise NotImplementedError
178 def defer_create_set(self, guid, name, value):
179 """Instructs setting an initial attribute on an element"""
180 raise NotImplementedError
182 def defer_factory_set(self, guid, name, value):
183 """Instructs setting an attribute on a factory"""
184 raise NotImplementedError
186 def defer_connect(self, guid1, connector_type_name1, guid2,
187 connector_type_name2):
188 """Instructs creation of a connection between the given connectors"""
189 raise NotImplementedError
191 def defer_cross_connect(self, guid, connector_type_name, cross_guid,
192 cross_testbed_id, cross_factory_id, cross_connector_type_name):
194 Instructs creation of a connection between the given connectors
195 of different testbed instances
197 raise NotImplementedError
199 def defer_add_trace(self, guid, trace_id):
200 """Instructs the addition of a trace"""
201 raise NotImplementedError
203 def defer_add_address(self, guid, address, netprefix, broadcast):
204 """Instructs the addition of an address"""
205 raise NotImplementedError
207 def defer_add_route(self, guid, destination, netprefix, nexthop):
208 """Instructs the addition of a route"""
209 raise NotImplementedError
212 """After do_setup the testbed initial configuration is done"""
213 raise NotImplementedError
217 After do_create all instructed elements are created and
220 raise NotImplementedError
222 def do_connect(self):
224 After do_connect all internal connections between testbed elements
227 raise NotImplementedError
229 def do_configure(self):
230 """After do_configure elements are configured"""
231 raise NotImplementedError
233 def do_cross_connect(self):
235 After do_cross_connect all external connections between different testbed
238 raise NotImplementedError
241 raise NotImplementedError
244 raise NotImplementedError
246 def set(self, time, guid, name, value):
247 raise NotImplementedError
249 def get(self, time, guid, name):
250 raise NotImplementedError
252 def action(self, time, guid, action):
253 raise NotImplementedError
255 def status(self, guid):
256 raise NotImplementedError
258 def trace(self, guid, trace_id):
259 raise NotImplementedError
262 raise NotImplementedError
264 class ExperimentController(object):
265 def __init__(self, experiment_xml):
266 self._experiment_xml = experiment_xml
267 self._testbeds = dict()
268 self._access_config = dict()
271 def experiment_xml(self):
272 return self._experiment_xml
274 def set_access_configuration(self, testbed_guid, access_config):
275 self._access_config[testbed_guid] = access_config
277 def trace(self, testbed_guid, guid, trace_id):
278 return self._testbeds[testbed_guid].trace(guid, trace_id)
281 self._create_testbed_instances()
282 for testbed in self._testbeds.values():
284 for testbed in self._testbeds.values():
287 testbed.do_configure()
288 for testbed in self._testbeds.values():
289 testbed.do_cross_connect()
290 for testbed in self._testbeds.values():
294 for testbed in self._testbeds.values():
297 def is_finished(self, guid):
298 for testbed in self._testbeds.values():
299 for guid_ in testbed.guids:
301 return testbed.status(guid) == STATUS_FINISHED
302 raise RuntimeError("No element exists with guid %d" % guid)
305 for testbed in self._testbeds.values():
308 def _create_testbed_instances(self):
309 parser = XmlExperimentParser()
310 data = parser.from_xml_to_data(self._experiment_xml)
311 element_guids = list()
312 for guid in data.guids:
313 if data.is_testbed_data(guid):
314 (testbed_id, testbed_version) = data.get_testbed_data(guid)
315 access_config = None if guid not in self._access_config else\
316 self._access_config[guid]
317 testbed = proxy.create_testbed_instance(testbed_id,
318 testbed_version, access_config)
319 for (name, value) in data.get_attribute_data(guid):
320 testbed.defer_configure(name, value)
321 self._testbeds[guid] = testbed
323 element_guids.append(guid)
324 self._program_testbed_instances(element_guids, data)
326 def _program_testbed_instances(self, element_guids, data):
327 for guid in element_guids:
328 (testbed_guid, factory_id) = data.get_box_data(guid)
329 testbed = self._testbeds[testbed_guid]
330 testbed.defer_create(guid, factory_id)
331 for (name, value) in data.get_attribute_data(guid):
332 testbed.defer_create_set(guid, name, value)
334 for guid in element_guids:
335 (testbed_guid, factory_id) = data.get_box_data(guid)
336 testbed = self._testbeds[testbed_guid]
337 for (connector_type_name, other_guid, other_connector_type_name) \
338 in data.get_connection_data(guid):
339 (testbed_guid, factory_id) = data.get_box_data(guid)
340 (other_testbed_guid, other_factory_id) = data.get_box_data(
342 if testbed_guid == other_testbed_guid:
343 testbed.defer_connect(guid, connector_type_name, other_guid,
344 other_connector_type_name)
346 testbed.defer_cross_connect(guid, connector_type_name, other_guid,
347 other_testbed_id, other_factory_id, other_connector_type_name)
348 for trace_id in data.get_trace_data(guid):
349 testbed.defer_add_trace(guid, trace_id)
350 for (autoconf, address, netprefix, broadcast) in \
351 data.get_address_data(guid):
353 testbed.defer_add_address(guid, address, netprefix, broadcast)
354 for (destination, netprefix, nexthop) in data.get_route_data(guid):
355 testbed.defer_add_route(guid, destination, netprefix, nexthop)