Code cleanup. Setting resource state through specific functions
[nepi.git] / src / nepi / resources / omf / channel.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.omf_api import OMFAPIFactory
26
27
28 @clsinit
29 class OMFChannel(ResourceManager):
30     """
31     .. class:: Class Args :
32       
33         :param ec: The Experiment controller
34         :type ec: ExperimentController
35         :param guid: guid of the RM
36         :type guid: int
37         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
38         :type creds: dict
39
40     .. note::
41
42        This class is used only by the Experiment Controller through the Resource Factory
43
44     """
45     _rtype = "OMFChannel"
46     _authorized_connections = ["OMFWifiInterface", "OMFNode"]
47
48     @classmethod
49     def _register_attributes(cls):
50         """Register the attributes of an OMF channel
51         
52         """
53         channel = Attribute("channel", "Name of the application")
54         xmppSlice = Attribute("xmppSlice","Name of the slice", flags = Flags.Credential)
55         xmppHost = Attribute("xmppHost", "Xmpp Server",flags = Flags.Credential)
56         xmppPort = Attribute("xmppPort", "Xmpp Port",flags = Flags.Credential)
57         xmppPassword = Attribute("xmppPassword", "Xmpp Port",flags = Flags.Credential)
58         cls._register_attribute(channel)
59         cls._register_attribute(xmppSlice)
60         cls._register_attribute(xmppHost)
61         cls._register_attribute(xmppPort)
62         cls._register_attribute(xmppPassword)
63
64     def __init__(self, ec, guid):
65         """
66         :param ec: The Experiment controller
67         :type ec: ExperimentController
68         :param guid: guid of the RM
69         :type guid: int
70         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
71         :type creds: dict
72
73         """
74         super(OMFChannel, self).__init__(ec, guid)
75
76         self._nodes_guid = list()
77
78         self._omf_api = None
79
80     @property
81     def exp_id(self):
82         if self.ec.exp_id.startswith('exp-'):
83             return None
84         return self.ec.exp_id
85
86     def valid_connection(self, guid):
87         """ Check if the connection with the guid in parameter is possible.
88         Only meaningful connections are allowed.
89
90         :param guid: Guid of the current RM
91         :type guid: int
92         :rtype:  Boolean
93
94         """
95         rm = self.ec.get_resource(guid)
96         
97         if rm.rtype() in self._authorized_connections:
98             msg = "Connection between %s %s and %s %s accepted" % (
99                     self.rtype(), self._guid, rm.rtype(), guid)
100             self.debug(msg)
101             return True
102
103         msg = "Connection between %s %s and %s %s refused" % (
104                 self.rtype(), self._guid, rm.rtype(), guid)
105         self.debug(msg)
106         
107         return False
108
109     def _get_target(self, conn_set):
110         """
111         Get the couples (host, interface) that uses this channel
112
113         :param conn_set: Connections of the current Guid
114         :type conn_set: set
115         :rtype: list
116         :return: self._nodes_guid
117
118         """
119         res = []
120         for elt in conn_set:
121             rm_iface = self.ec.get_resource(elt)
122             for conn in rm_iface.connections:
123                 rm_node = self.ec.get_resource(conn)
124                 if rm_node.rtype() == "OMFNode" and rm_node.get('hostname'):
125                     if rm_iface.state < ResourceState.PROVISIONED or \
126                             rm_node.state < ResourceState.READY:
127                         return "reschedule"
128                     couple = [rm_node.get('hostname'), rm_iface.get('alias')]
129                     #print couple
130                     res.append(couple)
131         return res
132
133     def discover(self):
134         """ Discover the availables channels
135
136         """
137         pass
138      
139     def provision(self):
140         """ Provision some availables channels
141
142         """
143         pass
144
145     def deploy(self):
146         """ Deploy the RM. It means : Get the xmpp client and send messages 
147         using OMF 5.4 protocol to configure the channel.
148         It becomes DEPLOYED after sending messages to configure the channel
149
150         """
151         if not self._omf_api :
152             self._omf_api = OMFAPIFactory.get_api(self.get('xmppSlice'), 
153                 self.get('xmppHost'), self.get('xmppPort'), 
154                 self.get('xmppPassword'), exp_id = self.exp_id)
155
156         if not self._omf_api :
157             msg = "Credentials are not initialzed. XMPP Connections impossible"
158             self.error(msg)
159             self.fail()
160             return
161
162         if not self.get('channel'):
163             msg = "Channel's value is not initialized"
164             self.error(msg)
165             self.fail()
166             raise
167
168         self._nodes_guid = self._get_target(self._connections) 
169         if self._nodes_guid == "reschedule" :
170             self.ec.schedule("2s", self.deploy)
171             return False
172
173         try:
174             for couple in self._nodes_guid:
175                 #print "Couple node/alias : " + couple[0] + "  ,  " + couple[1]
176                 attrval = self.get('channel')
177                 attrname = "net/%s/%s" % (couple[1], 'channel')
178                 self._omf_api.configure(couple[0], attrname, attrval)
179         except AttributeError:
180             msg = "Credentials are not initialzed. XMPP Connections impossible"
181             self.error(msg)
182             self.fail()
183             raise
184
185         super(OMFChannel, self).deploy()
186
187     def start(self):
188         """ Start the RM. It means nothing special for a channel for now
189         It becomes STARTED as soon as this method starts.
190
191         """
192
193         super(OMFChannel, self).start()
194
195     def stop(self):
196         """ Stop the RM. It means nothing special for a channel for now
197         It becomes STOPPED as soon as this method is called
198
199         """
200         super(OMFChannel, self).stop()
201
202     def release(self):
203         """ Clean the RM at the end of the experiment and release the API
204
205         """
206         if self._omf_api :
207             OMFAPIFactory.release_api(self.get('xmppSlice'), 
208                 self.get('xmppHost'), self.get('xmppPort'), 
209                 self.get('xmppPassword'), exp_id = self.exp_id)
210
211         super(OMFChannel, self).release()
212