update OMF RM to pass the test. Change status of the rm to fnish after it stops
[nepi.git] / src / nepi / resources / omf / application.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, ResourceState, \
22         reschedule_delay
23 from nepi.execution.attribute import Attribute, Flags 
24 from nepi.resources.omf.omf_resource import ResourceGateway, OMFResource
25 from nepi.resources.omf.node import OMFNode
26 from nepi.resources.omf.omf_api import OMFAPIFactory
27
28
29 @clsinit_copy
30 class OMFApplication(OMFResource):
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)
39         :type creds: dict
40
41     .. note::
42
43        This class is used only by the Experiment Controller through the 
44        Resource Factory
45
46     """
47     _rtype = "OMFApplication"
48     _authorized_connections = ["OMFNode"]
49
50     @classmethod
51     def _register_attributes(cls):
52         """ Register the attributes of an OMF application
53
54         """
55         appid = Attribute("appid", "Name of the application")
56         path = Attribute("path", "Path of the application")
57         args = Attribute("args", "Argument of the application")
58         env = Attribute("env", "Environnement variable of the application")
59         stdin = Attribute("stdin", "Input of the application", default = "")
60         cls._register_attribute(appid)
61         cls._register_attribute(path)
62         cls._register_attribute(args)
63         cls._register_attribute(env)
64         cls._register_attribute(stdin)
65
66     def __init__(self, ec, guid):
67         """
68         :param ec: The Experiment controller
69         :type ec: ExperimentController
70         :param guid: guid of the RM
71         :type guid: int
72         :param creds: Credentials to communicate with the rm (XmppClient for OMF)
73         :type creds: dict
74
75         """
76         super(OMFApplication, self).__init__(ec, guid)
77
78         self.set('appid', "")
79         self.set('path', "")
80         self.set('args', "")
81         self.set('env', "")
82
83         self._node = None
84
85         self._omf_api = None
86
87         self.add_set_hook()
88
89     @property
90     def exp_id(self):
91         return self.ec.exp_id
92
93     @property
94     def node(self):
95         rm_list = self.get_connected(OMFNode.rtype())
96         if rm_list: return rm_list[0]
97         return None
98
99     def stdin_hook(self, old_value, new_value):
100         self._omf_api.send_stdin(self.node.get('hostname'), new_value, self.get('appid'))
101         return new_value
102
103     def add_set_hook(self):
104         attr = self._attrs["stdin"]
105         attr.set_hook = self.stdin_hook
106
107
108     def valid_connection(self, guid):
109         """ Check if the connection with the guid in parameter is possible. 
110         Only meaningful connections are allowed.
111
112         :param guid: Guid of RM it will be connected
113         :type guid: int
114         :rtype:  Boolean
115
116         """
117         rm = self.ec.get_resource(guid)
118         if rm.rtype() not in self._authorized_connections:
119             msg = ("Connection between %s %s and %s %s refused: "
120                     "An Application can be connected only to a Node" ) % \
121                 (self.rtype(), self._guid, rm.rtype(), guid)
122             self.debug(msg)
123
124             return False
125
126         elif len(self.connections) != 0 :
127             msg = ("Connection between %s %s and %s %s refused: "
128                     "This Application is already connected" ) % \
129                 (self.rtype(), self._guid, rm.rtype(), guid)
130             self.debug(msg)
131
132             return False
133
134         else :
135             msg = "Connection between %s %s and %s %s accepted" % (
136                     self.rtype(), self._guid, rm.rtype(), guid)
137             self.debug(msg)
138
139             return True
140
141     def deploy(self):
142         """ Deploy the RM. It means nothing special for an application 
143         for now (later it will be upload sources, ...)
144         It becomes DEPLOYED after getting the xmpp client.
145
146         """
147         if not self._omf_api :
148             self._omf_api = OMFAPIFactory.get_api(self.get('xmppSlice'), 
149                 self.get('xmppHost'), self.get('xmppPort'), 
150                 self.get('xmppPassword'), exp_id = self.exp_id)
151
152         if not self._omf_api :
153             msg = "Credentials are not initialzed. XMPP Connections impossible"
154             self.error(msg)
155             self.fail()
156             return
157
158         super(OMFApplication, self).deploy()
159
160     def start(self):
161         """ Start the RM. It means : Send Xmpp Message Using OMF protocol 
162          to execute the application. 
163          It becomes STARTED before the messages are sent (for coordination)
164
165         """
166         if not (self.get('appid') and self.get('path')) :
167             msg = "Application's information are not initialized"
168             self.error(msg)
169             self.fail()
170             return
171
172         if not self.get('args'):
173             self.set('args', " ")
174         if not self.get('env'):
175             self.set('env', " ")
176
177         # Some information to check the information in parameter
178         msg = " " + self.rtype() + " ( Guid : " + str(self._guid) +") : " + \
179             self.get('appid') + " : " + self.get('path') + " : " + \
180             self.get('args') + " : " + self.get('env')
181         self.info(msg)
182
183         try:
184             self._omf_api.execute(self.node.get('hostname'),self.get('appid'), \
185                 self.get('args'), self.get('path'), self.get('env'))
186         except AttributeError:
187             msg = "Credentials are not initialzed. XMPP Connections impossible"
188             self.error(msg)
189             self.fail()
190             raise
191
192         super(OMFApplication, self).start()
193
194     def stop(self):
195         """ Stop the RM. It means : Send Xmpp Message Using OMF protocol to 
196         kill the application. 
197         State is set to STOPPED after the message is sent.
198
199         """
200         try:
201             self._omf_api.exit(self.node.get('hostname'),self.get('appid'))
202         except AttributeError:
203             msg = "Credentials were not initialzed. XMPP Connections impossible"
204             self.error(msg)
205             self.fail()
206             #raise
207
208         super(OMFApplication, self).stop()
209         self.set_finished()
210
211     def release(self):
212         """ Clean the RM at the end of the experiment and release the API.
213
214         """
215         if self._omf_api :
216             OMFAPIFactory.release_api(self.get('xmppSlice'), 
217                 self.get('xmppHost'), self.get('xmppPort'), 
218                 self.get('xmppPassword'), exp_id = self.exp_id)
219
220         super(OMFApplication, self).release()
221