1 // Copyright (C) 2007-2012 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
47 #include <Batch_config.h>
49 #include "Batch_Constants.hxx"
50 #include "Batch_BatchManager_eClient.hxx"
51 #include "Batch_RunTimeException.hxx"
54 #define EXISTS(path) _access_s(path, 0) == 0
56 #define EXISTS(path) access(path, F_OK) == 0
64 BatchManager_eClient::BatchManager_eClient(const Batch::FactBatchManager * parent, const char* host,
65 const char * username,
66 CommunicationProtocolType protocolType, const char* mpiImpl)
67 : BatchManager(parent, host), _protocol(CommunicationProtocol::getInstance(protocolType)),
70 // instanciation of mpi implementation needed to launch executable in batch script
71 _mpiImpl = FactoryMpiImpl(mpiImpl);
75 BatchManager_eClient::~BatchManager_eClient()
81 void BatchManager_eClient::exportInputFiles(const Job& job)
84 Parametre params = job.getParametre();
85 const Versatile & V = params[INFILE];
86 Versatile::const_iterator Vit;
88 status = _protocol.makeDirectory(string(params[TMPDIR]) + "/logs", _hostname, _username);
90 std::ostringstream oss;
92 std::string ex_mess("Error of connection on remote host ! status = ");
94 throw EmulationException(ex_mess.c_str());
97 // Second step : copy fileToExecute into
98 // batch tmp files directory
99 string executeFile = params[EXECUTABLE];
100 if (executeFile.size() != 0) {
101 status = _protocol.copyFile(executeFile, "", "",
102 params[TMPDIR], _hostname, _username);
104 std::ostringstream oss;
106 std::string ex_mess("Error of connection on remote host ! status = ");
107 ex_mess += oss.str();
108 throw EmulationException(ex_mess.c_str());
112 // On Windows, we make the remote file executable afterward because
113 // pscp does not preserve access permissions on files
115 string executable = string(params[EXECUTABLE]);
116 executable = executable.substr(executable.rfind("\\") + 1,executable.length());
118 string subCommand = string("chmod u+x ") + string(params[TMPDIR]) + "/" + executable;
119 string command = _protocol.getExecCommand(subCommand, _hostname, _username);
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());
132 // Third step : copy filesToExportList into
133 // batch tmp files directory
134 for(Vit=V.begin(); Vit!=V.end(); Vit++) {
135 CoupleType cpt = *static_cast< CoupleType * >(*Vit);
136 Couple inputFile = cpt;
137 status = _protocol.copyFile(inputFile.getLocal(), "", "",
138 inputFile.getRemote(), _hostname, _username);
140 std::ostringstream oss;
142 std::string ex_mess("Error of connection on remote host ! status = ");
143 ex_mess += oss.str();
144 throw EmulationException(ex_mess.c_str());
150 void BatchManager_eClient::importOutputFiles( const Job & job, const string directory )
152 Parametre params = job.getParametre();
153 const Versatile & V = params[OUTFILE];
154 Versatile::const_iterator Vit;
156 // Create local result directory
157 int status = CommunicationProtocol::getInstance(SH).makeDirectory(directory, "", "");
159 string mess("Directory creation failed. Status is :");
160 ostringstream status_str;
161 status_str << status;
162 mess += status_str.str();
163 cerr << mess << endl;
166 for(Vit=V.begin(); Vit!=V.end(); Vit++) {
167 CoupleType cpt = *static_cast< CoupleType * >(*Vit);
168 Couple outputFile = cpt;
169 status = _protocol.copyFile(outputFile.getRemote(), _hostname, _username,
170 outputFile.getLocal(), "", "");
172 // Try to get what we can (logs files)
173 // throw BatchException("Error of connection on remote host");
174 std::string mess("Copy command failed ! status is :");
175 ostringstream status_str;
176 status_str << status;
177 mess += status_str.str();
178 cerr << mess << endl;
183 status = _protocol.copyFile(string(params[TMPDIR]) + string("/logs"), _hostname, _username,
186 std::string mess("Copy logs directory failed ! status is :");
187 ostringstream status_str;
188 status_str << status;
189 mess += status_str.str();
190 cerr << mess << endl;
195 bool BatchManager_eClient::importDumpStateFile( const Job & job, const string directory )
197 Parametre params = job.getParametre();
199 // Create local result directory
200 int status = CommunicationProtocol::getInstance(SH).makeDirectory(directory, "", "");
202 string mess("Directory creation failed. Status is :");
203 ostringstream status_str;
204 status_str << status;
205 mess += status_str.str();
206 cerr << mess << endl;
210 status = _protocol.copyFile(string(params[TMPDIR]) + string("/dumpState*.xml"), _hostname, _username,
213 // Try to get what we can (logs files)
214 // throw BatchException("Error of connection on remote host");
215 std::string mess("Copy command failed ! status is :");
216 ostringstream status_str;
217 status_str << status;
218 mess += status_str.str();
219 cerr << mess << endl;
225 MpiImpl *BatchManager_eClient::FactoryMpiImpl(string mpiImpl)
228 return new MpiImpl_LAM();
229 else if(mpiImpl == "mpich1")
230 return new MpiImpl_MPICH1();
231 else if(mpiImpl == "mpich2")
232 return new MpiImpl_MPICH2();
233 else if(mpiImpl == "openmpi")
234 return new MpiImpl_OPENMPI();
235 else if(mpiImpl == "ompi")
236 return new MpiImpl_OMPI();
237 else if(mpiImpl == "slurm")
238 return new MpiImpl_SLURM();
239 else if(mpiImpl == "prun")
240 return new MpiImpl_PRUN();
241 else if(mpiImpl == "nompi")
245 oss << mpiImpl << " : not yet implemented";
246 throw EmulationException(oss.str().c_str());
251 * This method generates a temporary file name with the pattern "<tmpdir>/<prefix>-XXXXXX" where
252 * <tmpdir> is the directory for temporary files (see BatchManager_eClient::getTmpDir()) and the
253 * X's are replaced by random characters. Note that this method is less secure than
254 * BatchManager_eClient::createAndOpenTemporaryFile, so use the latter whenever possible.
255 * \param prefix the prefix to use for the temporary file.
256 * \return a name usable for a temporary file.
258 string BatchManager_eClient::generateTemporaryFileName(const string & prefix)
260 string fileName = getTmpDir() + "/" + prefix + "-XXXXXX";
264 sprintf(randstr, "%06d", rand() % 1000000);
265 fileName.replace(fileName.size()-6, 6, randstr);
266 } while (EXISTS(fileName.c_str()));
272 * This method creates a temporary file and opens an output stream to write into this file.
273 * The file is created with the pattern "<tmpdir>/<prefix>-XXXXXX" where <tmpdir> is the directory
274 * for temporary files (see BatchManager_eClient::getTmpDir()) and the X's are replaced by random
275 * characters. The caller is responsible for closing and deleting the file when it is no more used.
276 * \param prefix the prefix to use for the temporary file.
277 * \param outputStream an output stream that will be opened for writing in the temporary file. If
278 * the stream is already open, it will be closed first.
279 * \return the name of the created file.
281 string BatchManager_eClient::createAndOpenTemporaryFile(const string & prefix, ofstream & outputStream)
283 if (outputStream.is_open())
284 outputStream.close();
288 string fileName = generateTemporaryFileName(prefix);
289 // Open the file as binary to avoid problems with Windows newlines
290 outputStream.open(fileName.c_str(), ios_base::binary | ios_base::out);
294 string fileName = getTmpDir() + "/" + prefix + "-XXXXXX";
295 char * buf = new char[fileName.size()+1];
296 fileName.copy(buf, fileName.size());
297 buf[fileName.size()] = '\0';
299 int fd = mkstemp(buf);
302 throw RunTimeException(string("Can't create temporary file ") + fileName);
307 outputStream.open(fileName.c_str());
308 close(fd); // Close the file descriptor so that the file is not opened twice
312 if (outputStream.fail())
313 throw RunTimeException(string("Can't open temporary file ") + fileName);
319 * This method finds the name of the directory to use for temporary files in libBatch. This name
320 * is <tempdir>/libBatch-<username>-XXXXXX. <tempdir> is found by looking for environment
321 * variables TEMP, TMP, TEMPDIR, TMPDIR, and defaults to "/tmp" if none of them is defined.
322 * <username> is found by looking for environment variables USER and USERNAME, and defaults to
323 * "unknown". XXXXXX represents random characters. The directory name is generated only once for
324 * each BatchManager_eClient instance, and the directory is created at this moment. Subsequent
325 * calls will always return the same path and the existence of the directory will not be
327 * \return the name of the directory to use for temporary files.
329 const std::string & BatchManager_eClient::getTmpDir()
331 if (tmpDirName.empty()) {
332 const char * baseDir = getenv("TEMP");
333 if (baseDir == NULL) baseDir = getenv("TMP");
334 if (baseDir == NULL) baseDir = getenv("TEMPDIR");
335 if (baseDir == NULL) baseDir = getenv("TMPDIR");
336 if (baseDir == NULL) baseDir = "/tmp";
338 const char * userName = getenv("USER");
339 if (userName == NULL) userName = getenv("USERNAME");
340 if (userName == NULL) userName = "unknown";
342 string baseName = string(baseDir) + "/libBatch-" + userName + "-XXXXXX";
349 sprintf(randstr, "%06d", rand() % 1000000);
350 baseName.replace(baseName.size()-6, 6, randstr);
351 } while (EXISTS(baseName.c_str()));
352 if (_mkdir(baseName.c_str()) != 0)
353 throw RunTimeException(string("Can't create temporary directory ") + baseName);
354 tmpDirName = baseName;
358 char * buf = new char[baseName.size() + 1];
359 baseName.copy(buf, baseName.size());
360 buf[baseName.size()] = '\0';
361 if (mkdtemp(buf) == NULL) {
363 throw RunTimeException(string("Can't create temporary directory ") + baseName);