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