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