update OMF 6 and test it. It works once but not twice
[nepi.git] / src / nepi / resources / omf / application6.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.omf6_resource import OMF6Resource
25 from nepi.resources.omf.node6 import OMF6Node
26 from nepi.resources.omf.omf6_api import OMF6APIFactory
27
28 import os, time
29 from nepi.util import sshfuncs
30
31 @clsinit_copy
32 class OMF6Application(OMF6Resource):
33     """
34     .. class:: Class Args :
35       
36         :param ec: The Experiment controller
37         :type ec: ExperimentController
38         :param guid: guid of the RM
39         :type guid: int
40
41     """
42     _rtype = "OMF6Application"
43     _authorized_connections = ["OMF6Node"]
44
45     @classmethod
46     def _register_attributes(cls):
47         """ Register the attributes of an OMF application
48
49         """
50         command = Attribute("command", "Command to execute")
51         env = Attribute("env", "Environnement variable of the application")
52 #        sources = Attribute("sources", "Sources of the application", 
53 #                     flags = Flags.ExecReadOnly)
54 #        sshuser = Attribute("sshUser", "user to connect with ssh", 
55 #                     flags = Flags.ExecReadOnly)
56 #        sshkey = Attribute("sshKey", "key to use for ssh", 
57 #                     flags = Flags.ExecReadOnly)
58         cls._register_attribute(command)
59         cls._register_attribute(env)
60 #        cls._register_attribute(sources)
61 #        cls._register_attribute(sshuser)
62 #        cls._register_attribute(sshkey)
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(OMF6Application, self).__init__(ec, guid)
75
76         self.set('command', "")
77         self.set('env', "")
78
79         self._node = None
80         self._topic_app = None
81
82         self._omf_api = None
83
84     @property
85     def exp_id(self):
86         return self.ec.exp_id
87
88     @property
89     def node(self):
90         rm_list = self.get_connected(OMF6Node.get_rtype())
91         if rm_list: return rm_list[0]
92         return None
93
94     def valid_connection(self, guid):
95         """ Check if the connection with the guid in parameter is possible. 
96         Only meaningful connections are allowed.
97
98         :param guid: Guid of RM it will be connected
99         :type guid: int
100         :rtype:  Boolean
101
102         """
103         rm = self.ec.get_resource(guid)
104         if rm.get_rtype() not in self._authorized_connections:
105             msg = ("Connection between %s %s and %s %s refused: "
106                     "An Application can be connected only to a Node" ) % \
107                 (self.get_rtype(), self._guid, rm.get_rtype(), guid)
108             self.debug(msg)
109
110             return False
111
112         elif len(self.connections) != 0 :
113             msg = ("Connection between %s %s and %s %s refused: "
114                     "This Application is already connected" ) % \
115                 (self.get_rtype(), self._guid, rm.get_rtype(), guid)
116             self.debug(msg)
117
118             return False
119
120         else :
121             msg = "Connection between %s %s and %s %s accepted" % (
122                     self.get_rtype(), self._guid, rm.get_rtype(), guid)
123             self.debug(msg)
124
125             return True
126
127     def do_deploy(self):
128         """ Deploy the RM. It means nothing special for an application 
129         for now (later it will be upload sources, ...)
130         It becomes DEPLOYED after getting the xmpp client.
131
132         """
133
134         self.set('xmppUser',self.node.get('xmppUser'))
135         self.set('xmppHost',self.node.get('xmppHost'))
136         self.set('xmppPort',self.node.get('xmppPort'))
137         self.set('xmppPassword',self.node.get('xmppPassword'))
138
139         if not (self.get('xmppUser') and self.get('xmppHost')
140               and self.get('xmppPort') and self.get('xmppPassword')):
141             msg = "Credentials are not initialzed. XMPP Connections impossible"
142             self.error(msg)
143             raise RuntimeError, msg
144
145         if not self._omf_api :
146             self._omf_api = OMF6APIFactory.get_api(self.get('xmppHost'), 
147                 self.get('xmppUser'), self.get('xmppPort'), 
148                 self.get('xmppPassword'), exp_id = self.exp_id)
149
150 #        if self.get('sources'):
151 #            gateway = ResourceGateway.AMtoGateway[self.get('xmppHost')]
152 #            user = self.get('sshUser') or self.get('xmppSlice')
153 #            dst = user + "@"+ gateway + ":"
154 #            (out, err), proc = sshfuncs.rcopy(self.get('sources'), dst)
155          
156         self._topic_app = self.node.get('hostname') +'_'+ str(self.guid) +'_app'
157
158         self._omf_api.enroll_topic(self._topic_app)
159
160         props = {}
161         if self.get('command'):
162             props['application:binary_path'] = self.get('command')
163             props['application:hrn'] = self.get('command')
164             props['application:membership'] = self._topic_app
165         props['application:type'] = "application"
166         self._omf_api.frcp_create( self.node.get('hostname'), "application", props = props)
167
168
169
170         super(OMF6Application, self).do_deploy()
171
172     def do_start(self):
173         """ Start the RM. It means : Send Xmpp Message Using OMF protocol 
174          to execute the application. 
175          It becomes STARTED before the messages are sent (for coordination)
176
177         """
178         if not self.get('command') :
179             msg = "Application's Command is not initialized"
180             self.error(msg)
181             raise RuntimeError, msg
182
183         if not self.get('env'):
184             self.set('env', " ")
185
186         props = {}
187         props['state'] = "running"
188
189         guards = {}
190         guards['type'] = "application"
191         guards['name'] = self.get('command')
192         time.sleep(2)
193         self._omf_api.frcp_configure(self._topic_app, props = props, guards = guards )
194
195
196         super(OMF6Application, self).do_start()
197
198     def do_stop(self):
199         """ Stop the RM. It means : Send Xmpp Message Using OMF protocol to 
200         kill the application. 
201         State is set to STOPPED after the message is sent.
202
203         """
204
205         super(OMF6Application, self).do_stop()
206
207     def do_release(self):
208         """ Clean the RM at the end of the experiment and release the API.
209
210         """
211         props = {}
212         props['frcp:type'] = "application"
213
214         self._omf_api.frcp_release(self.node.get('hostname'),self._topic_app, props = props )
215
216         if self._omf_api:
217             OMF6APIFactory.release_api(self.get('xmppHost'), 
218                 self.get('xmppUser'), self.get('xmppPort'), 
219                 self.get('xmppPassword'), exp_id = self.exp_id)
220
221         super(OMF6Application, self).do_release()
222