Salome HOME
Changes due to recent improvements in libBatch.
[modules/kernel.git] / src / Launcher / Launcher.cxx
1 // Copyright (C) 2007-2011  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_BatchManagerCatalog.hxx>
26 #include <Batch/Batch_FactBatchManager_eClient.hxx>
27 #include <Batch/Batch_BatchManager_eClient.hxx>
28 #endif
29
30 #include "Basics_Utils.hxx"
31 #include "Basics_DirUtils.hxx"
32 #include "SALOME_Launcher_Handler.hxx"
33 #include "Launcher.hxx"
34 #include "Launcher_Job_Command.hxx"
35 #include <iostream>
36 #include <sstream>
37 #include <sys/stat.h>
38 #include <time.h>
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 Launcher_cpp::Launcher_cpp()
49 {
50   LAUNCHER_MESSAGE("Launcher_cpp constructor");
51   _job_cpt = 0;
52   _job_cpt_mutex = new pthread_mutex_t();
53   pthread_mutex_init(_job_cpt_mutex, NULL);
54 }
55
56 //=============================================================================
57 /*! 
58  * destructor
59  */
60 //=============================================================================
61 Launcher_cpp::~Launcher_cpp()
62 {
63   LAUNCHER_MESSAGE("Launcher_cpp destructor");
64 #ifdef WITH_LIBBATCH
65   std::map<int, Launcher::Job *>::const_iterator it_job;
66   for(it_job = _launcher_job_map.begin(); it_job != _launcher_job_map.end(); it_job++)
67     delete it_job->second;
68   std::map < std::string, Batch::BatchManager_eClient * >::const_iterator it1;
69   for(it1=_batchmap.begin();it1!=_batchmap.end();it1++)
70     delete it1->second;
71 #endif
72
73   pthread_mutex_destroy(_job_cpt_mutex);
74   delete _job_cpt_mutex;
75 }
76
77 #ifdef WITH_LIBBATCH
78
79 //=============================================================================
80 /*!
81  * Add a job into the launcher - check resource and choose one 
82  */ 
83 //=============================================================================
84 void 
85 Launcher_cpp::createJob(Launcher::Job * new_job)
86 {
87   LAUNCHER_MESSAGE("Creating a new job");
88   
89   // First step take a resource
90   std::vector<std::string> ResourceList;
91   resourceParams params = new_job->getResourceRequiredParams();
92   try{
93     ResourceList = _ResManager->GetFittingResources(params);
94   }
95   catch(const ResourcesException &ex){
96     throw LauncherException(ex.msg.c_str());
97   }
98   if (ResourceList.size() == 0)
99   {
100     LAUNCHER_INFOS("No adequate resource found for the job, number " << new_job->getNumber() << " - deleting it");
101     delete new_job;
102     throw LauncherException("No resource found the job");
103   }
104
105   // Second step configure the job with the resource selected - the first of the list
106   ParserResourcesType resource_definition = _ResManager->GetResourcesDescr(ResourceList[0]);
107
108   // Set resource definition to the job
109   // The job will check if the definitions needed
110   try 
111   {
112     new_job->setResourceDefinition(resource_definition);
113   }
114   catch(const LauncherException &ex)
115   {
116     LAUNCHER_INFOS("Error in the definition of the resource, mess: " << ex.msg);
117     delete new_job;
118     throw ex;
119   }
120
121   // Third step search batch manager for the resource into the map -> instanciate one if does not exist
122 #ifdef WITH_LIBBATCH
123   std::string resource_name = resource_definition.Name;
124   std::map<std::string, Batch::BatchManager_eClient *>::const_iterator it = _batchmap.find(resource_name);
125   if(it == _batchmap.end())
126   {
127     try 
128     {
129       // Warning cannot write on one line like this, because map object is constructed before
130       // the method is called...
131       //_batchmap.[resource_name] = FactoryBatchManager(resource_definition);
132       Batch::BatchManager_eClient * batch_client = FactoryBatchManager(resource_definition);
133       _batchmap[resource_name] = batch_client;
134     }
135     catch(const LauncherException &ex)
136     {
137       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.msg);
138       delete new_job;
139       throw ex;
140     }
141     catch(const Batch::EmulationException &ex)
142     {
143       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.message);
144       delete new_job;
145       throw LauncherException(ex.message);
146     }
147     catch(const Batch::InvalidArgumentException &ex)
148     {
149       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.message);
150       throw LauncherException(ex.message);
151     }
152   }
153 #endif
154
155   // Final step - add job to the jobs map
156   pthread_mutex_lock(_job_cpt_mutex);
157   new_job->setNumber(_job_cpt);
158   _job_cpt++;
159   pthread_mutex_unlock(_job_cpt_mutex);
160   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(new_job->getNumber());
161   if (it_job == _launcher_job_map.end())
162     _launcher_job_map[new_job->getNumber()] = new_job;
163   else
164   {
165     LAUNCHER_INFOS("A job as already the same id: " << new_job->getNumber());
166     delete new_job;
167     throw LauncherException("A job as already the same id - job is not created !");
168   }
169   LAUNCHER_MESSAGE("New Job created");
170 }
171
172 //=============================================================================
173 /*!
174  * Launch a job 
175  */ 
176 //=============================================================================
177 void 
178 Launcher_cpp::launchJob(int job_id)
179 {
180   LAUNCHER_MESSAGE("Launch a job");
181
182   // Check if job exist
183   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
184   if (it_job == _launcher_job_map.end())
185   {
186     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
187     throw LauncherException("Cannot find the job, is it created ?");
188   }
189
190   Launcher::Job * job = it_job->second;
191
192   // Check job state (cannot launch a job already launched...)
193   if (job->getState() != "CREATED")
194   {
195     LAUNCHER_INFOS("Bad state of the job: " << job->getState());
196     throw LauncherException("Bad state of the job: " + job->getState());
197   }
198
199   std::string resource_name = job->getResourceDefinition().Name;
200   try {
201     Batch::JobId batch_manager_job_id = _batchmap[resource_name]->submitJob(*(job->getBatchJob()));
202     job->setBatchManagerJobId(batch_manager_job_id);
203     job->setState("QUEUED");
204   }
205   catch(const Batch::EmulationException &ex)
206   {
207     LAUNCHER_INFOS("Job is not launched, exception in submitJob: " << ex.message);
208     throw LauncherException(ex.message.c_str());
209   }
210   LAUNCHER_MESSAGE("Job launched");
211 }
212
213 //=============================================================================
214 /*!
215  * Get job state
216  */ 
217 //=============================================================================
218 const char *
219 Launcher_cpp::getJobState(int job_id)
220 {
221   LAUNCHER_MESSAGE("Get job state");
222
223   // Check if job exist
224   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
225   if (it_job == _launcher_job_map.end())
226   {
227     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
228     throw LauncherException("Cannot find the job, is it created ?");
229   }
230
231   Launcher::Job * job = it_job->second;
232   std::string state = job->updateJobState();
233
234   return state.c_str();
235 }
236
237 //=============================================================================
238 /*!
239  * Get Job result - the result directory could be changed
240  */ 
241 //=============================================================================
242 void
243 Launcher_cpp::getJobResults(int job_id, std::string directory)
244 {
245   LAUNCHER_MESSAGE("Get Job results");
246
247   // Check if job exist
248   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
249   if (it_job == _launcher_job_map.end())
250   {
251     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
252     throw LauncherException("Cannot find the job, is it created ?");
253   }
254
255   Launcher::Job * job = it_job->second;
256   std::string resource_name = job->getResourceDefinition().Name;
257   try 
258   {
259     if (directory != "")
260       _batchmap[resource_name]->importOutputFiles(*(job->getBatchJob()), directory);
261     else
262       _batchmap[resource_name]->importOutputFiles(*(job->getBatchJob()), job->getResultDirectory());
263   }
264   catch(const Batch::EmulationException &ex)
265   {
266     LAUNCHER_INFOS("getJobResult is maybe incomplete, exception: " << ex.message);
267     throw LauncherException(ex.message.c_str());
268   }
269   LAUNCHER_MESSAGE("getJobResult ended");
270 }
271
272 //=============================================================================
273 /*!
274  * Get Job dump state - the result directory could be changed
275  */ 
276 //=============================================================================
277 bool
278 Launcher_cpp::getJobDumpState(int job_id, std::string directory)
279 {
280   bool rtn;
281   LAUNCHER_MESSAGE("Get Job dump state");
282
283   // Check if job exist
284   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
285   if (it_job == _launcher_job_map.end())
286   {
287     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
288     throw LauncherException("Cannot find the job, is it created ?");
289   }
290
291   Launcher::Job * job = it_job->second;
292   std::string resource_name = job->getResourceDefinition().Name;
293   try 
294   {
295     if (directory != "")
296       rtn = _batchmap[resource_name]->importDumpStateFile(*(job->getBatchJob()), directory);
297     else
298       rtn = _batchmap[resource_name]->importDumpStateFile(*(job->getBatchJob()), job->getResultDirectory());
299   }
300   catch(const Batch::EmulationException &ex)
301   {
302     LAUNCHER_INFOS("getJobResult is maybe incomplete, exception: " << ex.message);
303     throw LauncherException(ex.message.c_str());
304   }
305   LAUNCHER_MESSAGE("getJobResult ended");
306   return rtn;
307 }
308
309 //=============================================================================
310 /*!
311  * Remove the job - into the Launcher and its batch manager
312  */ 
313 //=============================================================================
314 void
315 Launcher_cpp::removeJob(int job_id)
316 {
317   LAUNCHER_MESSAGE("Remove Job");
318
319   // Check if job exist
320   std::map<int, Launcher::Job *>::iterator it_job = _launcher_job_map.find(job_id);
321   if (it_job == _launcher_job_map.end())
322   {
323     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
324     throw LauncherException("Cannot find the job, is it created ?");
325   }
326
327   it_job->second->removeJob();
328   delete it_job->second;
329   _launcher_job_map.erase(it_job);
330 }
331
332 //=============================================================================
333 /*! 
334  *  create a launcher job based on a file
335  *  \param xmlExecuteFile     : to define the execution on the batch cluster
336  */
337 //=============================================================================
338 long 
339 Launcher_cpp::createJobWithFile(const std::string xmlExecuteFile, 
340                                 const std::string clusterName)
341 {
342   LAUNCHER_MESSAGE("Begin of Launcher_cpp::createJobWithFile");
343
344   // Parsing xml file
345   ParserLauncherType job_params = ParseXmlFile(xmlExecuteFile);
346
347   // Creating a new job
348   Launcher::Job_Command * new_job = new Launcher::Job_Command();
349
350   std::string cmdFile = Kernel_Utils::GetTmpFileName();  
351 #ifndef WIN32
352   cmdFile += ".sh";
353 #else
354   cmdFile += ".bat";
355 #endif
356   std::ofstream os;
357   os.open(cmdFile.c_str(), std::ofstream::out );
358   os << "#! /bin/sh" << std::endl;
359   os << job_params.Command;
360   os.close();
361
362   new_job->setJobFile(cmdFile);
363   new_job->setLocalDirectory(job_params.RefDirectory);
364   new_job->setWorkDirectory(job_params.MachinesList[clusterName].WorkDirectory);
365   new_job->setEnvFile(job_params.MachinesList[clusterName].EnvFile);
366
367   for(int i=0; i < job_params.InputFile.size(); i++)
368     new_job->add_in_file(job_params.InputFile[i]);
369   for(int i=0; i < job_params.OutputFile.size();i++)
370     new_job->add_out_file(job_params.OutputFile[i]);
371
372   resourceParams p;
373   p.hostname = clusterName;
374   p.name = "";
375   p.OS = "";
376   p.nb_proc = job_params.NbOfProcesses;
377   p.nb_node = 0;
378   p.nb_proc_per_node = 0;
379   p.cpu_clock = 0;
380   p.mem_mb = 0;
381   new_job->setResourceRequiredParams(p);
382
383   createJob(new_job);
384   return new_job->getNumber();
385 }
386
387 //=============================================================================
388 /*!
389  *  Factory to instanciate the good batch manager for choosen cluster.
390  */ 
391 //=============================================================================
392 Batch::BatchManager_eClient *
393 Launcher_cpp::FactoryBatchManager(ParserResourcesType& params)
394 {
395   std::string mpi;
396   Batch::CommunicationProtocolType protocol;
397   Batch::FactBatchManager_eClient* fact;
398
399   int nb_proc_per_node = params.DataForSort._nbOfProcPerNode;
400   std::string hostname = params.HostName;
401
402   switch(params.Protocol)
403   {
404     case rsh:
405       protocol = Batch::RSH;
406       break;
407     case ssh:
408       protocol = Batch::SSH;
409       break;
410     default:
411       throw LauncherException("Unknown protocol for this resource");
412       break;
413   }
414
415   switch(params.mpi)
416   {
417     case lam:
418       mpi = "lam";
419       break;
420     case mpich1:
421       mpi = "mpich1";
422       break;
423     case mpich2:
424       mpi = "mpich2";
425       break;
426     case openmpi:
427       mpi = "openmpi";
428       break;
429     case slurmmpi:
430       mpi = "slurmmpi";
431       break;
432     case prun:
433       mpi = "prun";
434       break;
435     default:
436       mpi = "nompi";
437   }
438
439   const char * bmType;
440   switch( params.Batch )
441   {
442     case pbs:
443       bmType = "ePBS";
444       break;
445     case lsf:
446       bmType = "eLSF";
447       break;
448     case sge:
449       bmType = "eSGE";
450       break;
451     case ccc:
452       bmType = "eCCC";
453       break;
454     case slurm:
455       bmType = "eSLURM";
456       break;
457     case ssh_batch:
458       bmType = "eSSH";
459       break;
460     case ll:
461       bmType = "eLL";
462       break;
463     default:
464       LAUNCHER_MESSAGE("Bad batch description of the resource: Batch = " << params.Batch);
465       throw LauncherException("No batchmanager for that cluster - Bad batch description of the resource");
466   }
467   Batch::BatchManagerCatalog & cata = Batch::BatchManagerCatalog::getInstance();
468   fact = dynamic_cast<Batch::FactBatchManager_eClient*>(cata(bmType));
469   if (fact == NULL) {
470     LAUNCHER_MESSAGE("Cannot find batch manager factory for " << bmType << ". Check your version of libBatch.");
471     throw LauncherException("Cannot find batch manager factory");
472   }
473   LAUNCHER_MESSAGE("Instanciation of batch manager of type: " << bmType);
474   Batch::BatchManager_eClient * batch_client = (*fact)(hostname.c_str(), params.UserName.c_str(),
475                                                        protocol, mpi.c_str(), nb_proc_per_node);
476   return batch_client;
477 }
478
479 //----------------------------------------------------------
480 // Without LIBBATCH - Launcher_cpp do nothing...
481 //----------------------------------------------------------
482 #else
483
484 void 
485 Launcher_cpp::createJob(Launcher::Job * new_job)
486 {
487   LAUNCHER_INFOS("Launcher compiled without LIBBATCH - cannot create a job !!!");
488   delete new_job;
489   throw LauncherException("Method Launcher_cpp::createJob is not available "
490                           "(libBatch was not present at compilation time)");
491 }
492
493 void 
494 Launcher_cpp::launchJob(int job_id)
495 {
496   LAUNCHER_INFOS("Launcher compiled without LIBBATCH - cannot launch a job !!!");
497   throw LauncherException("Method Launcher_cpp::launchJob is not available "
498                           "(libBatch was not present at compilation time)");
499 }
500
501 const char *
502 Launcher_cpp::getJobState(int job_id)
503 {
504   LAUNCHER_INFOS("Launcher compiled without LIBBATCH - cannot get job state!!!");
505   throw LauncherException("Method Launcher_cpp::getJobState is not available "
506                           "(libBatch was not present at compilation time)");
507 }
508
509 void
510 Launcher_cpp::getJobResults(int job_id, std::string directory)
511 {
512   LAUNCHER_INFOS("Launcher compiled without LIBBATCH - cannot get job results!!!");
513   throw LauncherException("Method Launcher_cpp::getJobResults is not available "
514                           "(libBatch was not present at compilation time)");
515 }
516
517 bool
518 Launcher_cpp::getJobDumpState(int job_id, std::string directory)
519 {
520   LAUNCHER_INFOS("Launcher compiled without LIBBATCH - cannot get job dump state!!!");
521   throw LauncherException("Method Launcher_cpp::getJobDumpState is not available "
522                           "(libBatch was not present at compilation time)");
523 }
524
525 void
526 Launcher_cpp::removeJob(int job_id)
527 {
528   LAUNCHER_INFOS("Launcher compiled without LIBBATCH - cannot remove job!!!");
529   throw LauncherException("Method Launcher_cpp::removeJob is not available "
530                           "(libBatch was not present at compilation time)");
531 }
532
533 long 
534 Launcher_cpp::createJobWithFile( const std::string xmlExecuteFile, std::string clusterName)
535 {
536   throw LauncherException("Method Launcher_cpp::createJobWithFile is not available "
537                           "(libBatch was not present at compilation time)");
538   return 0;
539 }
540
541 #endif
542
543 ParserLauncherType 
544 Launcher_cpp::ParseXmlFile(std::string xmlExecuteFile)
545 {
546   ParserLauncherType job_params;
547   SALOME_Launcher_Handler * handler = new SALOME_Launcher_Handler(job_params);
548
549   const char* aFilePath = xmlExecuteFile.c_str();
550   FILE* aFile = fopen(aFilePath, "r");
551   if (aFile != NULL)
552   {
553     xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
554     if (aDoc != NULL)
555       handler->ProcessXmlDocument(aDoc);
556     else
557     {
558       std::string message = "ResourcesManager_cpp: could not parse file: " + xmlExecuteFile;
559       LAUNCHER_MESSAGE(message);
560       delete handler;
561       throw LauncherException(message);
562     }
563     // Free the document
564     xmlFreeDoc(aDoc);
565     fclose(aFile);
566   }
567   else
568   {
569     std::string message = "ResourcesManager_cpp: file is not readable: " + xmlExecuteFile;
570     LAUNCHER_MESSAGE(message);
571     delete handler;
572     throw LauncherException(message);
573   }
574
575   // Return
576   delete handler;
577   return job_params;
578 }
579
580 std::map<int, Launcher::Job *>
581 Launcher_cpp::getJobs()
582 {
583   return _launcher_job_map;
584 }
585
586 void 
587 Launcher_cpp::checkFactoryForResource(const std::string & resource_name)
588 {
589   // Step 1: Check if resource exist in the resource manager
590   ParserResourcesType resource_definition;
591   try
592   {
593     resource_definition = _ResManager->GetResourcesDescr(resource_name);
594   }
595   catch(const ResourcesException &ex)
596   {
597     LAUNCHER_INFOS(ex.msg);
598     throw LauncherException(ex.msg);
599   }
600
601   // Step 2: We can now add a Factory is the resource is correctly define
602 #ifdef WITH_LIBBATCH
603   std::map<std::string, Batch::BatchManager_eClient *>::const_iterator it = _batchmap.find(resource_name);
604   if(it == _batchmap.end())
605   {
606     try
607     {
608       // Warning cannot write on one line like this, because map object is constructed before
609       // the method is called...
610       //_batchmap.[resource_name] = FactoryBatchManager(resource_definition);
611       Batch::BatchManager_eClient * batch_client = FactoryBatchManager(resource_definition);
612       _batchmap[resource_name] = batch_client;
613     }
614     catch(const LauncherException &ex)
615     {
616       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.msg);
617       throw ex;
618     }
619     catch(const Batch::EmulationException &ex)
620     {
621       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.message);
622       throw LauncherException(ex.message);
623     }
624     catch(const Batch::InvalidArgumentException &ex)
625     {
626       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.message);
627       throw LauncherException(ex.message);
628     }
629   }
630 #endif
631 }
632
633 void 
634 Launcher_cpp::addJobDirectlyToMap(Launcher::Job * new_job, const std::string job_reference)
635 {
636   // Step 1: check if resource is already in the map
637   std::string resource_name = new_job->getResourceDefinition().Name;
638   checkFactoryForResource(resource_name);
639   ParserResourcesType resource_definition = _ResManager->GetResourcesDescr(resource_name);
640   new_job->setResourceDefinition(resource_definition);
641
642   // Step 2: add the job to the batch manager
643 #ifdef WITH_LIBBATCH
644   try
645   {
646     Batch::JobId batch_manager_job_id = _batchmap[resource_name]->addJob(*(new_job->getBatchJob()), 
647                                                                          job_reference);
648     new_job->setBatchManagerJobId(batch_manager_job_id);
649   }
650   catch(const Batch::EmulationException &ex)
651   {
652     LAUNCHER_INFOS("Job is not launched, exception in submitJob: " << ex.message);
653     throw LauncherException(ex.message.c_str());
654   }
655
656   // Step 3: add job to launcher map
657   pthread_mutex_lock(_job_cpt_mutex);
658   new_job->setNumber(_job_cpt);
659   _job_cpt++;
660   pthread_mutex_unlock(_job_cpt_mutex);
661   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(new_job->getNumber());
662   if (it_job == _launcher_job_map.end())
663     _launcher_job_map[new_job->getNumber()] = new_job;
664   else
665   {
666     LAUNCHER_INFOS("A job as already the same id: " << new_job->getNumber());
667     delete new_job;
668     throw LauncherException("A job as already the same id - job is not created !");
669   }
670   LAUNCHER_MESSAGE("New job added");
671 #endif
672 }