rename src/nepi/ into just nepi/
[nepi.git] / nepi / resources / netns / netnswrapper.py
1 #
2 #    NEPI, a framework to manage network experiments
3 #    Copyright (C) 2013 INRIA
4 #
5 #    This program is free software: you can redistribute it and/or modify
6 #    it under the terms of the GNU General Public License version 2 as
7 #    published by the Free Software Foundation;
8 #
9 #    This program is distributed in the hope that it will be useful,
10 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #    GNU General Public License for more details.
13 #
14 #    You should have received a copy of the GNU General Public License
15 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 #
17 # Author: Alina Quereilhac <alina.quereilhac@inria.fr>
18
19 import logging
20 import time
21 import os
22 import sys
23 import uuid
24
25 from six import integer_types, string_types
26
27 class NetNSWrapper(object):
28     def __init__(self, loglevel = logging.INFO, enable_dump = False):
29         super(NetNSWrapper, self).__init__()
30         # holds reference to all C++ objects and variables in the simulation
31         self._objects = dict()
32
33         # Logging
34         self._logger = logging.getLogger("netnswrapper")
35         self._logger.setLevel(loglevel)
36
37         # Object to dump instructions to reproduce and debug experiment
38         from nepi.resources.netns.netnswrapper_debug import NetNSWrapperDebuger
39         self._debuger = NetNSWrapperDebuger(enabled = enable_dump)
40
41     @property
42     def debuger(self):
43         return self._debuger
44
45     @property
46     def logger(self):
47         return self._logger
48
49     def make_uuid(self):
50         return "uuid%s" % uuid.uuid4()
51
52     def get_object(self, uuid):
53         return self._objects.get(uuid)
54  
55     def create(self, clazzname, *args):
56         """ This method should be used to construct netns objects """
57         import netns
58
59         if clazzname not in ['open'] and not hasattr(netns, clazzname):
60             msg = "Type %s not supported" % (clazzname) 
61             self.logger.error(msg)
62
63         uuid = self.make_uuid()
64         
65         ### DEBUG
66         self.logger.debug("CREATE %s( %s )" % (clazzname, str(args)))
67     
68         self.debuger.dump_create(uuid, clazzname, args)
69         ########
70
71         if clazzname == "open":
72             path = args[0] 
73             mode = args[1] 
74             # xxx Thierry: not sure where this gets closed
75             obj = open(path, mode)
76         else:
77             clazz = getattr(netns, clazzname)
78      
79             # arguments starting with 'uuid' identify ns-3 C++
80             # objects and must be replaced by the actual object
81             realargs = self.replace_args(args)
82            
83             obj = clazz(*realargs)
84             
85         self._objects[uuid] = obj
86
87         ### DEBUG
88         self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), 
89             str(obj), clazzname, str(args)))
90         ########
91
92         return uuid
93
94     def invoke(self, uuid, operation, *args, **kwargs):
95         newuuid = self.make_uuid()
96         
97         ### DEBUG
98         self.logger.debug("INVOKE %s -> %s( %s, %s ) " % (
99             uuid, operation, str(args), str(kwargs)))
100             
101         self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs)
102         ########
103
104         obj = self.get_object(uuid)
105         
106         method = getattr(obj, operation)
107
108         # arguments starting with 'uuid' identify netns
109         # objects and must be replaced by the actual object
110         realargs = self.replace_args(args)
111         realkwargs = self.replace_kwargs(kwargs)
112
113         result = method(*realargs, **realkwargs)
114
115         # If the result is an object (not a base value),
116         # then keep track of the object and return the object
117         # reference (newuuid)
118         if result is not None \
119           and not isinstance(result, (bool, float) + integer_types + string_types):
120             self._objects[newuuid] = result
121             result = newuuid
122
123         ### DEBUG
124         self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % (
125             "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid, 
126             operation, str(args), str(kwargs)))
127         ########
128
129         return result
130
131     def set(self, uuid, name, value):
132         ### DEBUG
133         self.logger.debug("SET %s %s %s" % (uuid, name, str(value)))
134     
135         self.debuger.dump_set(uuid, name, value)
136         ########
137
138         obj = self.get_object(uuid)
139         setattr(obj, name, value)
140
141         ### DEBUG
142         self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, 
143             str(value)))
144         ########
145
146         return value
147
148     def get(self, uuid, name):
149         ### DEBUG
150         self.logger.debug("GET %s %s" % (uuid, name))
151         
152         self.debuger.dump_get(uuid, name)
153         ########
154
155         obj = self.get_object(uuid)
156         result = getattr(obj, name)
157
158         ### DEBUG
159         self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name))
160         ########
161
162         return result
163
164     def shutdown(self):
165         ### DEBUG
166         self.debuger.dump_shutdown()
167         ########
168
169         ### FLUSH PIPES
170         sys.stdout.flush()
171         sys.stderr.flush()
172
173         ### RELEASE OBJECTS
174         del self._objects 
175
176         ### DEBUG
177         self.logger.debug("SHUTDOWN")
178         ########
179
180     def replace_args(self, args):
181         realargs = [self.get_object(arg) if \
182                 str(arg).startswith("uuid") else arg for arg in args]
183  
184         return realargs
185
186     def replace_kwargs(self, kwargs):
187         realkwargs = dict([(k, self.get_object(v) \
188                 if str(v).startswith("uuid") else v) \
189                 for k,v in kwargs.items()])
190  
191         return realkwargs
192