1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 * BatchManager_eLSF.cxx : emulation of LSF client
25 * Auteur : Bernard SECHER - CEA DEN
26 * Mail : mailto:bernard.secher@cea.fr
27 * Date : Thu Apr 24 10:17:22 2008
32 #include "Batch_BatchManager_eClient.hxx"
33 #include "Batch_RunTimeException.hxx"
43 #include "Batch_config.h"
50 BatchManager_eClient::BatchManager_eClient(const Batch::FactBatchManager * parent, const char* host,
51 const char* protocol, const char* mpiImpl)
52 : BatchManager(parent, host), _protocol(protocol), _username("")
54 // instanciation of mpi implementation needed to launch executable in batch script
55 _mpiImpl = FactoryMpiImpl(mpiImpl);
59 BatchManager_eClient::~BatchManager_eClient()
65 void BatchManager_eClient::exportInputFiles(const Job& job)
68 Parametre params = job.getParametre();
69 Versatile V = params[INFILE];
70 Versatile::iterator Vit;
71 _username = string(params[USER]);
73 string command = "\"";
74 string copy_command = "\"";
77 if( _protocol == "rsh" ) {
80 } else if( _protocol == "ssh" ) {
84 throw EmulationException("Unknown protocol : only rsh and ssh are known !");
87 copy_command += "\" ";
89 // First step : creating batch tmp files directory
91 command += _username + "@";
94 command += " mkdir -p ";
95 command += string(params[TMPDIR]);
96 cerr << command.c_str() << endl;
97 status = system(command.c_str());
99 std::ostringstream oss;
101 std::string ex_mess("Error of connection on remote host ! status = ");
102 ex_mess += oss.str();
103 throw EmulationException(ex_mess.c_str());
106 // Second step : copy fileToExecute into
107 // batch tmp files directory
108 string executeFile = params[EXECUTABLE];
109 if( executeFile.size() > 0 ){
110 command = copy_command;
111 command += string(params[EXECUTABLE]);
114 command += _username;
117 command += _hostname;
119 command += string(params[TMPDIR]);
120 cerr << command.c_str() << endl;
121 status = system(command.c_str());
123 std::ostringstream oss;
125 std::string ex_mess("Error of connection on remote host ! status = ");
126 ex_mess += oss.str();
127 throw EmulationException(ex_mess.c_str());
131 // On Windows, we make the remote file executable afterward because pscp does not preserve
132 // access permissions on files
134 if( _protocol == "rsh" ) {
136 } else if( _protocol == "ssh" ) {
139 throw EmulationException("Unknown protocol : only rsh and ssh are known !");
143 command += _username + "@";
145 command += _hostname;
146 command += " chmod u+x ";
147 command += string(params[TMPDIR]) + "/" + string(params[EXECUTABLE]);
148 cerr << command.c_str() << endl;
149 status = system(command.c_str());
151 std::ostringstream oss;
153 std::string ex_mess("Error of connection on remote host ! status = ");
154 ex_mess += oss.str();
155 throw EmulationException(ex_mess.c_str());
160 // Third step : copy filesToExportList into
161 // batch tmp files directory
162 for(Vit=V.begin(); Vit!=V.end(); Vit++) {
163 CoupleType cpt = *static_cast< CoupleType * >(*Vit);
164 Couple inputFile = cpt;
165 command = copy_command;
166 command += inputFile.getLocal();
169 command += _username;
172 command += _hostname;
174 command += inputFile.getRemote();
175 cerr << command.c_str() << endl;
176 status = system(command.c_str());
178 std::ostringstream oss;
180 std::string ex_mess("Error of connection on remote host ! status = ");
181 ex_mess += oss.str();
182 throw EmulationException(ex_mess.c_str());
188 void BatchManager_eClient::importOutputFiles( const Job & job, const string directory ) throw(EmulationException)
192 Parametre params = job.getParametre();
193 Versatile V = params[OUTFILE];
194 Versatile::iterator Vit;
196 for(Vit=V.begin(); Vit!=V.end(); Vit++) {
197 CoupleType cpt = *static_cast< CoupleType * >(*Vit);
198 Couple outputFile = cpt;
200 string command = "\"";
203 if( _protocol == "rsh" ) {
205 } else if( _protocol == "ssh" ) {
208 throw EmulationException("Unknown protocol : only rsh and ssh are known !");
212 if (_username != ""){
213 command += _username;
216 command += _hostname;
218 command += outputFile.getRemote();
220 command += directory;
221 cerr << command.c_str() << endl;
222 status = system(command.c_str());
225 // Try to get what we can (logs files)
226 // throw BatchException("Error of connection on remote host");
227 std::string mess("Copy command failed ! status is :");
228 ostringstream status_str;
229 status_str << status;
230 mess += status_str.str();
231 cerr << mess << endl;
237 MpiImpl *BatchManager_eClient::FactoryMpiImpl(string mpiImpl) throw(EmulationException)
240 return new MpiImpl_LAM();
241 else if(mpiImpl == "mpich1")
242 return new MpiImpl_MPICH1();
243 else if(mpiImpl == "mpich2")
244 return new MpiImpl_MPICH2();
245 else if(mpiImpl == "openmpi")
246 return new MpiImpl_OPENMPI();
247 else if(mpiImpl == "slurm")
248 return new MpiImpl_SLURM();
249 else if(mpiImpl == "prun")
250 return new MpiImpl_PRUN();
251 else if(mpiImpl == "nompi")
252 throw EmulationException("you must specify an mpi implementation for batch manager");
255 oss << mpiImpl << " : not yet implemented";
256 throw EmulationException(oss.str().c_str());
261 * This method generates a temporary file name with the pattern "<tmpdir>/<prefix>-XXXXXX" where
262 * <tmpdir> is the directory for temporary files (see BatchManager_eClient::getTmpDir()) and the
263 * X's are replaced by random characters. Note that this method is less secure than
264 * BatchManager_eClient::createAndOpenTemporaryFile, so use the latter whenever possible.
265 * \param prefix the prefix to use for the temporary file.
266 * \return a name usable for a temporary file.
268 string BatchManager_eClient::generateTemporaryFileName(const string & prefix)
270 string fileName = getTmpDir() + "/" + prefix + "-XXXXXX";
274 sprintf(randstr, "%06d", rand() % 1000000);
275 fileName.replace(fileName.size()-6, 6, randstr);
276 } while (access(fileName.c_str(), F_OK) == 0);
282 * This method creates a temporary file and opens an output stream to write into this file.
283 * The file is created with the pattern "<tmpdir>/<prefix>-XXXXXX" where <tmpdir> is the directory
284 * for temporary files (see BatchManager_eClient::getTmpDir()) and the X's are replaced by random
285 * characters. The caller is responsible for closing and deleting the file when it is no more used.
286 * \param prefix the prefix to use for the temporary file.
287 * \param outputStream an output stream that will be opened for writing in the temporary file. If
288 * the stream is already open, it will be closed first.
289 * \return the name of the created file.
291 string BatchManager_eClient::createAndOpenTemporaryFile(const string & prefix, ofstream & outputStream)
293 if (outputStream.is_open())
294 outputStream.close();
298 string fileName = generateTemporaryFileName(prefix);
299 outputStream.open(fileName.c_str());
303 string fileName = getTmpDir() + "/" + prefix + "-XXXXXX";
304 char buf[fileName.size()+1];
305 fileName.copy(buf, fileName.size());
306 buf[fileName.size()] = '\0';
308 int fd = mkstemp(buf);
310 throw RunTimeException(string("Can't create temporary file ") + fileName);
313 outputStream.open(fileName.c_str());
314 close(fd); // Close the file descriptor so that the file is not opened twice
318 if (outputStream.fail())
319 throw RunTimeException(string("Can't open temporary file ") + fileName);
325 * This method finds the name of the directory to use for temporary files in libBatch. This name
326 * is <tempdir>/libBatch-<username>-XXXXXX. <tempdir> is found by looking for environment
327 * variables TEMP, TMP, TEMPDIR, TMPDIR, and defaults to "/tmp" if none of them is defined.
328 * <username> is found by looking for environment variables USER and USERNAME, and defaults to
329 * "unknown". XXXXXX represents random characters. The directory name is generated only once for
330 * each BatchManager_eClient instance, and the directory is created at this moment. Subsequent
331 * calls will always return the same path and the existence of the directory will not be
333 * \return the name of the directory to use for temporary files.
335 const std::string & BatchManager_eClient::getTmpDir()
337 if (tmpDirName.empty()) {
338 char * baseDir = getenv("TEMP");
339 if (baseDir == NULL) baseDir = getenv("TMP");
340 if (baseDir == NULL) baseDir = getenv("TEMPDIR");
341 if (baseDir == NULL) baseDir = getenv("TMPDIR");
342 if (baseDir == NULL) baseDir = "/tmp";
344 char * userName = getenv("USER");
345 if (userName == NULL) userName = getenv("USERNAME");
346 if (userName == NULL) userName = "unknown";
348 string baseName = string(baseDir) + "/libBatch-" + userName + "-XXXXXX";
355 sprintf(randstr, "%06d", rand() % 1000000);
356 baseName.replace(baseName.size()-6, 6, randstr);
357 } while (access(baseName.c_str(), F_OK) == 0);
358 if (_mkdir(baseName.c_str()) != 0)
359 throw RunTimeException(string("Can't create temporary directory ") + baseName);
360 tmpDirName = baseName;
364 char buf[baseName.size()+1];
365 baseName.copy(buf, baseName.size());
366 buf[baseName.size()] = '\0';
367 if (mkdtemp(buf) == NULL)
368 throw RunTimeException(string("Can't create temporary directory ") + baseName);