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