add the omf resource class
[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 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 #         Julien Tribino <julien.tribino@inria.fr>
20
21 from nepi.execution.resource import ResourceManager, clsinit_copy, ResourceState, \
22         reschedule_delay
23 from nepi.execution.attribute import Attribute, Flags 
24
25 from nepi.resources.omf.node import OMFNode
26 from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
27 from nepi.resources.omf.channel import OMFChannel
28 from nepi.resources.omf.omf_api import OMFAPIFactory
29
30 @clsinit_copy
31 class OMFWifiInterface(OMFResource):
32     """
33     .. class:: Class Args :
34       
35         :param ec: The Experiment controller
36         :type ec: ExperimentController
37         :param guid: guid of the RM
38         :type guid: int
39         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
40         :type creds: dict
41
42     .. note::
43
44        This class is used only by the Experiment Controller through the Resource 
45        Factory
46
47     """
48     _rtype = "OMFWifiInterface"
49     _authorized_connections = ["OMFNode" , "OMFChannel"]
50
51     #alias2name = dict({'w0':'wlan0', 'w1':'wlan1'})
52
53     @classmethod
54     def _register_attributes(cls):
55         """Register the attributes of an OMF interface 
56
57         """
58         alias = Attribute("alias","Alias of the interface", default = "w0")
59         mode = Attribute("mode","Mode of the interface")
60         type = Attribute("type","Type of the interface")
61         essid = Attribute("essid","Essid of the interface")
62         ip = Attribute("ip","IP of the interface")
63         cls._register_attribute(alias)
64         cls._register_attribute(mode)
65         cls._register_attribute(type)
66         cls._register_attribute(essid)
67         cls._register_attribute(ip)
68
69     def __init__(self, ec, guid):
70         """
71         :param ec: The Experiment controller
72         :type ec: ExperimentController
73         :param guid: guid of the RM
74         :type guid: int
75         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
76         :type creds: dict
77
78         """
79         super(OMFWifiInterface, self).__init__(ec, guid)
80
81         self._omf_api = None
82         self._alias = self.get('alias')
83
84     def valid_connection(self, guid):
85         """ Check if the connection with the guid in parameter is possible. 
86         Only meaningful connections are allowed.
87
88         :param guid: Guid of the current RM
89         :type guid: int
90         :rtype:  Boolean
91
92         """
93         rm = self.ec.get_resource(guid)
94         if rm.rtype() in self._authorized_connections:
95             msg = "Connection between %s %s and %s %s accepted" % \
96                 (self.rtype(), self._guid, rm.rtype(), guid)
97             self.debug(msg)
98
99             return True
100
101         msg = "Connection between %s %s and %s %s refused" % \
102              (self.rtype(), self._guid, rm.rtype(), guid)
103         self.debug(msg)
104
105         return False
106
107     @property
108     def exp_id(self):
109         return self.ec.exp_id
110
111     @property
112     def node(self):
113         rm_list = self.get_connected(OMFNode.rtype())
114         if rm_list: return rm_list[0]
115         return None
116
117     @property
118     def channel(self):
119         rm_list = self.get_connected(OMFChannel.rtype())
120         if rm_list: return rm_list[0]
121         return None
122
123
124     def configure_iface(self):
125         """ Configure the interface without the ip
126
127         """
128         if self.node.state < ResourceState.READY:
129             self.ec.schedule(reschedule_delay, self.deploy)
130             return False
131
132         try :
133             for attrname in ["mode", "type", "essid"]:
134                 attrval = self.get(attrname)
135                 attrname = "net/%s/%s" % (self._alias, attrname)
136                 self._omf_api.configure(self.node.get('hostname'), attrname, 
137                         attrval)
138         except AttributeError:
139             self._state = ResourceState.FAILED
140             msg = "Credentials are not initialzed. XMPP Connections impossible"
141             self.debug(msg)
142             #raise
143         
144         super(OMFWifiInterface, self).provision()
145         return True
146
147     def configure_ip(self):
148         """ Configure the ip of the interface
149
150         """
151         if self.channel.state < ResourceState.READY:
152             self.ec.schedule(reschedule_delay, self.deploy)
153             return False
154
155         try :
156             attrval = self.get("ip")
157             attrname = "net/%s/%s" % (self._alias, "ip")
158             self._omf_api.configure(self.node.get('hostname'), attrname, 
159                     attrval)
160         except AttributeError:
161             msg = "Credentials are not initialzed. XMPP Connections impossible"
162             self.debug(msg)
163             self.fail()
164             #raise
165
166         return True
167
168     def deploy(self):
169         """ Deploy the RM. It means : Get the xmpp client and send messages 
170         using OMF 5.4 protocol to configure the interface.
171         It becomes DEPLOYED after sending messages to configure the interface
172         """
173         self.set('xmppSlice', self.node.get('xmppSlice'))
174         self.set('xmppHost', self.node.get('xmppHost'))
175         self.set('xmppPort', self.node.get('xmppPort'))
176         self.set('xmppPassword', self.node.get('xmppPassword'))
177
178         if not self._omf_api :
179             self._omf_api = OMFAPIFactory.get_api(self.get('xmppSlice'), 
180                 self.get('xmppHost'), self.get('xmppPort'), 
181                 self.get('xmppPassword'), exp_id = self.exp_id)
182
183         if not self._omf_api :
184             msg = "Credentials are not initialzed. XMPP Connections impossible"
185             self.error(msg)
186             self.fail()
187             return
188
189         if not (self.get('mode') and self.get('type') and self.get('essid') \
190                 and self.get('ip')):
191             msg = "Interface's variable are not initialized"
192             self.error(msg)
193             self.fail()
194             return False
195
196         if not self.node.get('hostname') :
197             msg = "The channel is connected with an undefined node"
198             self.error(msg)
199             self.fail()
200             return False
201
202         # Just for information
203         self.debug(" " + self.rtype() + " ( Guid : " + str(self._guid) +") : " + \
204             self.get('mode') + " : " + self.get('type') + " : " + \
205             self.get('essid') + " : " + self.get('ip'))
206     
207         # Check if the node is already deployed
208         chk1 = True
209         if self.state < ResourceState.PROVISIONED:
210             chk1 = self.configure_iface()
211         if chk1:
212             chk2 = self.configure_ip()
213
214         if not (chk1 and chk2) :
215             return False
216             
217         super(OMFWifiInterface, self).deploy()
218         return True
219
220
221     def start(self):
222         """ Start the RM. It means nothing special for a channel for now
223         It becomes STARTED as soon as this method starts.
224
225         """
226
227         super(OMFWifiInterface, self).start()
228
229     def stop(self):
230         """ Stop the RM. It means nothing special for a channel for now
231         It becomes STOPPED as soon as this method is called
232
233         """
234         super(OMFWifiInterface, self).stop()
235         self.set_finished()
236
237     def release(self):
238         """ Clean the RM at the end of the experiment and release the API
239
240         """
241         if self._omf_api :
242             OMFAPIFactory.release_api(self.get('xmppSlice'), 
243                 self.get('xmppHost'), self.get('xmppPort'), 
244                 self.get('xmppPassword'), exp_id = self.exp_id)
245
246         super(OMFWifiInterface, self).release()
247