Salome HOME
Initial import: adding files
[tools/libbatch.git] / src / LSF / Batch_BatchManager_eLSF.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 /*
23  * BatchManager_eLSF.cxx : emulation of LSF client
24  *
25  * Auteur : Bernard SECHER - CEA DEN
26  * Mail   : mailto:bernard.secher@cea.fr
27  * Date   : Thu Apr 24 10:17:22 2008
28  * Projet : PAL Salome
29  *
30  */
31
32 #include <iostream>
33 #include <fstream>
34 #include <sstream>
35 #include <sys/stat.h>
36 #include <string.h>
37 #include <stdlib.h>
38
39 #include "Batch_BatchManager_eLSF.hxx"
40 #ifdef WIN32
41 # include <time.h>
42 # include <io.h>
43 #else
44 # include <libgen.h>
45 #endif
46
47 using namespace std;
48
49 namespace Batch {
50
51   BatchManager_eLSF::BatchManager_eLSF(const FactBatchManager * parent, const char * host, const char * protocol, const char * mpiImpl) throw(InvalidArgumentException,ConnexionFailureException) : BatchManager_eClient(parent,host,protocol,mpiImpl)
52   {
53     // Nothing to do
54   }
55
56   // Destructeur
57   BatchManager_eLSF::~BatchManager_eLSF()
58   {
59     // Nothing to do
60   }
61
62   // Methode pour le controle des jobs : soumet un job au gestionnaire
63   const JobId BatchManager_eLSF::submitJob(const Job & job)
64   {
65     int status;
66     Parametre params = job.getParametre();
67     const std::string dirForTmpFiles = params[TMPDIR];
68     const string fileToExecute = params[EXECUTABLE];
69     std::string fileNameToExecute;
70     if( fileToExecute.size() > 0 ){
71       string::size_type p1 = fileToExecute.find_last_of("/");
72       string::size_type p2 = fileToExecute.find_last_of(".");
73       fileNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
74     }
75     else
76       fileNameToExecute = "command";
77
78     // export input files on cluster
79     exportInputFiles(job);
80
81     // build batch script for job
82     buildBatchScript(job);
83
84     // define name of log file
85     string logFile="/tmp/logs/";
86     logFile += getenv("USER");
87     logFile += "/batchSalome_";
88     srand ( time(NULL) );
89     int ir = rand();
90     ostringstream oss;
91     oss << ir;
92     logFile += oss.str();
93     logFile += ".log";
94
95     string command;
96
97     // define command to submit batch
98     command = _protocol;
99     command += " ";
100
101     if(_username != ""){
102       command += _username;
103       command += "@";
104     }
105
106     command += _hostname;
107     command += " \"cd " ;
108     command += dirForTmpFiles ;
109     command += "; bsub < " ;
110     command += fileNameToExecute ;
111     command += "_Batch.sh\" > ";
112     command += logFile;
113     cerr << command.c_str() << endl;
114     status = system(command.c_str());
115     if(status)
116       throw EmulationException("Error of connection on remote host");
117
118     // read id of submitted job in log file
119     char line[128];
120     FILE *fp = fopen(logFile.c_str(),"r");
121     fgets( line, 128, fp);
122     fclose(fp);
123
124     string sline(line);
125     int p10 = sline.find("<");
126     int p20 = sline.find(">");
127     string strjob = sline.substr(p10+1,p20-p10-1);
128
129     JobId id(this, strjob);
130     return id;
131   }
132
133   // Methode pour le controle des jobs : retire un job du gestionnaire
134   void BatchManager_eLSF::deleteJob(const JobId & jobid)
135   {
136     int status;
137     int ref;
138     istringstream iss(jobid.getReference());
139     iss >> ref;
140
141     // define command to submit batch
142     string command;
143     command = _protocol;
144     command += " ";
145
146     if (_username != ""){
147       command += _username;
148       command += "@";
149     }
150
151     command += _hostname;
152     command += " \"bkill " ;
153     command += iss.str();
154     command += "\"";
155     cerr << command.c_str() << endl;
156     status = system(command.c_str());
157     if(status)
158       throw EmulationException("Error of connection on remote host");
159
160     cerr << "jobId = " << ref << "killed" << endl;
161   }
162
163   // Methode pour le controle des jobs : suspend un job en file d'attente
164   void BatchManager_eLSF::holdJob(const JobId & jobid)
165   {
166     throw EmulationException("Not yet implemented");
167   }
168
169   // Methode pour le controle des jobs : relache un job suspendu
170   void BatchManager_eLSF::releaseJob(const JobId & jobid)
171   {
172     throw EmulationException("Not yet implemented");
173   }
174
175
176   // Methode pour le controle des jobs : modifie un job en file d'attente
177   void BatchManager_eLSF::alterJob(const JobId & jobid, const Parametre & param, const Environnement & env)
178   {
179     throw EmulationException("Not yet implemented");
180   }
181
182   // Methode pour le controle des jobs : modifie un job en file d'attente
183   void BatchManager_eLSF::alterJob(const JobId & jobid, const Parametre & param)
184   {
185     alterJob(jobid, param, Environnement());
186   }
187
188   // Methode pour le controle des jobs : modifie un job en file d'attente
189   void BatchManager_eLSF::alterJob(const JobId & jobid, const Environnement & env)
190   {
191     alterJob(jobid, Parametre(), env);
192   }
193
194   // Methode pour le controle des jobs : renvoie l'etat du job
195   JobInfo BatchManager_eLSF::queryJob(const JobId & jobid)
196   {
197     int id;
198     istringstream iss(jobid.getReference());
199     iss >> id;
200
201     // define name of log file
202     string logFile="/tmp/logs/";
203     logFile += getenv("USER");
204     logFile += "/batchSalome_";
205
206     srand ( time(NULL) );
207     int ir = rand();
208     ostringstream oss;
209     oss << ir;
210     logFile += oss.str();
211     logFile += ".log";
212
213     string command;
214     int status;
215
216     // define command to submit batch
217     command = _protocol;
218     command += " ";
219
220     if (_username != ""){
221       command += _username;
222       command += "@";
223     }
224
225     command += _hostname;
226     command += " \"bjobs " ;
227     command += iss.str();
228     command += "\" > ";
229     command += logFile;
230     cerr << command.c_str() << endl;
231     status = system(command.c_str());
232     if(status)
233       throw EmulationException("Error of connection on remote host");
234
235     JobInfo_eLSF ji = JobInfo_eLSF(id,logFile);
236     return ji;
237   }
238
239
240
241   // Methode pour le controle des jobs : teste si un job est present en machine
242   bool BatchManager_eLSF::isRunning(const JobId & jobid)
243   {
244     throw EmulationException("Not yet implemented");
245   }
246
247   void BatchManager_eLSF::buildBatchScript(const Job & job)
248   {
249 #ifndef WIN32 //TODO: need for porting on Windows
250     int status;
251     Parametre params = job.getParametre();
252     Environnement env = job.getEnvironnement();
253     const int nbproc = params[NBPROC];
254     const long edt = params[MAXWALLTIME];
255     const long mem = params[MAXRAMSIZE];
256     const string workDir = params[WORKDIR];
257     const std::string dirForTmpFiles = params[TMPDIR];
258     const string fileToExecute = params[EXECUTABLE];
259     const string home = params[HOMEDIR];
260     const std::string queue = params[QUEUE];
261     std::string rootNameToExecute;
262     std::string fileNameToExecute;
263     std::string filelogtemp;
264     if( fileToExecute.size() > 0 ){
265       string::size_type p1 = fileToExecute.find_last_of("/");
266       string::size_type p2 = fileToExecute.find_last_of(".");
267       rootNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
268       char* basec=strdup(fileToExecute.c_str());
269       fileNameToExecute = "~/" + dirForTmpFiles + "/" + string(basename(basec));
270       free(basec);
271
272       int idx = dirForTmpFiles.find("Batch/");
273       filelogtemp = dirForTmpFiles.substr(idx+6, dirForTmpFiles.length());
274     }
275     else{
276       rootNameToExecute = "command";
277     }
278
279     ofstream tempOutputFile;
280     std::string TmpFileName = createAndOpenTemporaryFile(tempOutputFile);
281
282     tempOutputFile << "#! /bin/sh -f" << endl ;
283     if (queue != "")
284       tempOutputFile << "#BSUB -q " << queue << endl;
285     if( edt > 0 )
286       tempOutputFile << "#BSUB -W " << getWallTime(edt) << endl ;
287     if( mem > 0 )
288       tempOutputFile << "#BSUB -M " << mem*1024 << endl ;
289     tempOutputFile << "#BSUB -n " << nbproc << endl ;
290     if( fileToExecute.size() > 0 ){
291       tempOutputFile << "#BSUB -o " << home << "/" << dirForTmpFiles << "/output.log." << filelogtemp << endl ;
292       tempOutputFile << "#BSUB -e " << home << "/" << dirForTmpFiles << "/error.log." << filelogtemp << endl ;
293     }
294     else{
295       tempOutputFile << "#BSUB -o " << dirForTmpFiles << "/" << env["LOGFILE"] << ".output.log" << endl ;
296       tempOutputFile << "#BSUB -e " << dirForTmpFiles << "/" << env["LOGFILE"] << ".error.log" << endl ;
297     }
298     if( workDir.size() > 0 )
299       tempOutputFile << "cd " << workDir << endl ;
300     if( fileToExecute.size() > 0 ){
301       tempOutputFile << _mpiImpl->boot("",nbproc);
302       tempOutputFile << _mpiImpl->run("",nbproc,fileNameToExecute);
303       tempOutputFile << _mpiImpl->halt();
304     }
305     else{
306       tempOutputFile << "source " << env["SOURCEFILE"] << endl ;
307       tempOutputFile << env["COMMAND"];
308     }
309
310     tempOutputFile.flush();
311     tempOutputFile.close();
312 #ifdef WIN32
313     _chmod(
314 #else
315     chmod(
316 #endif
317       TmpFileName.c_str(), 0x1ED);
318     cerr << TmpFileName.c_str() << endl;
319
320     string command;
321     if( _protocol == "rsh" )
322       command = "rcp ";
323     else if( _protocol == "ssh" )
324       command = "scp ";
325     else
326       throw EmulationException("Unknown protocol");
327     command += TmpFileName;
328     command += " ";
329     if(_username != ""){
330       command +=  _username;
331       command += "@";
332     }
333     command += _hostname;
334     command += ":";
335     command += dirForTmpFiles ;
336     command += "/" ;
337     command += rootNameToExecute ;
338     command += "_Batch.sh" ;
339     cerr << command.c_str() << endl;
340     status = system(command.c_str());
341     if(status)
342       throw EmulationException("Error of connection on remote host");
343
344     remove(TmpFileName.c_str());
345 #endif
346
347   }
348
349   std::string BatchManager_eLSF::getWallTime(const long edt)
350   {
351     long h, m;
352     h = edt / 60;
353     m = edt - h*60;
354     ostringstream oss;
355     if( m >= 10 )
356       oss << h << ":" << m;
357     else
358       oss << h << ":0" << m;
359     return oss.str();
360   }
361
362 }