a3b9c3a3d290a213eeb1a1e8a78863052eefc7c1
[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 @clsinit
30 class OMFWifiInterface(ResourceManager):
31     """
32     .. class:: Class Args :
33       
34         :param ec: The Experiment controller
35         :type ec: ExperimentController
36         :param guid: guid of the RM
37         :type guid: int
38         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
39         :type creds: dict
40
41     .. note::
42
43        This class is used only by the Experiment Controller through the Resource 
44        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     def valid_connection(self, guid):
92         """ Check if the connection with the guid in parameter is possible. 
93         Only meaningful connections are allowed.
94
95         :param guid: Guid of the current RM
96         :type guid: int
97         :rtype:  Boolean
98
99         """
100         rm = self.ec.get_resource(guid)
101         if rm.rtype() in self._authorized_connections:
102             msg = "Connection between %s %s and %s %s accepted" % \
103                 (self.rtype(), self._guid, rm.rtype(), guid)
104             self.debug(msg)
105
106             return True
107
108         msg = "Connection between %s %s and %s %s refused" % \
109              (self.rtype(), self._guid, rm.rtype(), guid)
110         self.debug(msg)
111
112         return False
113
114     @property
115     def node(self):
116         rm_list = self.get_connected(OMFNode.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.rtype())
123         if rm_list: return rm_list[0]
124         return None
125
126
127     def configure_iface(self):
128         """ Configure the interface without the ip
129
130         """
131         if self.node.state < ResourceState.READY:
132             self.ec.schedule(reschedule_delay, self.deploy)
133             return False
134
135         try :
136             for attrname in ["mode", "type", "essid"]:
137                 attrval = self.get(attrname)
138                 attrname = "net/%s/%s" % (self._alias, attrname)
139                 self._omf_api.configure(self.node.get('hostname'), attrname, 
140                         attrval)
141         except AttributeError:
142             self._state = ResourceState.FAILED
143             msg = "Credentials are not initialzed. XMPP Connections impossible"
144             self.debug(msg)
145             #raise
146         
147         super(OMFWifiInterface, self).provision()
148         return True
149
150     def configure_ip(self):
151         """ Configure the ip of the interface
152
153         """
154         if self.channel.state < ResourceState.READY:
155             self.ec.schedule(reschedule_delay, self.deploy)
156             return False
157
158         try :
159             attrval = self.get("ip")
160             attrname = "net/%s/%s" % (self._alias, "ip")
161             self._omf_api.configure(self.node.get('hostname'), attrname, 
162                     attrval)
163         except AttributeError:
164             msg = "Credentials are not initialzed. XMPP Connections impossible"
165             self.debug(msg)
166             self.fail()
167             #raise
168
169         return True
170
171     def deploy(self):
172         """ Deploy the RM. It means : Get the xmpp client and send messages 
173         using OMF 5.4 protocol to configure the interface.
174         It becomes DEPLOYED after sending messages to configure the interface
175         """
176         if not self._omf_api :
177             self._omf_api = OMFAPIFactory.get_api(self.get('xmppSlice'), 
178                 self.get('xmppHost'), self.get('xmppPort'), 
179                 self.get('xmppPassword'), exp_id = self.ec.exp_id)
180
181         if not self._omf_api :
182             msg = "Credentials are not initialzed. XMPP Connections impossible"
183             self.error(msg)
184             self.fail()
185             return
186
187         if not (self.get('mode') and self.get('type') and self.get('essid') \
188                 and self.get('ip')):
189             msg = "Interface's variable are not initialized"
190             self.error(msg)
191             self.fail()
192             return False
193
194         if not self.node.get('hostname') :
195             msg = "The channel is connected with an undefined node"
196             self.error(msg)
197             self.fail()
198             return False
199
200         # Just for information
201         self.debug(" " + self.rtype() + " ( Guid : " + str(self._guid) +") : " + \
202             self.get('mode') + " : " + self.get('type') + " : " + \
203             self.get('essid') + " : " + self.get('ip'))
204     
205         # Check if the node is already deployed
206         chk1 = True
207         if self.state < ResourceState.PROVISIONED:
208             chk1 = self.configure_iface()
209         if chk1:
210             chk2 = self.configure_ip()
211
212         if not (chk1 and chk2) :
213             return False
214             
215         super(OMFWifiInterface, self).deploy()
216         return True
217
218     def release(self):
219         """ Clean the RM at the end of the experiment and release the API
220
221         """
222         if self._omf_api :
223             OMFAPIFactory.release_api(self.get('xmppSlice'), 
224                 self.get('xmppHost'), self.get('xmppPort'), 
225                 self.get('xmppPassword'), exp_id = self.ec.exp_id)
226
227         super(OMFWifiInterface, self).release()
228