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