Salome HOME
Merged from BR_V51_RB (removed Batch and added libBatch as an optional prerequisite).
[modules/kernel.git] / src / Launcher / Launcher.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 #ifdef WITH_LIBBATCH
24 #include <Batch/Batch_Date.hxx>
25 #include <Batch/Batch_FactBatchManager_eLSF.hxx>
26 #include <Batch/Batch_FactBatchManager_ePBS.hxx>
27 #include <Batch/Batch_BatchManager_eClient.hxx>
28 #include <Batch/Batch_FactBatchManager_eSGE.hxx>
29 #endif
30
31 #include "SALOME_Launcher_Handler.hxx"
32 #include "Launcher.hxx"
33 #include <iostream>
34 #include <sstream>
35 #include <sys/stat.h>
36 #include <time.h>
37
38 using namespace std;
39
40 //=============================================================================
41 /*! 
42  *  Constructor
43  *  \param orb
44  *  Define a CORBA single thread policy for the server, which avoid to deal
45  *  with non thread-safe usage like Change_Directory in SALOME naming service
46  */
47 //=============================================================================
48
49 Launcher_cpp::Launcher_cpp()
50 {
51 #if defined(_DEBUG_) || defined(_DEBUG)
52   cerr << "Launcher_cpp constructor" << endl;
53 #endif
54 }
55
56 //=============================================================================
57 /*! 
58  * destructor
59  */
60 //=============================================================================
61
62 Launcher_cpp::~Launcher_cpp()
63 {
64 #if defined(_DEBUG_) || defined(_DEBUG)
65   cerr << "Launcher_cpp destructor" << endl;
66 #endif
67
68 #ifdef WITH_LIBBATCH
69   std::map < string, Batch::BatchManager_eClient * >::const_iterator it1;
70   for(it1=_batchmap.begin();it1!=_batchmap.end();it1++)
71     delete it1->second;
72   std::map < std::pair<std::string,long> , Batch::Job* >::const_iterator it2;
73   for(it2=_jobmap.begin();it2!=_jobmap.end();it2++)
74     delete it2->second;
75 #endif
76 }
77
78 //=============================================================================
79 /*! CORBA Method:
80  *  Submit a batch job on a cluster and returns the JobId
81  *  \param xmlExecuteFile     : to define the execution on the batch cluster
82  *  \param clusterName        : name of the batch cluster
83  */
84 //=============================================================================
85 long Launcher_cpp::submitJob( const std::string xmlExecuteFile,
86                   const std::string clusterName) throw(LauncherException)
87 {
88 #ifdef WITH_LIBBATCH
89 #if defined(_DEBUG_) || defined(_DEBUG)
90   cout << "BEGIN OF Launcher_cpp::submitJob" << endl;
91 #endif
92   long jobId;
93   vector<string> aMachineList;
94
95   if(!_ResManager)
96     throw LauncherException("You must set Resources Manager to Launcher!!");
97
98   // verify if cluster is in resources catalog
99   machineParams params;
100   params.hostname = clusterName;
101   try{
102     aMachineList = _ResManager->GetFittingResources(params);
103   }
104   catch(const ResourcesException &ex){
105     throw LauncherException(ex.msg.c_str());
106   }
107   if (aMachineList.size() == 0)
108     throw LauncherException("This cluster is not in resources catalog");
109
110   // Parsing xml file
111   ParseXmlFile(xmlExecuteFile);
112
113   // verify if clustername is in xml file
114   map<std::string,MachineParameters>::const_iterator it1 = _launch.MachinesList.find(clusterName);
115   if(it1 == _launch.MachinesList.end())
116     throw LauncherException("This cluster is not in xml file");
117
118   ParserResourcesType p = _ResManager->GetResourcesList(aMachineList[0]);
119   string cname(p.Alias);
120 #if defined(_DEBUG_) || defined(_DEBUG)
121   cout << "Choose cluster: " <<  cname << endl;
122 #endif
123
124   // search batch manager for that cluster in map or instanciate one
125   map < string, Batch::BatchManager_eClient * >::const_iterator it2 = _batchmap.find(cname);
126   if(it2 == _batchmap.end())
127     {
128       _batchmap[cname] = FactoryBatchManager(p);
129       // TODO: Add a test for the cluster !
130     }
131     
132   try{
133
134     // directory on cluster to put files to execute
135     string remotedir = _launch.MachinesList[clusterName].WorkDirectory;
136     // local directory to get files to execute and to put results
137     string localdir = _launch.RefDirectory;
138
139     int idx1 = xmlExecuteFile.find_last_of("/");
140     if(idx1 == string::npos) idx1 = -1;
141     int idx2 = xmlExecuteFile.find(".xml");
142     string logfile = xmlExecuteFile.substr(idx1+1,idx2-idx1-1);
143     string ologfile = logfile + ".output.log";
144     string elogfile = logfile + ".error.log";
145
146     // create and submit job on cluster
147     Batch::Parametre param;
148     param[USER] = p.UserName;
149     param[EXECUTABLE] = "";
150     for(int i=0; i<_launch.InputFile.size();i++)
151       param[INFILE] += Batch::Couple( localdir + "/" + _launch.InputFile[i], remotedir + "/" + _launch.InputFile[i] );
152     for(int i=0; i<_launch.OutputFile.size();i++)
153       param[OUTFILE] += Batch::Couple( localdir + "/" + _launch.OutputFile[i], remotedir + "/" + _launch.OutputFile[i] );
154     param[OUTFILE] += Batch::Couple( localdir + "/" + ologfile, remotedir + "/" + ologfile );
155     param[OUTFILE] += Batch::Couple( localdir + "/" + elogfile, remotedir + "/" + elogfile );
156     param[NBPROC] = _launch.NbOfProcesses;
157     param[WORKDIR] = remotedir;
158     param[TMPDIR] = remotedir;
159     param[MAXWALLTIME] = getWallTime("");
160     param[MAXRAMSIZE] = getRamSize("");
161     param[HOMEDIR] = "";
162
163     Batch::Environnement env;
164     env["COMMAND"] = _launch.Command;
165     env["SOURCEFILE"] = _launch.MachinesList[clusterName].EnvFile;
166     env["LOGFILE"] = logfile;
167
168     Batch::Job* job = new Batch::Job(param,env);
169
170     // submit job on cluster
171     Batch::JobId jid = _batchmap[cname]->submitJob(*job);
172
173     // get job id in long
174     istringstream iss(jid.getReference());
175     iss >> jobId;
176
177     _jobmap[ pair<string,long>(cname,jobId) ] = job;
178   }
179   catch(const Batch::EmulationException &ex){
180     throw LauncherException(ex.message.c_str());
181   }
182
183   return jobId;
184 #else
185   throw LauncherException("Method Launcher_cpp::submitJob is not available "
186                           "(libBatch was not present at compilation time)");
187 #endif
188 }
189
190 //=============================================================================
191 /*! CORBA Method:
192  *  Submit a batch job on a cluster and returns the JobId
193  *  \param fileToExecute      : .py/.exe/.sh/... to execute on the batch cluster
194  *  \param filesToExport      : to export on the batch cluster
195  *  \param NumberOfProcessors : Number of processors needed on the batch cluster
196  *  \param params             : Constraints for the choice of the batch cluster
197  */
198 //=============================================================================
199 long Launcher_cpp::submitSalomeJob( const string fileToExecute ,
200                                     const vector<string>& filesToExport ,
201                                     const vector<string>& filesToImport ,
202                                     const batchParams& batch_params,
203                                     const machineParams& params) throw(LauncherException)
204 {
205 #ifdef WITH_LIBBATCH
206 #if defined(_DEBUG_) || defined(_DEBUG)
207   cerr << "BEGIN OF Launcher_cpp::submitSalomeJob" << endl;
208 #endif
209   long jobId;
210   vector<string> aMachineList;
211
212   if(!_ResManager)
213     throw LauncherException("You must set Resources Manager to Launcher!!");
214
215   // check batch params
216   if ( !check(batch_params) )
217     throw LauncherException("Batch parameters are bad (see informations above)");
218
219   // find a cluster matching the structure params
220   try{
221     aMachineList = _ResManager->GetFittingResources(params);
222   }
223   catch(const ResourcesException &ex){
224     throw LauncherException(ex.msg.c_str());
225   }
226   if (aMachineList.size() == 0)
227     throw LauncherException("No resources have been found with your parameters");
228
229   ParserResourcesType p = _ResManager->GetResourcesList(aMachineList[0]);
230   string clustername(p.Alias);
231 #if defined(_DEBUG_) || defined(_DEBUG)
232   cerr << "Choose cluster: " <<  clustername << endl;
233 #endif
234   
235   // search batch manager for that cluster in map or instanciate one
236   map < string, Batch::BatchManager_eClient * >::const_iterator it = _batchmap.find(clustername);
237   if(it == _batchmap.end())
238     {
239       _batchmap[clustername] = FactoryBatchManager(p);
240       // TODO: Add a test for the cluster !
241     }
242     
243   try{
244     // tmp directory on cluster to put files to execute
245     string tmpdir = getTmpDirForBatchFiles();
246
247     // create and submit job on cluster
248     Batch::Parametre param;
249     param[USER] = p.UserName;
250     param[EXECUTABLE] = buildSalomeCouplingScript(fileToExecute,tmpdir,p);
251     param[INFILE] = Batch::Couple( fileToExecute, getRemoteFile(tmpdir,fileToExecute) );
252     for(int i=0;i<filesToExport.size();i++)
253       param[INFILE] += Batch::Couple( filesToExport[i], getRemoteFile(tmpdir,filesToExport[i]) );
254
255     ostringstream file_name_output;
256     file_name_output << "~/" << tmpdir << "/" << "output.log*";
257     ostringstream file_name_error;
258     file_name_error << "~/" << tmpdir << "/" << "error.log*";
259     ostringstream file_container_log;
260     file_container_log << "~/" << tmpdir << "/" << "YACS_Server*";
261     param[OUTFILE] = Batch::Couple( "", file_name_output.str());
262     param[OUTFILE] += Batch::Couple( "", file_name_error.str());
263     param[OUTFILE] += Batch::Couple( "", file_container_log.str());
264
265     for(int i=0;i<filesToImport.size();i++)
266       param[OUTFILE] += Batch::Couple( "", filesToImport[i] );
267
268     param[NBPROC] = batch_params.nb_proc;
269     param[WORKDIR] = batch_params.batch_directory;
270     param[TMPDIR] = tmpdir;
271     param[MAXWALLTIME] = getWallTime(batch_params.expected_during_time);
272     param[MAXRAMSIZE] = getRamSize(batch_params.mem);
273     param[HOMEDIR] = getHomeDir(p, tmpdir);
274     param[QUEUE] = p.batchQueue;
275
276     Batch::Environnement env;
277
278     Batch::Job* job = new Batch::Job(param,env);
279
280     // submit job on cluster
281     Batch::JobId jid = _batchmap[clustername]->submitJob(*job);
282
283     // get job id in long
284     istringstream iss(jid.getReference());
285     iss >> jobId;
286
287     _jobmap[ pair<string,long>(clustername,jobId) ] = job;    
288   }
289   catch(const Batch::EmulationException &ex){
290     throw LauncherException(ex.message.c_str());
291   }
292
293   return jobId;
294 #else
295   throw LauncherException("Method Launcher_cpp::submitSalomeJob is not available "
296                           "(libBatch was not present at compilation time)");
297 #endif
298 }
299
300 //=============================================================================
301 /*! CORBA Method:
302  *  Query a batch job on a cluster and returns the status of job
303  *  \param jobId              : identification of Salome job
304  *  \param params             : Constraints for the choice of the batch cluster
305  */
306 //=============================================================================
307 string Launcher_cpp::queryJob( long id, 
308                                const machineParams& params) throw(LauncherException)
309 {
310 #ifdef WITH_LIBBATCH
311   if(!_ResManager)
312     throw LauncherException("You must set Resources Manager to Launcher!!");
313
314   // find a cluster matching params structure
315   vector<string> aMachineList = _ResManager->GetFittingResources( params ) ;
316   ParserResourcesType p = _ResManager->GetResourcesList(aMachineList[0]);
317   string clustername(p.Alias);
318     
319   // search batch manager for that cluster in map
320   std::map < string, Batch::BatchManager_eClient * >::const_iterator it = _batchmap.find(clustername);
321   if(it == _batchmap.end())
322     throw LauncherException("no batchmanager for that cluster");
323     
324   Batch::Parametre par;
325   try{
326     ostringstream oss;
327     oss << id;
328     Batch::JobId jobId( _batchmap[clustername], oss.str() );
329
330     Batch::JobInfo jinfo = jobId.queryJob();
331     par = jinfo.getParametre();
332   }
333   catch(const Batch::EmulationException &ex){
334     throw LauncherException(ex.message.c_str());
335   }
336
337   return par[STATE];
338 #else
339   throw LauncherException("Method Launcher_cpp::queryJob is not available "
340                           "(libBatch was not present at compilation time)");
341 #endif
342 }
343
344 string Launcher_cpp::queryJob( long id, 
345                                const std::string clusterName) throw (LauncherException)
346 {
347   machineParams params;
348   params.hostname = clusterName;
349   return queryJob(id,params);
350 }
351
352 //=============================================================================
353 /*! CORBA Method:
354  *  Delete a batch job on a cluster 
355  *  \param jobId              : identification of Salome job
356  *  \param params             : Constraints for the choice of the batch cluster
357  */
358 //=============================================================================
359 void Launcher_cpp::deleteJob( const long id, 
360                               const machineParams& params) throw(LauncherException)
361 {
362 #ifdef WITH_LIBBATCH
363   if(!_ResManager)
364     throw LauncherException("You must set Resources Manager to Launcher!!");
365
366   // find a cluster matching params structure
367   vector<string> aMachineList = _ResManager->GetFittingResources( params ) ;
368   ParserResourcesType p = _ResManager->GetResourcesList(aMachineList[0]);
369   string clustername(p.Alias);
370     
371   // search batch manager for that cluster in map
372   map < string, Batch::BatchManager_eClient * >::const_iterator it = _batchmap.find(clustername);
373   if(it == _batchmap.end())
374     throw LauncherException("no batchmanager for that cluster");
375   
376   ostringstream oss;
377   oss << id;
378   Batch::JobId jobId( _batchmap[clustername], oss.str() );
379
380   jobId.deleteJob();
381 #else
382   throw LauncherException("Method Launcher_cpp::deleteJob is not available "
383                           "(libBatch was not present at compilation time)");
384 #endif
385 }
386
387 void Launcher_cpp::deleteJob( long id, 
388                               const std::string clusterName) throw (LauncherException)
389 {
390   machineParams params;
391   params.hostname = clusterName;
392   deleteJob(id,params);
393 }
394
395 //=============================================================================
396 /*! CORBA Method:
397  *  Get result files of job on a cluster
398  *  \param jobId              : identification of Salome job
399  *  \param params             : Constraints for the choice of the batch cluster
400  */
401 //=============================================================================
402 void Launcher_cpp::getResultsJob( const string directory,
403                                   const long id, 
404                                   const machineParams& params) throw(LauncherException)
405 {
406 #ifdef WITH_LIBBATCH
407   if(!_ResManager)
408     throw LauncherException("You must set Resources Manager to Launcher!!");
409
410   vector<string> aMachineList = _ResManager->GetFittingResources( params ) ;
411   ParserResourcesType p = _ResManager->GetResourcesList(aMachineList[0]);
412   string clustername(p.Alias);
413     
414   // search batch manager for that cluster in map
415   map < string, Batch::BatchManager_eClient * >::const_iterator it = _batchmap.find(clustername);
416   if(it == _batchmap.end())
417     throw LauncherException("no batchmanager for that cluster");
418     
419   Batch::Job* job = _jobmap[ pair<string,long>(clustername,id) ];
420
421   _batchmap[clustername]->importOutputFiles( *job, directory );
422 #else
423   throw LauncherException("Method Launcher_cpp::getResultsJob is not available "
424                           "(libBatch was not present at compilation time)");
425 #endif
426 }
427
428 void Launcher_cpp::getResultsJob( const std::string directory, 
429                                   long id, 
430                                   const std::string clusterName) throw (LauncherException)
431 {
432   machineParams params;
433   params.hostname = clusterName;
434   getResultsJob(directory,id,params);
435 }
436
437 //=============================================================================
438 /*!
439  *  Factory to instanciate the good batch manager for choosen cluster.
440  */ 
441 //=============================================================================
442
443 Batch::BatchManager_eClient *Launcher_cpp::FactoryBatchManager( const ParserResourcesType& params ) throw(LauncherException)
444 {
445 #ifdef WITH_LIBBATCH
446   std::string hostname, mpi;
447   Batch::CommunicationProtocolType protocol;
448   Batch::FactBatchManager_eClient* fact;
449
450   hostname = params.Alias;
451   switch(params.Protocol){
452   case rsh:
453     protocol = Batch::RSH;
454     break;
455   case ssh:
456     protocol = Batch::SSH;
457     break;
458   default:
459     throw LauncherException("unknown protocol");
460     break;
461   }
462   switch(params.mpi){
463   case lam:
464     mpi = "lam";
465     break;
466   case mpich1:
467     mpi = "mpich1";
468     break;
469   case mpich2:
470     mpi = "mpich2";
471     break;
472   case openmpi:
473     mpi = "openmpi";
474     break;
475   case slurm:
476     mpi = "slurm";
477     break;
478   case prun:
479     mpi = "prun";
480     break;
481   case nompi:
482     throw LauncherException("you must specified an mpi implementation for batch manager");
483     break;
484   default:
485     throw LauncherException("unknown mpi implementation");
486     break;
487   }    
488 #if defined(_DEBUG_) || defined(_DEBUG)
489   cerr << "Instanciation of batch manager" << endl;
490 #endif
491   switch( params.Batch ){
492   case pbs:
493 #if defined(_DEBUG_) || defined(_DEBUG)
494     cerr << "Instantiation of PBS batch manager" << endl;
495 #endif
496     fact = new Batch::FactBatchManager_ePBS;
497     break;
498   case lsf:
499 #if defined(_DEBUG_) || defined(_DEBUG)
500     cerr << "Instantiation of LSF batch manager" << endl;
501 #endif
502     fact = new Batch::FactBatchManager_eLSF;
503     break;
504   case sge:
505 #if defined(_DEBUG_) || defined(_DEBUG)
506     cout << "Instantiation of SGE batch manager" << endl;
507 #endif
508     fact = new Batch::FactBatchManager_eSGE;
509     break;
510   default:
511 #if defined(_DEBUG_) || defined(_DEBUG)
512     cerr << "BATCH = " << params.Batch << endl;
513 #endif
514     throw LauncherException("no batchmanager for that cluster");
515   }
516   return (*fact)(hostname.c_str(), protocol, mpi.c_str());
517 #else
518   throw LauncherException("Method Launcher_cpp::FactoryBatchManager is not available "
519                           "(libBatch was not present at compilation time)");
520 #endif
521 }
522
523 string Launcher_cpp::buildSalomeCouplingScript(const string fileToExecute, const string dirForTmpFiles, const ParserResourcesType& params)
524 {
525 #ifdef WITH_LIBBATCH
526 #ifndef WIN32 //TODO: need for porting on Windows
527   int idx = dirForTmpFiles.find("Batch/");
528   std::string filelogtemp = dirForTmpFiles.substr(idx+6, dirForTmpFiles.length());
529
530   string::size_type p1 = fileToExecute.find_last_of("/");
531   string::size_type p2 = fileToExecute.find_last_of(".");
532   std::string fileNameToExecute = fileToExecute.substr(p1+1,p2-p1-1);
533   std::string TmpFileName = "/tmp/runSalome_" + fileNameToExecute + ".sh";
534
535   MpiImpl* mpiImpl = FactoryMpiImpl(params.mpi);
536
537   ofstream tempOutputFile;
538   tempOutputFile.open(TmpFileName.c_str(), ofstream::out );
539
540   // Begin
541   tempOutputFile << "#! /bin/sh -f" << endl ;
542   tempOutputFile << "cd " ;
543   tempOutputFile << params.AppliPath << endl ;
544   tempOutputFile << "export SALOME_BATCH=1\n";
545   tempOutputFile << "export PYTHONPATH=~/" ;
546   tempOutputFile << dirForTmpFiles ;
547   tempOutputFile << ":$PYTHONPATH" << endl ;
548
549   // Adding user script
550   std::string script = params.userCommands;
551   if (script != "")
552     tempOutputFile << script << endl;
553   // Test node rank
554   tempOutputFile << "if test \"" ;
555   tempOutputFile << mpiImpl->rank() ;
556   tempOutputFile << "\" = \"0\"; then" << endl ;
557
558   // -----------------------------------------------
559   // Code for rank 0 : launch runAppli and a container
560   // RunAppli
561   if(params.ModulesList.size()>0)
562     tempOutputFile << "  ./runAppli --terminal --modules=" ;
563   else
564     tempOutputFile << "  ./runAppli --terminal ";
565   for ( int i = 0 ; i < params.ModulesList.size() ; i++ ) {
566     tempOutputFile << params.ModulesList[i] ;
567     if ( i != params.ModulesList.size()-1 )
568       tempOutputFile << "," ;
569   }
570   tempOutputFile << " --standalone=registry,study,moduleCatalog --ns-port-log="
571                  << filelogtemp 
572                  << " &\n";
573
574   // Wait NamingService
575   tempOutputFile << "  current=0\n"
576                  << "  stop=20\n" 
577                  << "  while ! test -f " << filelogtemp << "\n"
578                  << "  do\n"
579                  << "    sleep 2\n"
580                  << "    let current=current+1\n"
581                  << "    if [ \"$current\" -eq \"$stop\" ] ; then\n"
582                  << "      echo Error Naming Service failed ! >&2"
583                  << "      exit\n"
584                  << "    fi\n"
585                  << "  done\n"
586                  << "  port=`cat " << filelogtemp << "`\n";
587     
588   // Wait other containers
589   tempOutputFile << "  for ((ip=1; ip < ";
590   tempOutputFile << mpiImpl->size();
591   tempOutputFile << " ; ip++))" << endl;
592   tempOutputFile << "  do" << endl ;
593   tempOutputFile << "    arglist=\"$arglist YACS_Server_\"$ip" << endl ;
594   tempOutputFile << "  done" << endl ;
595   tempOutputFile << "  sleep 5" << endl ;
596   tempOutputFile << "  ./runSession waitContainers.py $arglist" << endl ;
597   
598   // Launch user script
599   tempOutputFile << "  ./runSession python ~/" << dirForTmpFiles << "/" << fileNameToExecute << ".py" << endl;
600
601   // Stop application
602   tempOutputFile << "  rm " << filelogtemp << "\n"
603                  << "  ./runSession shutdownSalome.py" << endl;
604
605   // -------------------------------------
606   // Other nodes launch a container
607   tempOutputFile << "else" << endl ;
608
609   // Wait NamingService
610   tempOutputFile << "  current=0\n"
611                  << "  stop=20\n" 
612                  << "  while ! test -f " << filelogtemp << "\n"
613                  << "  do\n"
614                  << "    sleep 2\n"
615                  << "    let current=current+1\n"
616                  << "    if [ \"$current\" -eq \"$stop\" ] ; then\n"
617                  << "      echo Error Naming Service failed ! >&2"
618                  << "      exit\n"
619                  << "    fi\n"
620                  << "  done\n"
621                  << "  port=`cat " << filelogtemp << "`\n";
622
623   // Launching container
624   tempOutputFile << "  ./runSession SALOME_Container YACS_Server_";
625   tempOutputFile << mpiImpl->rank()
626                  << " > ~/" << dirForTmpFiles << "/YACS_Server_" 
627                  << mpiImpl->rank() << "_container_log." << filelogtemp
628                  << " 2>&1\n";
629   tempOutputFile << "fi" << endl ;
630   tempOutputFile.flush();
631   tempOutputFile.close();
632   chmod(TmpFileName.c_str(), 0x1ED);
633 #if defined(_DEBUG_) || defined(_DEBUG)
634   cerr << TmpFileName.c_str() << endl;
635 #endif
636
637   delete mpiImpl;
638
639   return TmpFileName;
640 #else
641   return "";
642 #endif
643     
644 #else
645   throw LauncherException("Method Launcher_cpp::buildSalomeCouplingScript is not available "
646                           "(libBatch was not present at compilation time)");
647 #endif
648 }
649
650 MpiImpl *Launcher_cpp::FactoryMpiImpl(MpiImplType mpi) throw(LauncherException)
651 {
652 #ifdef WITH_LIBBATCH
653   switch(mpi){
654   case lam:
655     return new MpiImpl_LAM();
656   case mpich1:
657     return new MpiImpl_MPICH1();
658   case mpich2:
659     return new MpiImpl_MPICH2();
660   case openmpi:
661     return new MpiImpl_OPENMPI();
662   case slurm:
663     return new MpiImpl_SLURM();
664   case prun:
665     return new MpiImpl_PRUN();
666   case nompi:
667     throw LauncherException("you must specify an mpi implementation for batch manager");
668   default:
669     ostringstream oss;
670     oss << mpi << " : not yet implemented";
671     throw LauncherException(oss.str().c_str());
672   }
673 #else
674   throw LauncherException("Method Launcher_cpp::FactoryMpiImpl is not available "
675                           "(libBatch was not present at compilation time)");
676 #endif
677 }
678
679 string Launcher_cpp::getTmpDirForBatchFiles()
680 {
681 #ifdef WITH_LIBBATCH
682   string ret;
683   string thedate;
684
685   // Adding date to the directory name
686   Batch::Date date = Batch::Date(time(0));
687   thedate = date.str();
688   int lend = thedate.size() ;
689   int i = 0 ;
690   while ( i < lend ) {
691     if ( thedate[i] == '/' || thedate[i] == '-' || thedate[i] == ':' ) {
692       thedate[i] = '_' ;
693     }
694     i++ ;
695   }
696
697   ret = string("Batch/");
698   ret += thedate;
699   return ret;
700 #else
701   throw LauncherException("Method Launcher_cpp::getTmpDirForBatchFiles is not available "
702                           "(libBatch was not present at compilation time)");
703 #endif
704 }
705
706 string Launcher_cpp::getRemoteFile( std::string remoteDir, std::string localFile )
707 {
708   string::size_type pos = localFile.find_last_of("/") + 1;
709   int ln = localFile.length() - pos;
710   string remoteFile = remoteDir + "/" + localFile.substr(pos,ln);
711   return remoteFile;
712 }
713
714 bool Launcher_cpp::check(const batchParams& batch_params)
715 {
716   bool rtn = true;
717 #if defined(_DEBUG_) || defined(_DEBUG)
718   cerr << "Job parameters are :" << endl;
719   cerr << "Directory : $HOME/Batch/$date" << endl;
720 #endif
721
722   // check expected_during_time (check the format)
723   std::string edt_info = batch_params.expected_during_time;
724   std::string edt_value = batch_params.expected_during_time;
725   if (edt_value != "") {
726     std::string begin_edt_value = edt_value.substr(0, 2);
727     std::string mid_edt_value = edt_value.substr(2, 1);
728     std::string end_edt_value = edt_value.substr(3);
729   
730     long value;
731     std::istringstream iss(begin_edt_value);
732     if (!(iss >> value)) {
733       edt_info = "Error on definition ! : " + edt_value;
734       rtn = false;
735     }
736     else if (value < 0) {
737       edt_info = "Error on definition time is negative ! : " + value;
738       rtn = false;
739     }
740     std::istringstream iss_2(end_edt_value);
741     if (!(iss_2 >> value)) {
742       edt_info = "Error on definition ! : " + edt_value;
743       rtn = false;
744     }
745     else if (value < 0) {
746       edt_info = "Error on definition time is negative ! : " + value;
747       rtn = false;
748     }
749     if (mid_edt_value != ":") {
750       edt_info = "Error on definition ! :" + edt_value;
751       rtn = false;
752     }
753   }
754   else {
755     edt_info = "No value given";
756   }
757 #if defined(_DEBUG_) || defined(_DEBUG)
758   cerr << "Expected during time : " << edt_info << endl;;
759 #endif
760
761   // check memory (check the format)
762   std::string mem_info;
763   std::string mem_value = batch_params.mem;
764   if (mem_value != "") {
765     std::string begin_mem_value = mem_value.substr(0, mem_value.length()-2);
766     long re_mem_value;
767     std::istringstream iss(begin_mem_value);
768     if (!(iss >> re_mem_value)) {
769       mem_info = "Error on definition ! : " + mem_value;
770       rtn = false;
771     }
772     else if (re_mem_value <= 0) {
773       mem_info = "Error on definition memory is negative ! : " + mem_value;
774       rtn = false;
775     }
776     std::string end_mem_value = mem_value.substr(mem_value.length()-2);
777     if (end_mem_value != "gb" && end_mem_value != "mb") {
778       mem_info = "Error on definition, type is bad ! " + mem_value;
779       rtn = false;
780     }
781   }
782   else {
783     mem_info = "No value given";
784   }
785 #if defined(_DEBUG_) || defined(_DEBUG)
786   cerr << "Memory : " << mem_info << endl;
787 #endif
788
789   // check nb_proc
790   std::string nb_proc_info;
791   ostringstream nb_proc_value;
792   nb_proc_value << batch_params.nb_proc;
793   if(batch_params.nb_proc <= 0) {
794     nb_proc_info = "Bad value ! nb_proc = ";
795     nb_proc_info += nb_proc_value.str();
796     rtn = false;
797   }
798   else {
799     nb_proc_info = nb_proc_value.str();
800   }
801 #if defined(_DEBUG_) || defined(_DEBUG)
802   cerr << "Nb of processors : " << nb_proc_info << endl;
803 #endif
804
805   return rtn;
806 }
807
808 long Launcher_cpp::getWallTime(std::string edt)
809 {
810   long hh, mm, ret;
811
812   if( edt.size() == 0 )
813     return 0;
814
815   string::size_type pos = edt.find(":");
816   string h = edt.substr(0,pos);
817   string m = edt.substr(pos+1,edt.size()-pos+1);
818   istringstream issh(h);
819   issh >> hh;
820   istringstream issm(m);
821   issm >> mm;
822   ret = hh*60 + mm;
823   return  ret;
824 }
825
826 long Launcher_cpp::getRamSize(std::string mem)
827 {
828   long mv;
829
830   if( mem.size() == 0 )
831     return 0;
832
833   string ram = mem.substr(0,mem.size()-2);
834   istringstream iss(ram);
835   iss >> mv;
836   string unity = mem.substr(mem.size()-2,2);
837   if( (unity.find("gb") != string::npos) || (unity.find("GB") != string::npos) )
838     return mv*1024;
839   else if( (unity.find("mb") != string::npos) || (unity.find("MB") != string::npos) )
840     return mv;
841   else if( (unity.find("kb") != string::npos) || (unity.find("KB") != string::npos) )
842     return mv/1024;
843   else if( (unity.find("b") != string::npos) || (unity.find("B") != string::npos) )
844     return mv/(1024*1024);
845   else
846     return 0;
847 }
848
849 void Launcher_cpp::ParseXmlFile(string xmlExecuteFile)
850 {
851   SALOME_Launcher_Handler* handler = new SALOME_Launcher_Handler(_launch);
852
853   const char* aFilePath = xmlExecuteFile.c_str();
854   FILE* aFile = fopen(aFilePath, "r");
855   
856   if (aFile != NULL)
857     {
858       xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
859       
860       if (aDoc != NULL)
861         handler->ProcessXmlDocument(aDoc);
862       else{
863 #if defined(_DEBUG_) || defined(_DEBUG)
864         cout << "ResourcesManager_cpp: could not parse file "<< aFilePath << endl;
865 #endif
866       }
867       
868       // Free the document
869       xmlFreeDoc(aDoc);
870
871       fclose(aFile);
872     }
873   else{
874 #if defined(_DEBUG_) || defined(_DEBUG)
875     cout << "Launcher_cpp: file "<<aFilePath<<" is not readable." << endl;
876 #endif
877   }
878   
879   delete handler;
880
881 }
882
883 std::string Launcher_cpp::getHomeDir(const ParserResourcesType& p, const std::string& tmpdir)
884 {
885   std::string home;
886   std::string command;
887   int idx = tmpdir.find("Batch/");
888   std::string filelogtemp = tmpdir.substr(idx+6, tmpdir.length());
889   filelogtemp = "/tmp/logs" + filelogtemp + "_home";
890   
891   if( p.Protocol == rsh )
892     command = "rsh ";
893   else if( p.Protocol == ssh )
894     command = "ssh ";
895   else
896     throw LauncherException("Unknown protocol");
897   if (p.UserName != ""){
898     command += p.UserName;
899     command += "@";
900   }
901   command += p.Alias;
902   command += " 'echo $HOME' > ";
903   command += filelogtemp;
904 #if defined(_DEBUG_) || defined(_DEBUG)
905   std::cerr << command.c_str() << std::endl;
906 #endif
907   int status = system(command.c_str());
908   if(status)
909     throw LauncherException("Error of launching home command on remote host");
910   
911   std::ifstream file_home(filelogtemp.c_str());
912   std::getline(file_home, home);
913   file_home.close();
914   return home;
915 }