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