Salome HOME
CCAR: remove bug in FindOrLoad_Component
[modules/kernel.git] / src / Batch / Batch_BatchManager_ePBS.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_ePBS.cxx : emulation of PBS 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_ePBS.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_ePBS::BatchManager_ePBS(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_ePBS::~BatchManager_ePBS()
58   {
59     // Nothing to do
60   }
61
62   // Methode pour le controle des jobs : soumet un job au gestionnaire
63   const JobId BatchManager_ePBS::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     string::size_type p1 = fileToExecute.find_last_of("/");
70     string::size_type p2 = fileToExecute.find_last_of(".");
71     std::string fileNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
72
73     // export input files on cluster
74     exportInputFiles(job);
75
76     // build batch script for job
77     buildBatchScript(job);
78
79     // define name of log file
80     string logFile="/tmp/logs/";
81     logFile += getenv("USER");
82     logFile += "/batchSalome_";
83     srand ( time(NULL) );
84     int ir = rand();
85     ostringstream oss;
86     oss << ir;
87     logFile += oss.str();
88     logFile += ".log";
89
90     string command;
91
92     // define command to submit batch
93     command = _protocol;
94     command += " ";
95
96     if(_username != ""){
97       command += _username;
98       command += "@";
99     }
100
101     command += _hostname;
102     command += " \"cd " ;
103     command += dirForTmpFiles ;
104     command += "; qsub " ;
105     command += fileNameToExecute ;
106     command += "_Batch.sh\" > ";
107     command += logFile;
108     cerr << command.c_str() << endl;
109     status = system(command.c_str());
110     if(status)
111       throw EmulationException("Error of connection on remote host");
112
113     // read id of submitted job in log file
114     char line[128];
115     FILE *fp = fopen(logFile.c_str(),"r");
116     fgets( line, 128, fp);
117     fclose(fp);
118     
119     string sline(line);
120     int pos = sline.find(".");
121     string strjob;
122     if(pos == string::npos)
123       strjob = sline;
124     else
125       strjob = sline.substr(0,pos);
126
127     JobId id(this, strjob);
128     return id;
129   }
130
131   // Methode pour le controle des jobs : retire un job du gestionnaire
132   void BatchManager_ePBS::deleteJob(const JobId & jobid)
133   {
134     int status;
135     int ref;
136     istringstream iss(jobid.getReference());
137     iss >> ref;
138     
139     // define command to submit batch
140     string command;
141     command = _protocol;
142     command += " ";
143
144     if (_username != ""){
145       command += _username;
146       command += "@";
147     }
148
149     command += _hostname;
150     command += " \"qdel " ;
151     command += iss.str();
152     command += "\"";
153     cerr << command.c_str() << endl;
154     status = system(command.c_str());
155     if(status)
156       throw EmulationException("Error of connection on remote host");
157
158     cerr << "jobId = " << ref << "killed" << endl;
159   }
160    
161   // Methode pour le controle des jobs : suspend un job en file d'attente
162   void BatchManager_ePBS::holdJob(const JobId & jobid)
163   {
164     throw EmulationException("Not yet implemented");
165   }
166
167   // Methode pour le controle des jobs : relache un job suspendu
168   void BatchManager_ePBS::releaseJob(const JobId & jobid)
169   {
170     throw EmulationException("Not yet implemented");
171   }
172
173
174   // Methode pour le controle des jobs : modifie un job en file d'attente
175   void BatchManager_ePBS::alterJob(const JobId & jobid, const Parametre & param, const Environnement & env)
176   {
177     throw EmulationException("Not yet implemented");
178   }
179
180   // Methode pour le controle des jobs : modifie un job en file d'attente
181   void BatchManager_ePBS::alterJob(const JobId & jobid, const Parametre & param)
182   {
183     alterJob(jobid, param, Environnement());
184   }
185
186   // Methode pour le controle des jobs : modifie un job en file d'attente
187   void BatchManager_ePBS::alterJob(const JobId & jobid, const Environnement & env)
188   {
189     alterJob(jobid, Parametre(), env);
190   }
191
192   // Methode pour le controle des jobs : renvoie l'etat du job
193   JobInfo BatchManager_ePBS::queryJob(const JobId & jobid)
194   {
195     int id;
196     istringstream iss(jobid.getReference());
197     iss >> id;
198
199     // define name of log file
200     string logFile="/tmp/logs/";
201     logFile += getenv("USER");
202     logFile += "/batchSalome_";
203
204     ostringstream oss;
205     oss << this << "_" << id;
206     logFile += oss.str();
207     logFile += ".log";
208
209     string command;
210     int status;
211
212     // define command to submit batch
213     command = _protocol;
214     command += " ";
215
216     if (_username != ""){
217       command += _username;
218       command += "@";
219     }
220
221     command += _hostname;
222     command += " \"qstat -f " ;
223     command += iss.str();
224     command += "\" > ";
225     command += logFile;
226     cerr << command.c_str() << endl;
227     status = system(command.c_str());
228     if(status && status != 153 && status != 256*153)
229       throw EmulationException("Error of connection on remote host");
230
231     JobInfo_ePBS ji = JobInfo_ePBS(id,logFile);
232     return ji;
233   }
234
235   // Methode pour le controle des jobs : teste si un job est present en machine
236   bool BatchManager_ePBS::isRunning(const JobId & jobid)
237   {
238     throw EmulationException("Not yet implemented");
239   }
240
241   void BatchManager_ePBS::buildBatchScript(const Job & job) throw(EmulationException)
242   {
243 #ifndef WIN32 //TODO: need for porting on Windows
244     int status;
245     Parametre params = job.getParametre();
246     Environnement env = job.getEnvironnement();
247     const long nbproc = params[NBPROC];
248     const long edt = params[MAXWALLTIME];
249     const long mem = params[MAXRAMSIZE];
250     const string workDir = params[WORKDIR];
251     const std::string dirForTmpFiles = params[TMPDIR];
252     const string fileToExecute = params[EXECUTABLE];
253     const string home = params[HOMEDIR];
254     const std::string queue = params[QUEUE];
255     std::string rootNameToExecute;
256     std::string fileNameToExecute;
257     std::string filelogtemp;
258     if( fileToExecute.size() > 0 ){
259       string::size_type p1 = fileToExecute.find_last_of("/");
260       string::size_type p2 = fileToExecute.find_last_of(".");
261       rootNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
262       char* basec=strdup(fileToExecute.c_str());
263       fileNameToExecute = "~/" + dirForTmpFiles + "/" + string(basename(basec));
264       free(basec);
265
266       int idx = dirForTmpFiles.find("Batch/");
267       filelogtemp = dirForTmpFiles.substr(idx+6, dirForTmpFiles.length());
268     }
269     else{
270       rootNameToExecute = "command";
271     }
272
273     std::string TmpFileName = BuildTemporaryFileName();
274     ofstream tempOutputFile;
275     tempOutputFile.open(TmpFileName.c_str(), ofstream::out );
276
277     tempOutputFile << "#! /bin/sh -f" << endl;
278     if (queue != "")
279       tempOutputFile << "#BSUB -q " << queue << endl;
280     if( edt > 0 )
281       tempOutputFile << "#PBS -l walltime=" << edt*60 << endl ;
282     if( mem > 0 )
283       tempOutputFile << "#PBS -l mem=" << mem << "mb" << endl ;
284     if( fileToExecute.size() > 0 ){
285       tempOutputFile << "#PBS -o " << home << "/" << dirForTmpFiles << "/output.log." << filelogtemp << endl ;
286       tempOutputFile << "#PBS -e " << home << "/" << dirForTmpFiles << "/error.log." << filelogtemp << endl ;
287     }
288     else{
289       tempOutputFile << "#PBS -o " << dirForTmpFiles << "/" << env["LOGFILE"] << ".output.log" << endl ;
290       tempOutputFile << "#PBS -e " << dirForTmpFiles << "/" << env["LOGFILE"] << ".error.log" << endl ;
291     }
292     if( workDir.size() > 0 )
293       tempOutputFile << "cd " << workDir << endl ;
294     if( fileToExecute.size() > 0 ){
295       tempOutputFile << _mpiImpl->boot("${PBS_NODEFILE}",nbproc);
296       tempOutputFile << _mpiImpl->run("${PBS_NODEFILE}",nbproc,fileNameToExecute);
297       tempOutputFile << _mpiImpl->halt();
298     }
299     else{
300       tempOutputFile << "source " << env["SOURCEFILE"] << endl ;
301       tempOutputFile << env["COMMAND"];
302     }
303       
304     tempOutputFile.flush();
305     tempOutputFile.close();
306 #ifdef WIN32
307     _chmod(
308 #else
309     chmod(
310 #endif
311       TmpFileName.c_str(), 0x1ED);
312     cerr << TmpFileName.c_str() << endl;
313
314     string command;
315     if( _protocol == "rsh" )
316       command = "rcp ";
317     else if( _protocol == "ssh" )
318       command = "scp ";
319     else
320       throw EmulationException("Unknown protocol");
321     command += TmpFileName;
322     command += " ";
323     if(_username != ""){
324       command +=  _username;
325       command += "@";
326     }
327     command += _hostname;
328     command += ":";
329     command += dirForTmpFiles ;
330     command += "/" ;
331     command += rootNameToExecute ;
332     command += "_Batch.sh" ;
333     cerr << command.c_str() << endl;
334     status = system(command.c_str());
335     if(status)
336       throw EmulationException("Error of connection on remote host");    
337
338     RmTmpFile(TmpFileName);
339 #endif    
340   }
341
342 }