import files that are relative to the source as nepi.full.path
[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 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 class NetNSWrapper(object):
26     def __init__(self, loglevel = logging.INFO, enable_dump = False):
27         super(NetNSWrapper, self).__init__()
28         # holds reference to all C++ objects and variables in the simulation
29         self._objects = dict()
30
31         # Logging
32         self._logger = logging.getLogger("netnswrapper")
33         self._logger.setLevel(loglevel)
34
35         # Object to dump instructions to reproduce and debug experiment
36         from nepi.resources.netns.netnswrapper_debug import NetNSWrapperDebuger
37         self._debuger = NetNSWrapperDebuger(enabled = enable_dump)
38
39     @property
40     def debuger(self):
41         return self._debuger
42
43     @property
44     def logger(self):
45         return self._logger
46
47     def make_uuid(self):
48         return "uuid%s" % uuid.uuid4()
49
50     def get_object(self, uuid):
51         return self._objects.get(uuid)
52  
53     def create(self, clazzname, *args):
54         """ This method should be used to construct netns objects """
55         import netns
56
57         if clazzname not in ['open'] and not hasattr(netns, clazzname):
58             msg = "Type %s not supported" % (clazzname) 
59             self.logger.error(msg)
60
61         uuid = self.make_uuid()
62         
63         ### DEBUG
64         self.logger.debug("CREATE %s( %s )" % (clazzname, str(args)))
65     
66         self.debuger.dump_create(uuid, clazzname, args)
67         ########
68
69         if clazzname == "open":
70             path = args[0] 
71             mode = args[1] 
72             # xxx Thierry: not sure where this gets closed
73             obj = open(path, mode)
74         else:
75             clazz = getattr(netns, clazzname)
76      
77             # arguments starting with 'uuid' identify ns-3 C++
78             # objects and must be replaced by the actual object
79             realargs = self.replace_args(args)
80            
81             obj = clazz(*realargs)
82             
83         self._objects[uuid] = obj
84
85         ### DEBUG
86         self.logger.debug("RET CREATE ( uuid %s ) %s = %s( %s )" % (str(uuid), 
87             str(obj), clazzname, str(args)))
88         ########
89
90         return uuid
91
92     def invoke(self, uuid, operation, *args, **kwargs):
93         newuuid = self.make_uuid()
94         
95         ### DEBUG
96         self.logger.debug("INVOKE %s -> %s( %s, %s ) " % (
97             uuid, operation, str(args), str(kwargs)))
98             
99         self.debuger.dump_invoke(newuuid, uuid, operation, args, kwargs)
100         ########
101
102         obj = self.get_object(uuid)
103         
104         method = getattr(obj, operation)
105
106         # arguments starting with 'uuid' identify netns
107         # objects and must be replaced by the actual object
108         realargs = self.replace_args(args)
109         realkwargs = self.replace_kwargs(kwargs)
110
111         result = method(*realargs, **realkwargs)
112
113         # If the result is an object (not a base value),
114         # then keep track of the object a return the object
115         # reference (newuuid)
116         # xxx the two instances of `int` are from 2to3
117         if not (result is None or type(result) in [
118                 bool, float, int, str, int]):
119             self._objects[newuuid] = result
120             result = newuuid
121
122         ### DEBUG
123         self.logger.debug("RET INVOKE %s%s = %s -> %s(%s, %s) " % (
124             "(uuid %s) " % str(newuuid) if newuuid else "", str(result), uuid, 
125             operation, str(args), str(kwargs)))
126         ########
127
128         return result
129
130     def set(self, uuid, name, value):
131         ### DEBUG
132         self.logger.debug("SET %s %s %s" % (uuid, name, str(value)))
133     
134         self.debuger.dump_set(uuid, name, value)
135         ########
136
137         obj = self.get_object(uuid)
138         setattr(obj, name, value)
139
140         ### DEBUG
141         self.logger.debug("RET SET %s = %s -> set(%s, %s)" % (str(value), uuid, name, 
142             str(value)))
143         ########
144
145         return value
146
147     def get(self, uuid, name):
148         ### DEBUG
149         self.logger.debug("GET %s %s" % (uuid, name))
150         
151         self.debuger.dump_get(uuid, name)
152         ########
153
154         obj = self.get_object(uuid)
155         result = getattr(obj, name)
156
157         ### DEBUG
158         self.logger.debug("RET GET %s = %s -> get(%s)" % (str(result), uuid, name))
159         ########
160
161         return result
162
163     def shutdown(self):
164         ### DEBUG
165         self.debuger.dump_shutdown()
166         ########
167
168         ### FLUSH PIPES
169         sys.stdout.flush()
170         sys.stderr.flush()
171
172         ### RELEASE OBJECTS
173         del self._objects 
174
175         ### DEBUG
176         self.logger.debug("SHUTDOWN")
177         ########
178
179     def replace_args(self, args):
180         realargs = [self.get_object(arg) if \
181                 str(arg).startswith("uuid") else arg for arg in args]
182  
183         return realargs
184
185     def replace_kwargs(self, kwargs):
186         realkwargs = dict([(k, self.get_object(v) \
187                 if str(v).startswith("uuid") else v) \
188                 for k,v in kwargs.items()])
189  
190         return realkwargs
191