Making runId as sub folder optional for the Collector RM
[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
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
40     """
41     _rtype = "OMFWifiInterface"
42     _authorized_connections = ["OMFNode" , "OMFChannel"]
43
44     #alias2name = dict({'w0':'wlan0', 'w1':'wlan1'})
45
46     @classmethod
47     def _register_attributes(cls):
48         """Register the attributes of an OMF interface 
49
50         """
51         alias = Attribute("alias","Alias of the interface", default = "w0")
52         mode = Attribute("mode","Mode of the interface")
53         type = Attribute("type","Type of the interface")
54         essid = Attribute("essid","Essid of the interface")
55         ip = Attribute("ip","IP of the interface")
56         cls._register_attribute(alias)
57         cls._register_attribute(mode)
58         cls._register_attribute(type)
59         cls._register_attribute(essid)
60         cls._register_attribute(ip)
61
62     def __init__(self, ec, guid):
63         """
64         :param ec: The Experiment controller
65         :type ec: ExperimentController
66         :param guid: guid of the RM
67         :type guid: int
68         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
69         :type creds: dict
70
71         """
72         super(OMFWifiInterface, self).__init__(ec, guid)
73
74         self._conf = False
75
76         self._omf_api = None
77         self._alias = self.get('alias')
78
79     def valid_connection(self, guid):
80         """ Check if the connection with the guid in parameter is possible. 
81         Only meaningful connections are allowed.
82
83         :param guid: Guid of the current RM
84         :type guid: int
85         :rtype:  Boolean
86
87         """
88         rm = self.ec.get_resource(guid)
89         if rm.get_rtype() in self._authorized_connections:
90             msg = "Connection between %s %s and %s %s accepted" % \
91                 (self.get_rtype(), self._guid, rm.get_rtype(), guid)
92             self.debug(msg)
93
94             return True
95
96         msg = "Connection between %s %s and %s %s refused" % \
97              (self.get_rtype(), self._guid, rm.get_rtype(), guid)
98         self.debug(msg)
99
100         return False
101
102     @property
103     def exp_id(self):
104         return self.ec.exp_id
105
106     @property
107     def node(self):
108         rm_list = self.get_connected(OMFNode.get_rtype())
109         if rm_list: return rm_list[0]
110         return None
111
112     @property
113     def channel(self):
114         rm_list = self.get_connected(OMFChannel.get_rtype())
115         if rm_list: return rm_list[0]
116         return None
117
118     def configure_iface(self):
119         """ Configure the interface without the ip
120
121         """
122         if self.node.state < ResourceState.READY:
123             self.ec.schedule(reschedule_delay, self.deploy)
124             return False
125
126         for attrname in ["mode", "type", "essid"]:
127             attrval = self.get(attrname)
128             attrname = "net/%s/%s" % (self._alias, attrname)
129             self._omf_api.configure(self.node.get('hostname'), attrname, 
130                         attrval)
131         
132         super(OMFWifiInterface, self).do_provision()
133         return True
134
135     def configure_ip(self):
136         """ Configure the ip of the interface
137
138         """
139         if self.channel.state < ResourceState.READY:
140             self.ec.schedule(reschedule_delay, self.deploy)
141             return False
142
143         attrval = self.get("ip")
144         attrname = "net/%s/%s" % (self._alias, "ip")
145         self._omf_api.configure(self.node.get('hostname'), attrname, 
146                     attrval)
147
148         return True
149
150     def do_deploy(self):
151         """ Deploy the RM. It means : Get the xmpp client and send messages 
152         using OMF 5.4 protocol to configure the interface.
153         It becomes DEPLOYED after sending messages to configure the interface
154         """
155         self.set('xmppSlice',self.node.get('xmppSlice'))
156         self.set('xmppHost',self.node.get('xmppHost'))
157         self.set('xmppPort',self.node.get('xmppPort'))
158         self.set('xmppPassword',self.node.get('xmppPassword'))
159
160         if not (self.get('xmppSlice') and self.get('xmppHost')
161               and self.get('xmppPort') and self.get('xmppPassword')):
162             msg = "Credentials are not initialzed. XMPP Connections impossible"
163             self.error(msg)
164             raise RuntimeError, msg
165
166         if not self._omf_api :
167             self._omf_api = OMFAPIFactory.get_api(self.get('xmppSlice'), 
168                 self.get('xmppHost'), self.get('xmppPort'), 
169                 self.get('xmppPassword'), exp_id = self.exp_id)
170
171         if not (self.get('mode') and self.get('type') and self.get('essid') \
172                 and self.get('ip')):
173             msg = "Interface's variable are not initialized"
174             self.error(msg)
175             raise RuntimeError, msg
176
177         if not self.node.get('hostname') :
178             msg = "The channel is connected with an undefined node"
179             self.error(msg)
180             raise RuntimeError, msg
181
182         # Just for information
183         self.info(" " + self.get_rtype() + " ( Guid : " + str(self._guid) +") : " + \
184                 self.get('mode') + " : " + self.get('type') + " : " + \
185                 self.get('essid') + " : " + self.get('ip') + " : " + str(self.state))
186     
187         # Check if the node is already deployed
188         if self.state < ResourceState.PROVISIONED:
189             if self._conf == False:
190                 self._conf = self.configure_iface()
191         res = False
192         if self._conf == True:
193             res = self.configure_ip()
194             
195         if not (res and self._conf):
196             return
197
198         super(OMFWifiInterface, self).do_deploy()
199
200     def do_release(self):
201         """ Clean the RM at the end of the experiment and release the API
202
203         """
204         if self._omf_api:
205             OMFAPIFactory.release_api(self.get('xmppSlice'), 
206                 self.get('xmppHost'), self.get('xmppPort'), 
207                 self.get('xmppPassword'), exp_id = self.exp_id)
208
209         super(OMFWifiInterface, self).do_release()
210