020b97f179979d86270e6459fd8413c4b96471f1
[nepi.git] / src / nepi / testbeds / netns / execute.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 from constants import TESTBED_ID, TESTBED_VERSION
5 from nepi.core import testbed_impl
6 from nepi.util.constants import TIME_NOW
7 import os
8 import fcntl
9 import threading
10
11 class TestbedController(testbed_impl.TestbedController):
12     from nepi.util.tunchannel_impl import TunChannel
13     
14     LOCAL_FACTORIES = {
15         'TunChannel' : TunChannel,
16     }
17     
18     LOCAL_TYPES = tuple(LOCAL_FACTORIES.values())
19
20     class HostLock(object):
21         # This class is used as a lock to prevent concurrency issues with more
22         # than one instance of netns running in the same machine. Both in 
23         # different processes or different threads.
24         taken = False
25         processcond = threading.Condition()
26         
27         def __init__(self, lockfile):
28             processcond = self.__class__.processcond
29             
30             processcond.acquire()
31             try:
32                 # It's not reentrant
33                 while self.__class__.taken:
34                     processcond.wait()
35                 self.__class__.taken = True
36             finally:
37                 processcond.release()
38             
39             self.lockfile = lockfile
40             fcntl.flock(self.lockfile, fcntl.LOCK_EX)
41         
42         def __del__(self):
43             processcond = self.__class__.processcond
44             
45             processcond.acquire()
46             try:
47                 assert self.__class__.taken, "HostLock unlocked without being locked!"
48
49                 fcntl.flock(self.lockfile, fcntl.LOCK_UN)
50                 
51                 # It's not reentrant
52                 self.__class__.taken = False
53                 processcond.notify()
54             finally:
55                 processcond.release()
56     
57     def __init__(self):
58         super(TestbedController, self).__init__(TESTBED_ID, TESTBED_VERSION)
59         self._netns = None
60         self._home_directory = None
61         self._traces = dict()
62         self._netns_lock = open("/tmp/nepi-netns-lock","a")
63     
64     def _lock(self):
65         return self.HostLock(self._netns_lock)
66
67     @property
68     def home_directory(self):
69         return self._home_directory
70
71     @property
72     def netns(self):
73         return self._netns
74
75     def do_setup(self):
76         self._home_directory = self._attributes.\
77             get_attribute_value("homeDirectory")
78         # create home...
79         home = os.path.normpath(self.home_directory)
80         if not os.path.exists(home):
81             os.makedirs(home, 0755)
82
83         self._netns = self._load_netns_module()
84         super(TestbedController, self).do_setup()
85     
86     def do_create(self):
87         lock = self._lock()
88         super(TestbedController, self).do_create()    
89
90     def set(self, guid, name, value, time = TIME_NOW):
91         super(TestbedController, self).set(guid, name, value, time)
92         # TODO: take on account schedule time for the task 
93         factory_id = self._create[guid]
94         factory = self._factories[factory_id]
95         if factory_id not in self.LOCAL_FACTORIES and \
96                 factory.box_attributes.is_attribute_metadata(name):
97             return
98         element = self._elements.get(guid)
99         if element:
100             setattr(element, name, value)
101
102     def get(self, guid, name, time = TIME_NOW):
103         value = super(TestbedController, self).get(guid, name, time)
104         # TODO: take on account schedule time for the task
105         factory_id = self._create[guid]
106         factory = self._factories[factory_id]
107         if factory_id not in self.LOCAL_FACTORIES and \
108                 factory.box_attributes.is_attribute_metadata(name):
109             return value
110         element = self._elements.get(guid)
111         try:
112             return getattr(element, name)
113         except (KeyError, AttributeError):
114             return value
115
116     def action(self, time, guid, action):
117         raise NotImplementedError
118
119     def shutdown(self):
120         for guid, traces in self._traces.iteritems():
121             for trace_id, (trace, filename) in traces.iteritems():
122                 if hasattr(trace, "close"):
123                     trace.close()
124         for guid, element in self._elements.iteritems():
125             if isinstance(element, self.TunChannel):
126                 element.cleanup()
127             else:
128                 factory_id = self._create[guid]
129                 if factory_id == "Node":
130                     element.destroy()
131         self._elements.clear()
132
133     def trace_filepath(self, guid, trace_id, filename = None):
134         if not filename:
135             (trace, filename) = self._traces[guid][trace_id]
136         return os.path.join(self.home_directory, filename)
137
138     def trace_filename(self, guid, trace_id):
139         (trace, filename) = self._traces[guid][trace_id]
140         return filename
141
142
143     def follow_trace(self, guid, trace_id, trace, filename):
144         if not guid in self._traces:
145             self._traces[guid] = dict()
146         self._traces[guid][trace_id] = (trace, filename)
147
148     def _load_netns_module(self):
149         # TODO: Do something with the configuration!!!
150         import sys
151         __import__("netns")
152         netns_mod = sys.modules["netns"]
153         # enable debug
154         enable_debug = self._attributes.get_attribute_value("enableDebug")
155         if enable_debug:
156             netns_mod.environ.set_log_level(netns_mod.environ.LOG_DEBUG)
157         return netns_mod
158