applied the except and raise fixers to the master branch to close the gap with py3
[nepi.git] / src / nepi / resources / omf / interface.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 #         Julien Tribino <julien.tribino@inria.fr>
19
20 import os, time
21 from nepi.util.timefuncs import tnow
22 from nepi.execution.resource import ResourceManager, clsinit_copy, \
23         ResourceState
24 from nepi.execution.attribute import Attribute, Flags 
25
26 from nepi.resources.omf.node import OMFNode, confirmation_counter, reschedule_check
27 from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
28 from nepi.resources.omf.channel import OMFChannel
29 from nepi.resources.omf.omf_api_factory import OMFAPIFactory
30
31 @clsinit_copy
32 class OMFWifiInterface(OMFResource):
33     """
34     .. class:: Class Args :
35       
36         :param ec: The Experiment controller
37         :type ec: ExperimentController
38         :param guid: guid of the RM
39         :type guid: int
40
41     """
42     _rtype = "omf::WifiInterface"
43     _authorized_connections = ["omf::Node" , "omf::Channel", "wilabt::sfa::Node"]
44
45     @classmethod
46     def _register_attributes(cls):
47         """Register the attributes of an OMF interface 
48
49         """
50         name = Attribute("name","Alias of the interface : wlan0, wlan1, ..", default = "wlan0")
51         mode = Attribute("mode","Mode of the interface")
52         hw_mode = Attribute("hw_mode","Choose between : a, b, g, n")
53         essid = Attribute("essid","Essid of the interface")
54         ip = Attribute("ip","IP of the interface")
55         cls._register_attribute(name)
56         cls._register_attribute(mode)
57         cls._register_attribute(hw_mode)
58         cls._register_attribute(essid)
59         cls._register_attribute(ip)
60
61     def __init__(self, ec, guid):
62         """
63         :param ec: The Experiment controller
64         :type ec: ExperimentController
65         :param guid: guid of the RM
66         :type guid: int
67         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
68         :type creds: dict
69
70         """
71         super(OMFWifiInterface, self).__init__(ec, guid)
72
73         self._conf = False
74         self.alias = None
75         self._type = None
76
77         self.create_id = None
78         self._create_cnt = 0
79         self.release_id = None
80         self._release_cnt = 0
81         self._topic_iface = None
82         self._omf_api = None
83         self._type = ""
84
85         # For performance tests
86         self.perf = True
87         self.begin_deploy_time = None
88
89     def valid_connection(self, guid):
90         """ Check if the connection with the guid in parameter is possible. 
91         Only meaningful connections are allowed.
92
93         :param guid: Guid of the current RM
94         :type guid: int
95         :rtype:  Boolean
96
97         """
98         rm = self.ec.get_resource(guid)
99         if rm.get_rtype() in self._authorized_connections:
100             msg = "Connection between %s %s and %s %s accepted" % \
101                 (self.get_rtype(), self._guid, rm.get_rtype(), guid)
102             self.debug(msg)
103             return True
104
105         msg = "Connection between %s %s and %s %s refused" % \
106              (self.get_rtype(), self._guid, rm.get_rtype(), guid)
107         self.debug(msg)
108         return False
109
110     @property
111     def exp_id(self):
112         return self.ec.exp_id
113
114     @property
115     def node(self):
116         rm_list = self.get_connected(OMFNode.get_rtype())
117         if rm_list: return rm_list[0]
118         return None
119
120     @property
121     def channel(self):
122         rm_list = self.get_connected(OMFChannel.get_rtype())
123         if rm_list: return rm_list[0]
124         return None
125
126     def configure_iface(self):
127         """ Configure the interface without the ip
128
129         """
130         if self.node.state < ResourceState.READY:
131             self.ec.schedule(self.reschedule_delay, self.deploy)
132             return False
133
134         for attrname in ["mode", "type", "essid"]:
135             if attrname == "type" :
136                 attrval = self._type
137             else :
138                 attrval = self.get(attrname)
139             attrname = "net/%s/%s" % (self.alias, attrname)
140             self._omf_api.configure(self.node.get('hostname'), attrname, 
141                         attrval)
142         
143         super(OMFWifiInterface, self).do_provision()
144         return True
145
146     def configure_ip(self):
147         """ Configure the ip of the interface
148
149         .. note : The ip is separated from the others parameters to avoid 
150         CELL ID shraing problem. By putting th ip at the end of the configuration, 
151         each node use the same channel and can then share the same CELL ID.
152         In the second case, the channel is defined at the end and the node don't
153         share a common CELL ID and can not communicate.
154
155         """
156         if self.channel.state < ResourceState.READY:
157             self.ec.schedule(self.reschedule_delay, self.deploy)
158             return False
159
160         attrval = self.get("ip")
161         if '/' in attrval:
162            attrval,mask = attrval.split('/')
163         attrname = "net/%s/%s" % (self.alias, "ip")
164         self._omf_api.configure(self.node.get('hostname'), attrname, 
165                     attrval)
166         return True
167
168
169     def configure_on_omf5(self):
170         """ Method to configure the wifi interface when OMF 5.4 is used.
171
172         """    
173
174         self._type = self.get('hw_mode')
175         if self.get('name') == "wlan0" or "eth0":
176             self.alias = "w0"
177         else:    
178             self.alias = "w1"
179         res = False
180         if self.state < ResourceState.PROVISIONED:
181             if self._conf == False:
182                 self._conf = self.configure_iface()
183         if self._conf == True:
184             res = self.configure_ip()
185         return res
186
187     def check_deploy(self, cid):
188         """ Check, through the mail box in the parser, 
189         if the confirmation of the creation has been received
190
191         :param cid: the id of the original message
192         :type guid: string
193
194         """
195         uid = self._omf_api.check_mailbox("create", cid)
196         if uid : 
197             return uid
198         return False
199
200     def do_deploy(self):
201         """ Deploy the RM. It means : Get the xmpp client and send messages 
202         using OMF 5.4 or 6 protocol to configure the interface.
203
204         """
205         if not self.node or self.node.state < ResourceState.READY:
206             self.debug("---- RESCHEDULING DEPLOY ---- node state %s "
207                        % self.node.state )
208             self.ec.schedule(self.reschedule_delay, self.deploy)
209             return
210
211         if not self.channel or self.channel.state < ResourceState.READY:
212             self.debug("---- RESCHEDULING DEPLOY ---- channel state %s "
213                        % self.channel.state )
214             self.ec.schedule(self.reschedule_delay, self.deploy)
215             return
216
217         ## For performance test
218         if self.perf:
219             self.begin_deploy_time = tnow()
220             self.perf = False
221
222         self.set('xmppUser',self.node.get('xmppUser'))
223         self.set('xmppServer',self.node.get('xmppServer'))
224         self.set('xmppPort',self.node.get('xmppPort'))
225         self.set('xmppPassword',self.node.get('xmppPassword'))
226         self.set('version',self.node.get('version'))
227
228         if not self.get('xmppServer'):
229             msg = "XmppServer is not initialzed. XMPP Connections impossible"
230             self.error(msg)
231             raise RuntimeError(msg)
232
233         if not (self.get('xmppUser') or self.get('xmppPort') 
234                    or self.get('xmppPassword')):
235             msg = "Credentials are not all initialzed. Default values will be used"
236             self.warn(msg)
237
238         if not self._omf_api :
239             self._omf_api = OMFAPIFactory.get_api(self.get('version'), 
240               self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'),
241                self.get('xmppPassword'), exp_id = self.exp_id)
242
243         if not (self.get('name')):
244             msg = "Interface's name is not initialized"
245             self.error(msg)
246             raise RuntimeError(msg)
247
248         if not (self.get('mode') and self.get('essid') \
249                  and self.get('hw_mode') and self.get('ip')):
250             msg = "Interface's variable are not initialized"
251             self.error(msg)
252             raise RuntimeError(msg)
253
254         if self.get('version') == "5":
255             res = self.configure_on_omf5()        
256
257         else :
258             res = self.configure_on_omf6()
259
260         if res:
261             super(OMFWifiInterface, self).do_deploy()
262
263     def configure_on_omf6(self):
264         """ Method to configure the wifi interface when OMF 6 is used.
265
266         """   
267         if not self.create_id :
268             props = {}
269             props['wlan:if_name'] = self.get('name')
270             props['wlan:mode'] = {
271                 "mode": self.get('mode'),
272                 "hw_mode" :  self.get('hw_mode'),
273                 "channel" : self.channel.get('channel'),
274                 "essid" : self.get('essid'),
275                 "ip_addr" : self.get('ip'),
276                 "frequency" : self.channel.frequency,
277                 "phy" : "%0%"
278                }
279             props['wlan:hrn'] = self.get('name')
280             props['wlan:type'] = "wlan"
281     
282             self.create_id = os.urandom(16).encode('hex')
283             self._omf_api.frcp_create( self.create_id, self.node.get('hostname'), "wlan", props = props)
284     
285         if self._create_cnt > confirmation_counter:
286             msg = "Couldn't retrieve the confirmation of the creation"
287             self.error(msg)
288             raise RuntimeError(msg)
289
290         uid = self.check_deploy(self.create_id)
291         if not uid:
292             self._create_cnt +=1
293             self.ec.schedule(reschedule_check, self.deploy)
294             return False
295
296         self._topic_iface = uid
297         self._omf_api.enroll_topic(self._topic_iface)
298         return True
299
300     def check_release(self, cid):
301         """ Check, through the mail box in the parser, 
302         if the confirmation of the release has been received
303
304         :param cid: the id of the original message
305         :type guid: string
306
307         """
308         res = self._omf_api.check_mailbox("release", cid)
309         if res : 
310             return res
311         return False
312
313     def do_release(self):
314         """ Clean the RM at the end of the experiment and release the API
315
316         """
317         if self._omf_api:
318             if self.get('version') == "6" and self._topic_iface :
319                 if not self.release_id:
320                     self.release_id = os.urandom(16).encode('hex')
321                     self._omf_api.frcp_release( self.release_id, self.node.get('hostname'),self._topic_iface, res_id=self._topic_iface)
322     
323                 if self._release_cnt < confirmation_counter:
324                     cid = self.check_release(self.release_id)
325                     if not cid:
326                         self._release_cnt +=1
327                         self.ec.schedule(reschedule_check, self.release)
328                         return
329                 else:
330                     msg = "Couldn't retrieve the confirmation of the release"
331                     self.error(msg)
332
333
334             OMFAPIFactory.release_api(self.get('version'), 
335               self.get('xmppServer'), self.get('xmppUser'), self.get('xmppPort'),
336                self.get('xmppPassword'), exp_id = self.exp_id)
337
338         super(OMFWifiInterface, self).do_release()
339