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