merged ex_shutdown into nepi-3-dev
[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, \
22         ResourceState, reschedule_delay, failtrap
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     def configure_iface(self):
124         """ Configure the interface without the ip
125
126         """
127         if self.node.state < ResourceState.READY:
128             self.ec.schedule(reschedule_delay, self.deploy)
129             return False
130
131         try :
132             for attrname in ["mode", "type", "essid"]:
133                 attrval = self.get(attrname)
134                 attrname = "net/%s/%s" % (self._alias, attrname)
135                 self._omf_api.configure(self.node.get('hostname'), attrname, 
136                         attrval)
137         except AttributeError:
138             self._state = ResourceState.FAILED
139             msg = "Credentials are not initialzed. XMPP Connections impossible"
140             self.debug(msg)
141             #raise
142         
143         super(OMFWifiInterface, self).provision()
144         return True
145
146     def configure_ip(self):
147         """ Configure the ip of the interface
148
149         """
150         if self.channel.state < ResourceState.READY:
151             self.ec.schedule(reschedule_delay, self.deploy)
152             return False
153
154         try :
155             attrval = self.get("ip")
156             attrname = "net/%s/%s" % (self._alias, "ip")
157             self._omf_api.configure(self.node.get('hostname'), attrname, 
158                     attrval)
159         except AttributeError:
160             msg = "Credentials are not initialzed. XMPP Connections impossible"
161             self.debug(msg)
162             self.fail()
163             #raise
164
165         return True
166
167     @failtrap
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         if not self._omf_api :
174             self._omf_api = OMFAPIFactory.get_api(self.get('xmppSlice'), 
175                 self.get('xmppHost'), self.get('xmppPort'), 
176                 self.get('xmppPassword'), exp_id = self.exp_id)
177
178         if not self._omf_api :
179             msg = "Credentials are not initialzed. XMPP Connections impossible"
180             self.error(msg)
181             raise RuntimeError, msg
182
183         if not (self.get('mode') and self.get('type') and self.get('essid') \
184                 and self.get('ip')):
185             msg = "Interface's variable are not initialized"
186             self.error(msg)
187             raise RuntimeError, msg
188
189         if not self.node.get('hostname') :
190             msg = "The channel is connected with an undefined node"
191             self.error(msg)
192             raise RuntimeError, msg
193
194         # Just for information
195         self.debug(" " + self.rtype() + " ( Guid : " + str(self._guid) +") : " + \
196             self.get('mode') + " : " + self.get('type') + " : " + \
197             self.get('essid') + " : " + self.get('ip'))
198     
199         # Check if the node is already deployed
200         if self.state < ResourceState.PROVISIONED:
201             if self.configure_iface():
202                 self.configure_ip()
203
204         super(OMFWifiInterface, self).deploy()
205
206     def release(self):
207         """ Clean the RM at the end of the experiment and release the API
208
209         """
210         try:
211             if self._omf_api :
212                 OMFAPIFactory.release_api(self.get('xmppSlice'), 
213                     self.get('xmppHost'), self.get('xmppPort'), 
214                     self.get('xmppPassword'), exp_id = self.exp_id)
215         except:
216             import traceback
217             err = traceback.format_exc()
218             self.error(err)
219
220         super(OMFWifiInterface, self).release()
221