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