2 # -*- coding: utf-8 -*-
4 from nepi.core.attributes import Attribute, AttributesMap
5 from nepi.core.connector import ConnectorTypeBase
6 from nepi.util import validation
7 from nepi.util.constants import STATUS_FINISHED, TIME_NOW
8 from nepi.util.parser._xml import XmlExperimentParser
17 ATTRIBUTE_PATTERN_BASE = re.compile(r"\{#\[(?P<label>[-a-zA-Z0-9._]*)\](?P<expr>(?P<component>\.addr\[[0-9]+\]|\.route\[[0-9]+\]|\.trace\[[0-9]+\])?.\[(?P<attribute>[-a-zA-Z0-9._]*)\])#}")
18 ATTRIBUTE_PATTERN_GUID_SUB = r"{#[%(guid)s]%(expr)s#}"
19 COMPONENT_PATTERN = re.compile(r"(?P<kind>[a-z]*)\[(?P<index>.*)\]")
21 class ConnectorType(ConnectorTypeBase):
22 def __init__(self, testbed_id, factory_id, name, max = -1, min = 0):
23 super(ConnectorType, self).__init__(testbed_id, factory_id, name, max, min)
24 # from_connections -- connections where the other connector is the "From"
25 # to_connections -- connections where the other connector is the "To"
26 # keys in the dictionary correspond to the
27 # connector_type_id for possible connections. The value is a tuple:
28 # (can_cross, connect)
29 # can_cross: indicates if the connection is allowed accros different
31 # code: is the connection function to be invoked when the elements
33 self._from_connections = dict()
34 self._to_connections = dict()
36 def add_from_connection(self, testbed_id, factory_id, name, can_cross,
37 init_code, compl_code):
38 type_id = self.make_connector_type_id(testbed_id, factory_id, name)
39 self._from_connections[type_id] = (can_cross, init_code, compl_code)
41 def add_to_connection(self, testbed_id, factory_id, name, can_cross,
42 init_code, compl_code):
43 type_id = self.make_connector_type_id(testbed_id, factory_id, name)
44 self._to_connections[type_id] = (can_cross, init_code, compl_code)
46 def can_connect(self, testbed_id, factory_id, name, count,
48 connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
49 for lookup_type_id in self._type_resolution_order(connector_type_id):
50 if lookup_type_id in self._from_connections:
51 (can_cross, init_code, compl_code) = self._from_connections[lookup_type_id]
52 elif lookup_type_id in self._to_connections:
53 (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
57 return not must_cross or can_cross
61 def _connect_to_code(self, testbed_id, factory_id, name,
63 connector_type_id = self.make_connector_type_id(testbed_id, factory_id, name)
64 for lookup_type_id in self._type_resolution_order(connector_type_id):
65 if lookup_type_id in self._to_connections:
66 (can_cross, init_code, compl_code) = self._to_connections[lookup_type_id]
67 if not must_cross or can_cross:
68 return (init_code, compl_code)
72 def connect_to_init_code(self, testbed_id, factory_id, name, must_cross):
73 return self._connect_to_code(testbed_id, factory_id, name, must_cross)[0]
75 def connect_to_compl_code(self, testbed_id, factory_id, name, must_cross):
76 return self._connect_to_code(testbed_id, factory_id, name, must_cross)[1]
78 class Factory(AttributesMap):
79 def __init__(self, factory_id, create_function, start_function,
80 stop_function, status_function,
81 configure_function, preconfigure_function,
83 allow_addresses = False, has_addresses = False,
84 allow_routes = False, has_routes = False):
85 super(Factory, self).__init__()
86 self._factory_id = factory_id
87 self._allow_addresses = bool(allow_addresses)
88 self._allow_routes = bool(allow_routes)
89 self._has_addresses = bool(has_addresses) or self._allow_addresses
90 self._has_routes = bool(has_routes) or self._allow_routes
91 self._create_function = create_function
92 self._start_function = start_function
93 self._stop_function = stop_function
94 self._status_function = status_function
95 self._configure_function = configure_function
96 self._preconfigure_function = preconfigure_function
97 self._prestart_function = prestart_function
98 self._connector_types = dict()
101 self._box_attributes = AttributesMap()
104 def factory_id(self):
105 return self._factory_id
108 def allow_addresses(self):
109 return self._allow_addresses
112 def allow_routes(self):
113 return self._allow_routes
116 def has_addresses(self):
117 return self._has_addresses
120 def has_routes(self):
121 return self._has_routes
124 def box_attributes(self):
125 return self._box_attributes
128 def create_function(self):
129 return self._create_function
132 def prestart_function(self):
133 return self._prestart_function
136 def start_function(self):
137 return self._start_function
140 def stop_function(self):
141 return self._stop_function
144 def status_function(self):
145 return self._status_function
148 def configure_function(self):
149 return self._configure_function
152 def preconfigure_function(self):
153 return self._preconfigure_function
163 def connector_type(self, name):
164 return self._connector_types[name]
166 def add_connector_type(self, connector_type):
167 self._connector_types[connector_type.name] = connector_type
169 def add_trace(self, trace_id):
170 self._traces.append(trace_id)
172 def add_tag(self, tag_id):
173 self._tags.append(tag_id)
175 def add_box_attribute(self, name, help, type, value = None, range = None,
176 allowed = None, flags = Attribute.NoFlags, validation_function = None,
178 self._box_attributes.add_attribute(name, help, type, value, range,
179 allowed, flags, validation_function, category)
181 class TestbedController(object):
182 def __init__(self, testbed_id, testbed_version):
183 self._testbed_id = testbed_id
184 self._testbed_version = testbed_version
187 def testbed_id(self):
188 return self._testbed_id
191 def testbed_version(self):
192 return self._testbed_version
196 raise NotImplementedError
198 def defer_configure(self, name, value):
199 """Instructs setting a configuartion attribute for the testbed instance"""
200 raise NotImplementedError
202 def defer_create(self, guid, factory_id):
203 """Instructs creation of element """
204 raise NotImplementedError
206 def defer_create_set(self, guid, name, value):
207 """Instructs setting an initial attribute on an element"""
208 raise NotImplementedError
210 def defer_factory_set(self, guid, name, value):
211 """Instructs setting an attribute on a factory"""
212 raise NotImplementedError
214 def defer_connect(self, guid1, connector_type_name1, guid2,
215 connector_type_name2):
216 """Instructs creation of a connection between the given connectors"""
217 raise NotImplementedError
219 def defer_cross_connect(self,
220 guid, connector_type_name,
221 cross_guid, cross_testbed_guid,
222 cross_testbed_id, cross_factory_id,
223 cross_connector_type_name):
225 Instructs creation of a connection between the given connectors
226 of different testbed instances
228 raise NotImplementedError
230 def defer_add_trace(self, guid, trace_id):
231 """Instructs the addition of a trace"""
232 raise NotImplementedError
234 def defer_add_address(self, guid, address, netprefix, broadcast):
235 """Instructs the addition of an address"""
236 raise NotImplementedError
238 def defer_add_route(self, guid, destination, netprefix, nexthop):
239 """Instructs the addition of a route"""
240 raise NotImplementedError
243 """After do_setup the testbed initial configuration is done"""
244 raise NotImplementedError
248 After do_create all instructed elements are created and
251 raise NotImplementedError
253 def do_connect_init(self):
255 After do_connect_init all internal connections between testbed elements
258 raise NotImplementedError
260 def do_connect_compl(self):
262 After do_connect all internal connections between testbed elements
265 raise NotImplementedError
267 def do_preconfigure(self):
269 Done just before resolving netrefs, after connection, before cross connections,
270 useful for early stages of configuration, for setting up stuff that might be
271 required for netref resolution.
273 raise NotImplementedError
275 def do_configure(self):
276 """After do_configure elements are configured"""
277 raise NotImplementedError
279 def do_prestart(self):
280 """Before do_start elements are prestart-configured"""
281 raise NotImplementedError
283 def do_cross_connect_init(self, cross_data):
285 After do_cross_connect_init initiation of all external connections
286 between different testbed elements is performed
288 raise NotImplementedError
290 def do_cross_connect_compl(self, cross_data):
292 After do_cross_connect_compl completion of all external connections
293 between different testbed elements is performed
295 raise NotImplementedError
298 raise NotImplementedError
301 raise NotImplementedError
303 def set(self, guid, name, value, time = TIME_NOW):
304 raise NotImplementedError
306 def get(self, guid, name, time = TIME_NOW):
307 raise NotImplementedError
309 def get_route(self, guid, index, attribute):
313 guid: guid of box to query
314 index: number of routing entry to fetch
315 attribute: one of Destination, NextHop, NetPrefix
317 raise NotImplementedError
319 def get_address(self, guid, index, attribute='Address'):
323 guid: guid of box to query
324 index: number of inteface to select
325 attribute: one of Address, NetPrefix, Broadcast
327 raise NotImplementedError
329 def get_attribute_list(self, guid):
330 raise NotImplementedError
332 def get_factory_id(self, guid):
333 raise NotImplementedError
335 def action(self, time, guid, action):
336 raise NotImplementedError
338 def status(self, guid):
339 raise NotImplementedError
341 def trace(self, guid, trace_id, attribute='value'):
342 raise NotImplementedError
344 def traces_info(self):
345 """ dictionary of dictionaries:
351 filesize = size in bytes,
355 raise NotImplementedError
358 raise NotImplementedError
360 class ExperimentController(object):
361 def __init__(self, experiment_xml, root_dir):
362 self._experiment_xml = experiment_xml
363 self._testbeds = dict()
364 self._deployment_config = dict()
365 self._netrefs = collections.defaultdict(set)
366 self._testbed_netrefs = collections.defaultdict(set)
367 self._cross_data = dict()
368 self._root_dir = root_dir
369 self._netreffed_testbeds = set()
370 self._guids_in_testbed_cache = dict()
372 self.persist_experiment_xml()
375 def experiment_xml(self):
376 return self._experiment_xml
381 for testbed_guid in self._testbeds.keys():
382 _guids = self._guids_in_testbed(testbed_guid)
387 def persist_experiment_xml(self):
388 xml_path = os.path.join(self._root_dir, "experiment.xml")
389 f = open(xml_path, "w")
390 f.write(self._experiment_xml)
393 def trace(self, guid, trace_id, attribute='value'):
394 testbed = self._testbed_for_guid(guid)
396 return testbed.trace(guid, trace_id, attribute)
397 raise RuntimeError("No element exists with guid %d" % guid)
399 def traces_info(self):
401 for guid, testbed in self._testbeds.iteritems():
402 traces_info[guid] = testbed.traces_info()
406 def _parallel(callables):
409 @functools.wraps(callable)
410 def wrapped(*p, **kw):
415 traceback.print_exc(file=sys.stderr)
416 excs.append(sys.exc_info())
418 threads = [ threading.Thread(target=wrap(callable)) for callable in callables ]
419 for thread in threads:
421 for thread in threads:
424 eTyp, eVal, eLoc = exc
425 raise eTyp, eVal, eLoc
428 parser = XmlExperimentParser()
429 data = parser.from_xml_to_data(self._experiment_xml)
431 self._init_testbed_controllers(data)
433 # persist testbed connection data, for potential recovery
434 self._persist_testbed_proxies()
436 def steps_to_configure(self, allowed_guids):
437 # perform setup in parallel for all test beds,
438 # wait for all threads to finish
439 self._parallel([testbed.do_setup
440 for guid,testbed in self._testbeds.iteritems()
441 if guid in allowed_guids])
443 # perform create-connect in parallel, wait
444 # (internal connections only)
445 self._parallel([testbed.do_create
446 for guid,testbed in self._testbeds.iteritems()
447 if guid in allowed_guids])
449 self._parallel([testbed.do_connect_init
450 for guid,testbed in self._testbeds.iteritems()
451 if guid in allowed_guids])
453 self._parallel([testbed.do_connect_compl
454 for guid,testbed in self._testbeds.iteritems()
455 if guid in allowed_guids])
457 self._parallel([testbed.do_preconfigure
458 for guid,testbed in self._testbeds.iteritems()
459 if guid in allowed_guids])
462 steps_to_configure(self, self._testbeds)
464 if self._netreffed_testbeds:
465 # initally resolve netrefs
466 self.do_netrefs(data, fail_if_undefined=False)
468 # rinse and repeat, for netreffed testbeds
469 netreffed_testbeds = set(self._netreffed_testbeds)
471 self._init_testbed_controllers(data)
473 # persist testbed connection data, for potential recovery
474 self._persist_testbed_proxies()
476 # configure dependant testbeds
477 steps_to_configure(self, netreffed_testbeds)
479 # final netref step, fail if anything's left unresolved
480 self.do_netrefs(data, fail_if_undefined=True)
482 self._program_testbed_cross_connections(data)
484 # perform do_configure in parallel for al testbeds
485 # (it's internal configuration for each)
486 self._parallel([testbed.do_configure
487 for testbed in self._testbeds.itervalues()])
491 #print >>sys.stderr, "DO IT"
495 # cross-connect (cannot be done in parallel)
496 for guid, testbed in self._testbeds.iteritems():
497 cross_data = self._get_cross_data(guid)
498 testbed.do_cross_connect_init(cross_data)
499 for guid, testbed in self._testbeds.iteritems():
500 cross_data = self._get_cross_data(guid)
501 testbed.do_cross_connect_compl(cross_data)
505 # Last chance to configure (parallel on all testbeds)
506 self._parallel([testbed.do_prestart
507 for testbed in self._testbeds.itervalues()])
511 # start experiment (parallel start on all testbeds)
512 self._parallel([testbed.start
513 for testbed in self._testbeds.itervalues()])
517 def _clear_caches(self):
518 # Cleaning cache for safety.
519 self._guids_in_testbed_cache = dict()
521 def _persist_testbed_proxies(self):
522 TRANSIENT = ('Recover',)
524 # persist access configuration for all testbeds, so that
525 # recovery mode can reconnect to them if it becomes necessary
526 conf = ConfigParser.RawConfigParser()
527 for testbed_guid, testbed_config in self._deployment_config.iteritems():
528 testbed_guid = str(testbed_guid)
529 conf.add_section(testbed_guid)
530 for attr in testbed_config.attributes_list:
531 if attr not in TRANSIENT:
532 conf.set(testbed_guid, attr,
533 testbed_config.get_attribute_value(attr))
535 f = open(os.path.join(self._root_dir, 'deployment_config.ini'), 'w')
539 def _load_testbed_proxies(self):
544 BOOLEAN : 'getboolean',
547 # deferred import because proxy needs
548 # our class definitions to define proxies
549 import nepi.util.proxy as proxy
551 conf = ConfigParser.RawConfigParser()
552 conf.read(os.path.join(self._root_dir, 'deployment_config.ini'))
553 for testbed_guid in conf.sections():
554 testbed_config = proxy.AccessConfiguration()
555 for attr in conf.options(testbed_guid):
556 testbed_config.set_attribute_value(attr,
557 conf.get(testbed_guid, attr) )
559 testbed_guid = str(testbed_guid)
560 conf.add_section(testbed_guid)
561 for attr in testbed_config.attributes_list:
562 if attr not in TRANSIENT:
563 getter = getattr(conf, TYPEMAP.get(
564 testbed_config.get_attribute_type(attr),
566 testbed_config.set_attribute_value(
567 testbed_guid, attr, getter(attr))
569 def _unpersist_testbed_proxies(self):
571 os.remove(os.path.join(self._root_dir, 'deployment_config.ini'))
573 # Just print exceptions, this is just cleanup
575 traceback.print_exc(file=sys.stderr)
578 for testbed in self._testbeds.values():
580 self._unpersist_testbed_proxies()
583 # reload perviously persisted testbed access configurations
584 self._load_testbed_proxies()
586 # recreate testbed proxies by reconnecting only
587 self._init_testbed_controllers(recover = True)
589 # another time, for netrefs
590 self._init_testbed_controllers(recover = True)
592 def is_finished(self, guid):
593 testbed = self._testbed_for_guid(guid)
595 return testbed.status(guid) == STATUS_FINISHED
596 raise RuntimeError("No element exists with guid %d" % guid)
598 def set(self, guid, name, value, time = TIME_NOW):
599 testbed = self._testbed_for_guid(guid)
601 testbed.set(guid, name, value, time)
603 raise RuntimeError("No element exists with guid %d" % guid)
605 def get(self, guid, name, time = TIME_NOW):
606 testbed = self._testbed_for_guid(guid)
608 return testbed.get(guid, name, time)
609 raise RuntimeError("No element exists with guid %d" % guid)
611 def get_factory_id(self, guid):
612 testbed = self._testbed_for_guid(guid)
614 return testbed.get_factory_id(guid)
615 raise RuntimeError("No element exists with guid %d" % guid)
617 def get_testbed_id(self, guid):
618 testbed = self._testbed_for_guid(guid)
620 return testbed.testbed_id
621 raise RuntimeError("No element exists with guid %d" % guid)
623 def get_testbed_version(self, guid):
624 testbed = self._testbed_for_guid(guid)
626 return testbed.testbed_version
627 raise RuntimeError("No element exists with guid %d" % guid)
631 for testbed in self._testbeds.values():
635 exceptions.append(sys.exc_info())
636 for exc_info in exceptions:
637 raise exc_info[0], exc_info[1], exc_info[2]
639 def _testbed_for_guid(self, guid):
640 for testbed_guid in self._testbeds.keys():
641 if guid in self._guids_in_testbed(testbed_guid):
642 return self._testbeds[testbed_guid]
645 def _guids_in_testbed(self, testbed_guid):
646 if testbed_guid not in self._testbeds:
648 if testbed_guid not in self._guids_in_testbed_cache:
649 self._guids_in_testbed_cache[testbed_guid] = \
650 set(self._testbeds[testbed_guid].guids)
651 return self._guids_in_testbed_cache[testbed_guid]
654 def _netref_component_split(component):
655 match = COMPONENT_PATTERN.match(component)
657 return match.group("kind"), match.group("index")
659 return component, None
661 _NETREF_COMPONENT_GETTERS = {
663 lambda testbed, guid, index, name:
664 testbed.get_address(guid, int(index), name),
666 lambda testbed, guid, index, name:
667 testbed.get_route(guid, int(index), name),
669 lambda testbed, guid, index, name:
670 testbed.trace(guid, index, name),
672 lambda testbed, guid, index, name:
673 testbed.get(guid, name),
676 def resolve_netref_value(self, value, failval = None):
677 match = ATTRIBUTE_PATTERN_BASE.search(value)
679 label = match.group("label")
680 if label.startswith('GUID-'):
681 ref_guid = int(label[5:])
683 expr = match.group("expr")
684 component = (match.group("component") or "")[1:] # skip the dot
685 attribute = match.group("attribute")
687 # split compound components into component kind and index
688 # eg: 'addr[0]' -> ('addr', '0')
689 component, component_index = self._netref_component_split(component)
691 # find object and resolve expression
692 for ref_testbed_guid, ref_testbed in self._testbeds.iteritems():
693 if component not in self._NETREF_COMPONENT_GETTERS:
694 raise ValueError, "Malformed netref: %r - unknown component" % (expr,)
695 elif ref_guid not in self._guids_in_testbed(ref_testbed_guid):
698 ref_value = self._NETREF_COMPONENT_GETTERS[component](
699 ref_testbed, ref_guid, component_index, attribute)
701 return value.replace(match.group(), ref_value)
702 # couldn't find value
705 def do_netrefs(self, data, fail_if_undefined = False):
707 for (testbed_guid, guid), attrs in self._netrefs.items():
708 testbed = self._testbeds.get(testbed_guid)
709 if testbed is not None:
710 for name in set(attrs):
711 value = testbed.get(guid, name)
712 if isinstance(value, basestring):
713 ref_value = self.resolve_netref_value(value)
714 if ref_value is not None:
715 testbed.set(guid, name, ref_value)
717 elif fail_if_undefined:
718 raise ValueError, "Unresolvable netref in: %r=%r" % (name,value,)
720 del self._netrefs[(testbed_guid, guid)]
723 for testbed_guid, attrs in self._testbed_netrefs.items():
724 tb_data = dict(data.get_attribute_data(testbed_guid))
726 for name in set(attrs):
727 value = tb_data.get(name)
728 if isinstance(value, basestring):
729 ref_value = self.resolve_netref_value(value)
730 if ref_value is not None:
731 data.set_attribute_data(testbed_guid, name, ref_value)
733 elif fail_if_undefined:
734 raise ValueError, "Unresolvable netref in: %r" % (value,)
736 del self._testbed_netrefs[testbed_guid]
739 def _init_testbed_controllers(self, data, recover = False):
740 blacklist_testbeds = set(self._testbeds)
741 element_guids = list()
743 data_guids = data.guids
745 # create testbed controllers
746 for guid in data_guids:
747 if data.is_testbed_data(guid):
748 if guid not in self._testbeds:
749 self._create_testbed_controller(guid, data, element_guids,
752 (testbed_guid, factory_id) = data.get_box_data(guid)
753 if testbed_guid not in blacklist_testbeds:
754 element_guids.append(guid)
755 label = data.get_attribute_data(guid, "label")
756 if label is not None:
757 if label in label_guids:
758 raise RuntimeError, "Label %r is not unique" % (label,)
759 label_guids[label] = guid
761 # replace references to elements labels for its guid
762 self._resolve_labels(data, data_guids, label_guids)
764 # program testbed controllers
766 self._program_testbed_controllers(element_guids, data)
768 def _resolve_labels(self, data, data_guids, label_guids):
769 netrefs = self._netrefs
770 testbed_netrefs = self._testbed_netrefs
771 for guid in data_guids:
772 for name, value in data.get_attribute_data(guid):
773 if isinstance(value, basestring):
774 match = ATTRIBUTE_PATTERN_BASE.search(value)
776 label = match.group("label")
777 if not label.startswith('GUID-'):
778 ref_guid = label_guids.get(label)
779 if ref_guid is not None:
780 value = ATTRIBUTE_PATTERN_BASE.sub(
781 ATTRIBUTE_PATTERN_GUID_SUB % dict(
782 guid = 'GUID-%d' % (ref_guid,),
783 expr = match.group("expr"),
786 data.set_attribute_data(guid, name, value)
788 # memorize which guid-attribute pairs require
789 # postprocessing, to avoid excessive controller-testbed
790 # communication at configuration time
791 # (which could require high-latency network I/O)
792 if not data.is_testbed_data(guid):
793 (testbed_guid, factory_id) = data.get_box_data(guid)
794 netrefs[(testbed_guid, guid)].add(name)
796 testbed_netrefs[guid].add(name)
798 def _create_testbed_controller(self, guid, data, element_guids, recover):
799 (testbed_id, testbed_version) = data.get_testbed_data(guid)
800 deployment_config = self._deployment_config.get(guid)
802 # deferred import because proxy needs
803 # our class definitions to define proxies
804 import nepi.util.proxy as proxy
806 if deployment_config is None:
808 deployment_config = proxy.AccessConfiguration()
810 for (name, value) in data.get_attribute_data(guid):
811 if value is not None and deployment_config.has_attribute(name):
812 # if any deployment config attribute has a netref, we can't
813 # create this controller yet
814 if isinstance(value, basestring) and ATTRIBUTE_PATTERN_BASE.search(value):
815 # remember to re-issue this one
816 self._netreffed_testbeds.add(guid)
819 # copy deployment config attribute
820 deployment_config.set_attribute_value(name, value)
823 self._deployment_config[guid] = deployment_config
825 if deployment_config is not None:
826 # force recovery mode
827 deployment_config.set_attribute_value("recover",recover)
829 testbed = proxy.create_testbed_controller(testbed_id,
830 testbed_version, deployment_config)
831 for (name, value) in data.get_attribute_data(guid):
832 testbed.defer_configure(name, value)
833 self._testbeds[guid] = testbed
834 if guid in self._netreffed_testbeds:
835 self._netreffed_testbeds.remove(guid)
837 def _program_testbed_controllers(self, element_guids, data):
838 for guid in element_guids:
839 (testbed_guid, factory_id) = data.get_box_data(guid)
840 testbed = self._testbeds.get(testbed_guid)
842 testbed.defer_create(guid, factory_id)
843 for (name, value) in data.get_attribute_data(guid):
844 # Try to resolve create-time netrefs, if possible
845 if isinstance(value, basestring) and ATTRIBUTE_PATTERN_BASE.search(value):
847 nuvalue = self.resolve_netref_value(value)
849 # Any trouble means we're not in shape to resolve the netref yet
851 if nuvalue is not None:
852 # Only if we succeed we remove the netref deferral entry
854 data.set_attribute_data(guid, name, value)
855 if (testbed_guid, guid) in self._netrefs:
856 self._netrefs[(testbed_guid, guid)].discard(name)
857 testbed.defer_create_set(guid, name, value)
859 for guid in element_guids:
860 (testbed_guid, factory_id) = data.get_box_data(guid)
861 testbed = self._testbeds.get(testbed_guid)
863 for (connector_type_name, cross_guid, cross_connector_type_name) \
864 in data.get_connection_data(guid):
865 (testbed_guid, factory_id) = data.get_box_data(guid)
866 (cross_testbed_guid, cross_factory_id) = data.get_box_data(
868 if testbed_guid == cross_testbed_guid:
869 testbed.defer_connect(guid, connector_type_name,
870 cross_guid, cross_connector_type_name)
871 for trace_id in data.get_trace_data(guid):
872 testbed.defer_add_trace(guid, trace_id)
873 for (autoconf, address, netprefix, broadcast) in \
874 data.get_address_data(guid):
876 testbed.defer_add_address(guid, address, netprefix,
878 for (destination, netprefix, nexthop) in data.get_route_data(guid):
879 testbed.defer_add_route(guid, destination, netprefix, nexthop)
881 def _program_testbed_cross_connections(self, data):
882 data_guids = data.guids
884 for guid in data_guids:
885 if not data.is_testbed_data(guid):
886 (testbed_guid, factory_id) = data.get_box_data(guid)
887 testbed = self._testbeds.get(testbed_guid)
889 for (connector_type_name, cross_guid, cross_connector_type_name) \
890 in data.get_connection_data(guid):
891 (testbed_guid, factory_id) = data.get_box_data(guid)
892 (cross_testbed_guid, cross_factory_id) = data.get_box_data(
894 if testbed_guid != cross_testbed_guid:
895 cross_testbed = self._testbeds[cross_testbed_guid]
896 cross_testbed_id = cross_testbed.testbed_id
897 testbed.defer_cross_connect(guid, connector_type_name, cross_guid,
898 cross_testbed_guid, cross_testbed_id, cross_factory_id,
899 cross_connector_type_name)
900 # save cross data for later
901 self._add_crossdata(testbed_guid, guid, cross_testbed_guid,
904 def _add_crossdata(self, testbed_guid, guid, cross_testbed_guid, cross_guid):
905 if testbed_guid not in self._cross_data:
906 self._cross_data[testbed_guid] = dict()
907 if cross_testbed_guid not in self._cross_data[testbed_guid]:
908 self._cross_data[testbed_guid][cross_testbed_guid] = set()
909 self._cross_data[testbed_guid][cross_testbed_guid].add(cross_guid)
911 def _get_cross_data(self, testbed_guid):
913 if not testbed_guid in self._cross_data:
915 for cross_testbed_guid, guid_list in \
916 self._cross_data[testbed_guid].iteritems():
917 cross_data[cross_testbed_guid] = dict()
918 cross_testbed = self._testbeds[cross_testbed_guid]
919 for cross_guid in guid_list:
920 elem_cross_data = dict(
922 _testbed_guid = cross_testbed_guid,
923 _testbed_id = cross_testbed.testbed_id,
924 _testbed_version = cross_testbed.testbed_version)
925 cross_data[cross_testbed_guid][cross_guid] = elem_cross_data
926 attributes_list = cross_testbed.get_attribute_list(cross_guid)
927 for attr_name in attributes_list:
928 attr_value = cross_testbed.get(cross_guid, attr_name)
929 elem_cross_data[attr_name] = attr_value