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