]> SALOME platform Git repositories - tools/libbatch.git/blob - src/Core/Batch_BatchManager_eClient.cxx
Salome HOME
add boolean in importDumpStateFile return function
[tools/libbatch.git] / src / Core / Batch_BatchManager_eClient.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_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 <stdlib.h>
33 #include <string.h>
34
35 #include <ctime>
36 #include <iostream>
37 #include <fstream>
38 #include <sstream>
39
40 #include <stdlib.h>
41
42 #ifdef WIN32
43 #include <direct.h>
44 #include <io.h>
45 #endif
46
47 #include <Batch_config.h>
48
49 #include "Batch_BatchManager_eClient.hxx"
50 #include "Batch_RunTimeException.hxx"
51
52 #ifdef MSVC
53 #define EXISTS(path) _access_s(path, 0) == 0
54 #else
55 #define EXISTS(path) access(path, F_OK) == 0
56 #endif
57
58 using namespace std;
59
60
61 namespace Batch {
62
63   BatchManager_eClient::BatchManager_eClient(const Batch::FactBatchManager * parent, const char* host,
64                                              const char * username,
65                                              CommunicationProtocolType protocolType, const char* mpiImpl)
66     : BatchManager(parent, host), _protocol(CommunicationProtocol::getInstance(protocolType)),
67       _username(username)
68   {
69     // instanciation of mpi implementation needed to launch executable in batch script
70     _mpiImpl = FactoryMpiImpl(mpiImpl);
71   }
72
73   // Destructeur
74   BatchManager_eClient::~BatchManager_eClient()
75   {
76     if (_mpiImpl)
77       delete _mpiImpl;
78   }
79
80   void BatchManager_eClient::exportInputFiles(const Job& job)
81   {
82     int status;
83     Parametre params = job.getParametre();
84     Versatile V = params[INFILE];
85     Versatile::iterator Vit;
86
87     status = _protocol.makeDirectory(string(params[TMPDIR]) + "/logs", _hostname, _username);
88     if(status) {
89       std::ostringstream oss;
90       oss << status;
91       std::string ex_mess("Error of connection on remote host ! status = ");
92       ex_mess += oss.str();
93       throw EmulationException(ex_mess.c_str());
94     }
95
96     // Second step : copy fileToExecute into
97     // batch tmp files directory
98     string executeFile = params[EXECUTABLE];
99     if (executeFile.size() != 0) {
100       status = _protocol.copyFile(executeFile, "", "",
101                                   params[TMPDIR], _hostname, _username);
102       if(status) {
103         std::ostringstream oss;
104         oss << status;
105         std::string ex_mess("Error of connection on remote host ! status = ");
106         ex_mess += oss.str();
107         throw EmulationException(ex_mess.c_str());
108       }
109
110 #ifdef WIN32
111       // On Windows, we make the remote file executable afterward because
112       // pscp does not preserve access permissions on files
113       string subCommand = string("chmod u+x ") + string(params[TMPDIR]) + "/" +
114                           string(params[EXECUTABLE]);
115       string command = _protocol.getExecCommand(subCommand, _hostname, _username);
116       cerr << command.c_str() << endl;
117       status = system(command.c_str());
118       if(status) {
119         std::ostringstream oss;
120         oss << status;
121         std::string ex_mess("Error of connection on remote host ! status = ");
122         ex_mess += oss.str();
123         throw EmulationException(ex_mess.c_str());
124       }
125 #endif
126     }
127
128     // Third step : copy filesToExportList into
129     // batch tmp files directory
130     for(Vit=V.begin(); Vit!=V.end(); Vit++) {
131       CoupleType cpt  = *static_cast< CoupleType * >(*Vit);
132       Couple inputFile = cpt;
133       status = _protocol.copyFile(inputFile.getLocal(), "", "",
134                                   inputFile.getRemote(), _hostname, _username);
135       if(status) {
136         std::ostringstream oss;
137         oss << status;
138         std::string ex_mess("Error of connection on remote host ! status = ");
139         ex_mess += oss.str();
140         throw EmulationException(ex_mess.c_str());
141       }
142     }
143
144   }
145
146   void BatchManager_eClient::importOutputFiles( const Job & job, const string directory )
147   {
148     Parametre params = job.getParametre();
149     Versatile V = params[OUTFILE];
150     Versatile::iterator Vit;
151
152     // Create local result directory
153     int status = CommunicationProtocol::getInstance(SH).makeDirectory(directory, "", "");
154     if (status) {
155       string mess("Directory creation failed. Status is :");
156       ostringstream status_str;
157       status_str << status;
158       mess += status_str.str();
159       cerr << mess << endl;
160     }
161
162     for(Vit=V.begin(); Vit!=V.end(); Vit++) {
163       CoupleType cpt  = *static_cast< CoupleType * >(*Vit);
164       Couple outputFile = cpt;
165       status = _protocol.copyFile(outputFile.getRemote(), _hostname, _username,
166                                   directory, "", "");
167       if (status) {
168         // Try to get what we can (logs files)
169         // throw BatchException("Error of connection on remote host");
170         std::string mess("Copy command failed ! status is :");
171         ostringstream status_str;
172         status_str << status;
173         mess += status_str.str();
174         cerr << mess << endl;
175       }
176     }
177
178     // Copy logs
179     status = _protocol.copyFile(string(params[TMPDIR]) + string("/logs"), _hostname, _username,
180                                 directory, "", "");
181     if (status) {
182       std::string mess("Copy logs directory failed ! status is :");
183       ostringstream status_str;
184       status_str << status;
185       mess += status_str.str();
186       cerr << mess << endl;
187     }
188
189   }
190
191   bool BatchManager_eClient::importDumpStateFile( const Job & job, const string directory )
192   {
193     Parametre params = job.getParametre();
194
195     // Create local result directory
196     int status = CommunicationProtocol::getInstance(SH).makeDirectory(directory, "", "");
197     if (status) {
198       string mess("Directory creation failed. Status is :");
199       ostringstream status_str;
200       status_str << status;
201       mess += status_str.str();
202       cerr << mess << endl;
203     }
204
205     bool ret = true;
206     status = _protocol.copyFile(string(params[TMPDIR]) + string("/dumpState*.xml"), _hostname, _username,
207                                 directory, "", "");
208     if (status) {
209       // Try to get what we can (logs files)
210       // throw BatchException("Error of connection on remote host");
211       std::string mess("Copy command failed ! status is :");
212       ostringstream status_str;
213       status_str << status;
214       mess += status_str.str();
215       cerr << mess << endl;
216       ret = false;
217     }
218     return ret;
219   }
220
221   MpiImpl *BatchManager_eClient::FactoryMpiImpl(string mpiImpl)
222   {
223     if(mpiImpl == "lam")
224       return new MpiImpl_LAM();
225     else if(mpiImpl == "mpich1")
226       return new MpiImpl_MPICH1();
227     else if(mpiImpl == "mpich2")
228       return new MpiImpl_MPICH2();
229     else if(mpiImpl == "openmpi")
230       return new MpiImpl_OPENMPI();
231     else if(mpiImpl == "slurm")
232       return new MpiImpl_SLURM();
233     else if(mpiImpl == "prun")
234       return new MpiImpl_PRUN();
235     else if(mpiImpl == "nompi")
236       return NULL;
237     else{
238       ostringstream oss;
239       oss << mpiImpl << " : not yet implemented";
240       throw EmulationException(oss.str().c_str());
241     }
242   }
243
244   /**
245    * This method generates a temporary file name with the pattern "<tmpdir>/<prefix>-XXXXXX" where
246    * <tmpdir> is the directory for temporary files (see BatchManager_eClient::getTmpDir()) and the
247    * X's are replaced by random characters. Note that this method is less secure than
248    * BatchManager_eClient::createAndOpenTemporaryFile, so use the latter whenever possible.
249    * \param prefix the prefix to use for the temporary file.
250    * \return a name usable for a temporary file.
251    */
252   string BatchManager_eClient::generateTemporaryFileName(const string & prefix)
253   {
254     string fileName = getTmpDir() + "/" + prefix + "-XXXXXX";
255     char randstr[7];
256
257     do {
258       sprintf(randstr, "%06d", rand() % 1000000);
259       fileName.replace(fileName.size()-6, 6, randstr);
260     } while (EXISTS(fileName.c_str()));
261
262     return fileName;
263   }
264
265   /**
266    * This method creates a temporary file and opens an output stream to write into this file.
267    * The file is created with the pattern "<tmpdir>/<prefix>-XXXXXX" where <tmpdir> is the directory
268    * for temporary files (see BatchManager_eClient::getTmpDir()) and the X's are replaced by random
269    * characters. The caller is responsible for closing and deleting the file when it is no more used.
270    * \param prefix the prefix to use for the temporary file.
271    * \param outputStream an output stream that will be opened for writing in the temporary file. If
272    * the stream is already open, it will be closed first.
273    * \return the name of the created file.
274    */
275   string BatchManager_eClient::createAndOpenTemporaryFile(const string & prefix, ofstream & outputStream)
276   {
277     if (outputStream.is_open())
278       outputStream.close();
279
280 #ifdef WIN32
281
282     string fileName = generateTemporaryFileName(prefix);
283     outputStream.open(fileName.c_str());
284
285 #else
286
287     string fileName = getTmpDir() + "/" + prefix + "-XXXXXX";
288     char * buf = new char[fileName.size()+1];
289     fileName.copy(buf, fileName.size());
290     buf[fileName.size()] = '\0';
291
292     int fd = mkstemp(buf);
293     if (fd == -1) {
294       delete[] buf;
295       throw RunTimeException(string("Can't create temporary file ") + fileName);
296     }
297     fileName = buf;
298     delete[] buf;
299
300     outputStream.open(fileName.c_str());
301     close(fd);  // Close the file descriptor so that the file is not opened twice
302
303 #endif
304
305     if (outputStream.fail())
306       throw RunTimeException(string("Can't open temporary file ") + fileName);
307
308     return fileName;
309   }
310
311   /**
312    * This method finds the name of the directory to use for temporary files in libBatch. This name
313    * is <tempdir>/libBatch-<username>-XXXXXX. <tempdir> is found by looking for environment
314    * variables TEMP, TMP, TEMPDIR, TMPDIR, and defaults to "/tmp" if none of them is defined.
315    * <username> is found by looking for environment variables USER and USERNAME, and defaults to
316    * "unknown". XXXXXX represents random characters. The directory name is generated only once for
317    * each BatchManager_eClient instance, and the directory is created at this moment. Subsequent
318    * calls will always return the same path and the existence of the directory will not be
319    * rechecked.
320    * \return the name of the directory to use for temporary files.
321    */
322   const std::string & BatchManager_eClient::getTmpDir()
323   {
324     if (tmpDirName.empty()) {
325       const char * baseDir = getenv("TEMP");
326       if (baseDir == NULL) baseDir = getenv("TMP");
327       if (baseDir == NULL) baseDir = getenv("TEMPDIR");
328       if (baseDir == NULL) baseDir = getenv("TMPDIR");
329       if (baseDir == NULL) baseDir = "/tmp";
330
331       const char * userName = getenv("USER");
332       if (userName == NULL) userName = getenv("USERNAME");
333       if (userName == NULL) userName = "unknown";
334
335       string baseName = string(baseDir) + "/libBatch-" + userName + "-XXXXXX";
336       srand(time(NULL));
337
338 #ifdef WIN32
339
340       char randstr[7];
341       do {
342         sprintf(randstr, "%06d", rand() % 1000000);
343         baseName.replace(baseName.size()-6, 6, randstr);
344       } while (EXISTS(baseName.c_str()));
345       if (_mkdir(baseName.c_str()) != 0)
346         throw RunTimeException(string("Can't create temporary directory ") + baseName);
347       tmpDirName = baseName;
348
349 #else
350
351       char * buf = new char[baseName.size() + 1];
352       baseName.copy(buf, baseName.size());
353       buf[baseName.size()] = '\0';
354       if (mkdtemp(buf) == NULL) {
355         delete[] buf;
356         throw RunTimeException(string("Can't create temporary directory ") + baseName);
357       }
358       tmpDirName = buf;
359       delete[] buf;
360
361 #endif
362
363     }
364
365     return tmpDirName;
366   }
367
368 }