Salome HOME
Added possibility to add specific parameters in the client classes. Added parameter...
[tools/libbatch.git] / src / PBS / Batch_BatchManager_ePBS.cxx
1 //  Copyright (C) 2007-2010  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, AndrĂ© RIBES - EDF R&D
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 <stdlib.h>
33 #include <string.h>
34
35 #include <iostream>
36 #include <fstream>
37 #include <sstream>
38 #include <sys/stat.h>
39
40 #include <stdlib.h>
41 #include <string.h>
42 #include <Batch_config.h>
43
44 #ifdef MSVC
45 #include <io.h>
46 #else
47 #include <libgen.h>
48 #endif
49
50 #include "Batch_Constants.hxx"
51 #include "Batch_BatchManager_ePBS.hxx"
52 #include "Batch_JobInfo_ePBS.hxx"
53
54 using namespace std;
55
56 namespace Batch {
57
58   BatchManager_ePBS::BatchManager_ePBS(const FactBatchManager * parent, const char * host,
59                                        const char * username,
60                                        CommunicationProtocolType protocolType, const char * mpiImpl, 
61                                        int nb_proc_per_node)
62     : BatchManager(parent, host),
63       BatchManager_eClient(parent, host, username, protocolType, mpiImpl)
64   {
65     // Nothing to do
66     _nb_proc_per_node = nb_proc_per_node;
67   }
68
69   // Destructeur
70   BatchManager_ePBS::~BatchManager_ePBS()
71   {
72     // Nothing to do
73   }
74
75   // Methode pour le controle des jobs : soumet un job au gestionnaire
76   const JobId BatchManager_ePBS::submitJob(const Job & job)
77   {
78     int status;
79     Parametre params = job.getParametre();
80     const std::string workDir = params[WORKDIR];
81     const string fileToExecute = params[EXECUTABLE];
82     string::size_type p1 = fileToExecute.find_last_of("/");
83     string::size_type p2 = fileToExecute.find_last_of(".");
84     std::string fileNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
85
86     // export input files on cluster
87     exportInputFiles(job);
88
89     // build batch script for job
90     buildBatchScript(job);
91
92     // define name of log file (local)
93     string logFile = generateTemporaryFileName("PBS-submitlog");
94
95     // define command to submit batch
96     string subCommand = string("cd ") + workDir + "; qsub " + fileNameToExecute + "_Batch.sh";
97     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
98     command += " > ";
99     command += logFile;
100     command += " 2>&1";
101     cerr << command.c_str() << endl;
102     status = system(command.c_str());
103     if(status)
104     {
105       ifstream error_message(logFile.c_str());
106       std::string mess;
107       std::string temp;
108       while(std::getline(error_message, temp))
109         mess += temp;
110       error_message.close();
111       throw EmulationException("Error of connection on remote host, error was: " + mess);
112     }
113
114     // read id of submitted job in log file
115     ifstream idfile(logFile.c_str());
116     string sline;
117     idfile >> sline;
118     idfile.close();
119     if (sline.size() == 0)
120       throw EmulationException("Error in the submission of the job on the remote host");
121
122     JobId id(this, sline);
123     return id;
124   }
125
126   // Ce manager permet de faire de la reprise
127   const Batch::JobId
128   BatchManager_ePBS::addJob(const Batch::Job & job, const std::string reference)
129   {
130     return JobId(this, reference);
131   }
132
133   // Methode pour le controle des jobs : retire un job du gestionnaire
134   void BatchManager_ePBS::deleteJob(const JobId & jobid)
135   {
136     int status;
137     int ref;
138     istringstream iss(jobid.getReference());
139     iss >> ref;
140
141     // define command to delete batch
142     string subCommand = string("qdel ") + iss.str();
143     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
144     cerr << command.c_str() << endl;
145     status = system(command.c_str());
146     if (status)
147       throw EmulationException("Error of connection on remote host");
148
149     cerr << "jobId = " << ref << "killed" << endl;
150   }
151
152   // Methode pour le controle des jobs : suspend un job en file d'attente
153   void BatchManager_ePBS::holdJob(const JobId & jobid)
154   {
155     throw EmulationException("Not yet implemented");
156   }
157
158   // Methode pour le controle des jobs : relache un job suspendu
159   void BatchManager_ePBS::releaseJob(const JobId & jobid)
160   {
161     throw EmulationException("Not yet implemented");
162   }
163
164
165   // Methode pour le controle des jobs : modifie un job en file d'attente
166   void BatchManager_ePBS::alterJob(const JobId & jobid, const Parametre & param, const Environnement & env)
167   {
168     throw EmulationException("Not yet implemented");
169   }
170
171   // Methode pour le controle des jobs : modifie un job en file d'attente
172   void BatchManager_ePBS::alterJob(const JobId & jobid, const Parametre & param)
173   {
174     alterJob(jobid, param, Environnement());
175   }
176
177   // Methode pour le controle des jobs : modifie un job en file d'attente
178   void BatchManager_ePBS::alterJob(const JobId & jobid, const Environnement & env)
179   {
180     alterJob(jobid, Parametre(), env);
181   }
182
183   // Methode pour le controle des jobs : renvoie l'etat du job
184   JobInfo BatchManager_ePBS::queryJob(const JobId & jobid)
185   {
186     int id;
187     istringstream iss(jobid.getReference());
188     iss >> id;
189
190     // define name of log file (local)
191     string logFile = generateTemporaryFileName(string("PBS-querylog-id") + jobid.getReference());
192
193     // define command to query batch
194     string subCommand = string("qstat -f ") + iss.str();
195     string command = _protocol.getExecCommand(subCommand, _hostname, _username);
196     command += " > ";
197     command += logFile;
198     cerr << command.c_str() << endl;
199     int status = system(command.c_str());
200     if(status && status != 153 && status != 256*153)
201       throw EmulationException("Error of connection on remote host");
202
203     JobInfo_ePBS ji = JobInfo_ePBS(id,logFile);
204     return ji;
205   }
206
207   // Methode pour le controle des jobs : teste si un job est present en machine
208   bool BatchManager_ePBS::isRunning(const JobId & jobid)
209   {
210     throw EmulationException("Not yet implemented");
211   }
212
213   void BatchManager_ePBS::buildBatchScript(const Job & job)
214   {
215     std::cerr << "BuildBatchScript" << std::endl;
216     Parametre params = job.getParametre();
217     Environnement env = job.getEnvironnement();
218
219     // Job Parameters
220     string workDir       = "";
221     string fileToExecute = "";
222     int nbproc           = 0;
223     int edt              = 0;
224     int mem              = 0;
225     string queue         = "";
226
227     // Mandatory parameters
228     if (params.find(WORKDIR) != params.end()) 
229       workDir = params[WORKDIR].str();
230     else 
231       throw EmulationException("params[WORKDIR] is not defined ! Please defined it, cannot submit this job");
232     if (params.find(EXECUTABLE) != params.end()) 
233       fileToExecute = params[EXECUTABLE].str();
234     else 
235       throw EmulationException("params[EXECUTABLE] is not defined ! Please defined it, cannot submit this job");
236
237     // Optional parameters
238     if (params.find(NBPROC) != params.end()) 
239       nbproc = params[NBPROC];
240     if (params.find(MAXWALLTIME) != params.end()) 
241       edt = params[MAXWALLTIME];
242     if (params.find(MAXRAMSIZE) != params.end()) 
243       mem = params[MAXRAMSIZE];
244     if (params.find(QUEUE) != params.end()) 
245       queue = params[QUEUE].str();
246
247     string::size_type p1 = fileToExecute.find_last_of("/");
248     string::size_type p2 = fileToExecute.find_last_of(".");
249     string rootNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
250     string fileNameToExecute = fileToExecute.substr(p1+1);
251
252     // Create batch submit file
253     ofstream tempOutputFile;
254     std::string TmpFileName = createAndOpenTemporaryFile("PBS-script", tempOutputFile);
255
256     tempOutputFile << "#! /bin/sh -f" << endl;
257     if (nbproc > 0)
258     {
259       // Division - arrondi supĂ©rieur
260       int nodes_requested = (nbproc + _nb_proc_per_node -1) / _nb_proc_per_node;
261       tempOutputFile << "#PBS -l nodes=" << nodes_requested << ":ppn=" << _nb_proc_per_node << endl;
262     }
263     if (queue != "")
264       tempOutputFile << "#PBS -q " << queue << endl;
265     if( edt > 0 )
266       tempOutputFile << "#PBS -l walltime=" << edt*60 << endl;
267     if( mem > 0 )
268       tempOutputFile << "#PBS -l mem=" << mem << "MB" << endl;
269     tempOutputFile << "#PBS -o " << workDir << "/logs/output.log." << rootNameToExecute << endl;
270     tempOutputFile << "#PBS -e " << workDir << "/logs/error.log."  << rootNameToExecute << endl;
271
272     // Define environment for the job
273     if (!env.empty()) {
274       tempOutputFile << "#PBS -v ";
275       Environnement::const_iterator iter;
276       for (iter = env.begin() ; iter != env.end() ; ++iter) {
277         tempOutputFile << iter->first << "=" << iter->second << ",";
278       }
279       tempOutputFile << endl;
280     }
281
282     // Abstraction of PBS_NODEFILE - TODO
283     tempOutputFile << "export LIBBATCH_NODEFILE=$PBS_NODEFILE" << endl;
284
285     // Launch the executable
286     tempOutputFile << "cd " << workDir << endl;
287     tempOutputFile << "./" + fileNameToExecute << endl;
288     tempOutputFile.flush();
289     tempOutputFile.close();
290
291     BATCH_CHMOD(TmpFileName.c_str(), 0x1ED);
292     cerr << "Batch script file generated is: " << TmpFileName.c_str() << endl;
293
294     int status = _protocol.copyFile(TmpFileName, "", "",
295                                     workDir + "/" + rootNameToExecute + "_Batch.sh",
296                                     _hostname, _username);
297     if (status)
298       throw EmulationException("Error of connection on remote host, cannot copy batch submission file");
299   }
300 }