Create home directory if not found - NS3 needs it indeed
[nepi.git] / src / nepi / testbeds / ns3 / execute.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from constants import TESTBED_ID
5 from nepi.core import testbed_impl
6 from nepi.core.attributes import Attribute
7 from nepi.util.constants import TIME_NOW
8 import os
9 import sys
10 import threading
11
12 class TestbedController(testbed_impl.TestbedController):
13     def __init__(self, testbed_version):
14         super(TestbedController, self).__init__(TESTBED_ID, testbed_version)
15         self._ns3 = None
16         self._home_directory = None
17         self._traces = dict()
18         self._simulator_thread = None
19         self._condition = None
20
21     @property
22     def home_directory(self):
23         return self._home_directory
24
25     @property
26     def ns3(self):
27         return self._ns3
28
29     def do_setup(self):
30         self._home_directory = self._attributes.\
31             get_attribute_value("homeDirectory")
32         self._ns3 = self._load_ns3_module()
33         
34         # create home...
35         home = os.path.normpath(self.home_directory)
36         if not os.path.exists(home):
37             os.makedirs(home, 0755)
38         
39         super(TestbedController, self).do_setup()
40
41     def start(self):
42         super(TestbedController, self).start()
43         self._condition = threading.Condition()
44         self._simulator_thread = threading.Thread(target = self._simulator_run,
45                 args = [self._condition])
46         self._simulator_thread.start()
47
48     def set(self, guid, name, value, time = TIME_NOW):
49         super(TestbedController, self).set(guid, name, value, time)
50         # TODO: take on account schedule time for the task
51         factory_id = self._create[guid]
52         factory = self._factories[factory_id]
53         if factory.box_attributes.is_attribute_design_only(name) or \
54                 factory.box_attributes.is_attribute_invisible(name):
55             return
56         element = self._elements[guid]
57         ns3_value = self._to_ns3_value(guid, name, value) 
58         element.SetAttribute(name, ns3_value)
59
60     def get(self, guid, name, time = TIME_NOW):
61         value = super(TestbedController, self).get(guid, name, time)
62         # TODO: take on account schedule time for the task
63         factory_id = self._create[guid]
64         factory = self._factories[factory_id]
65         if factory.box_attributes.is_attribute_design_only(name) or \
66                 factory.box_attributes.is_attribute_invisible(name):
67             return value
68         TypeId = self.ns3.TypeId()
69         typeid = TypeId.LookupByName(factory_id)
70         info = TypeId.AttributeInfo()
71         if not typeid or not typeid.LookupAttributeByName(name, info):
72             raise AttributeError("Invalid attribute %s for element type %d" % \
73                 (name, guid))
74         checker = info.checker
75         ns3_value = checker.Create() 
76         element = self._elements[guid]
77         element.GetAttribute(name, ns3_value)
78         value = ns3_value.SerializeToString(checker)
79         attr_type = factory.box_attributes.get_attribute_type(name)
80         if attr_type == Attribute.INTEGER:
81             return int(value)
82         if attr_type == Attribute.DOUBLE:
83             return float(value)
84         if attr_type == Attribute.BOOL:
85             return value == "true"
86         return value
87
88     def action(self, time, guid, action):
89         raise NotImplementedError
90
91     def trace_filename(self, guid, trace_id):
92         # TODO: Need to be defined inside a home!!!! with and experiment id_code
93         filename = self._traces[guid][trace_id]
94         return os.path.join(self.home_directory, filename)
95
96     def follow_trace(self, guid, trace_id, filename):
97         if guid not in self._traces:
98             self._traces[guid] = dict()
99         self._traces[guid][trace_id] = filename
100
101     def shutdown(self):
102         for element in self._elements.values():
103             element = None
104
105     def _simulator_run(self, condition):
106         # Run simulation
107         self.ns3.Simulator.Run()
108         # Signal condition on simulation end to notify waiting threads
109         condition.acquire()
110         condition.notifyAll()
111         condition.release()
112
113     def _schedule_event(self, condition, func, *args):
114         """Schedules event on running experiment"""
115         def execute_event(condition, has_event_occurred, func, *args):
116             # exec func
117             func(*args)
118             # flag event occured
119             has_event_occurred[0] = True
120             # notify condition indicating attribute was set
121             condition.acquire()
122             condition.notifyAll()
123             condition.release()
124
125         # contextId is defined as general context
126         contextId = long(0xffffffff)
127         # delay 0 means that the event is expected to execute inmediately
128         delay = self.ns3.Seconds(0)
129         # flag to indicate that the event occured
130         # because bool is an inmutable object in python, in order to create a
131         # bool flag, a list is used as wrapper
132         has_event_occurred = [False]
133         condition.acquire()
134         if not self.ns3.Simulator.IsFinished():
135             self.ns3.Simulator.ScheduleWithContext(contextId, delay, execute_event,
136                  condition, has_event_occurred, func, *args)
137             while not has_event_occurred[0] and not self.ns3.Simulator.IsFinished():
138                 condition.wait()
139                 condition.release()
140                 if not has_event_occurred[0]:
141                     raise RuntimeError('Event could not be scheduled : %s %s ' \
142                     % (repr(func), repr(args)))
143
144     def _to_ns3_value(self, guid, name, value):
145         factory_id = self._create[guid]
146         TypeId = self.ns3.TypeId()
147         typeid = TypeId.LookupByName(factory_id)
148         info = TypeId.AttributeInfo()
149         if not typeid.LookupAttributeByName(name, info):
150             raise RuntimeError("Attribute %s doesn't belong to element %s" \
151                    % (name, factory_id))
152         str_value = str(value)
153         if isinstance(value, bool):
154             str_value = str_value.lower()
155         checker = info.checker
156         ns3_value = checker.Create()
157         ns3_value.DeserializeFromString(str_value, checker)
158         return ns3_value
159
160     def _load_ns3_module(self):
161         import ctypes
162         import imp
163
164         simu_impl_type = self._attributes.get_attribute_value(
165                 "SimulatorImplementationType")
166         checksum = self._attributes.get_attribute_value("ChecksumEnabled")
167
168         bindings = os.environ["NEPI_NS3BINDINGS"] \
169                 if "NEPI_NS3BINDINGS" in os.environ else None
170         libfile = os.environ["NEPI_NS3LIBRARY"] \
171                 if "NEPI_NS3LIBRARY" in os.environ else None
172
173         if libfile:
174             ctypes.CDLL(libfile, ctypes.RTLD_GLOBAL)
175
176         path = [ os.path.dirname(__file__) ] + sys.path
177         if bindings:
178             path = [ bindings ] + path
179
180         try:
181             module = imp.find_module ('ns3', path)
182             mod = imp.load_module ('ns3', *module)
183         except ImportError:
184             # In some environments, ns3 per-se does not exist,
185             # only the low-level _ns3
186             module = imp.find_module ('_ns3', path)
187             mod = imp.load_module ('_ns3', *module)
188             sys.modules["ns3"] = mod # install it as ns3 too
189             
190             # When using _ns3, we have to make sure we destroy
191             # the simulator when the process finishes
192             import atexit
193             atexit.register(mod.Simulator.Destroy)
194     
195         if simu_impl_type:
196             value = mod.StringValue(simu_impl_type)
197             mod.GlobalValue.Bind ("SimulatorImplementationType", value)
198         if checksum:
199             value = mod.BooleanValue(checksum)
200             mod.GlobalValue.Bind ("ChecksumEnabled", value)
201         return mod
202
203     def _get_construct_parameters(self, guid):
204         params = self._get_parameters(guid)
205         construct_params = dict()
206         factory_id = self._create[guid]
207         TypeId = self.ns3.TypeId()
208         typeid = TypeId.LookupByName(factory_id)
209         for name, value in params.iteritems():
210             info = self.ns3.TypeId.AttributeInfo()
211             found = typeid.LookupAttributeByName(name, info)
212             if found and \
213                 (info.flags & TypeId.ATTR_CONSTRUCT == TypeId.ATTR_CONSTRUCT):
214                 construct_params[name] = value
215         return construct_params
216