Salome HOME
Merge from V5_1_main 10/06/2010
[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_FactBatchManager_eCCC.hxx>
26 #include <Batch/Batch_FactBatchManager_eLSF.hxx>
27 #include <Batch/Batch_FactBatchManager_ePBS.hxx>
28 #include <Batch/Batch_BatchManager_eClient.hxx>
29 #include <Batch/Batch_FactBatchManager_eSGE.hxx>
30 #include <Batch/Batch_FactBatchManager_eSSH.hxx>
31 #endif
32
33 #include "Basics_Utils.hxx"
34 #include "Basics_DirUtils.hxx"
35 #include "SALOME_Launcher_Handler.hxx"
36 #include "Launcher.hxx"
37 #include "Launcher_Job_Command.hxx"
38 #include <iostream>
39 #include <sstream>
40 #include <sys/stat.h>
41 #include <time.h>
42
43 //=============================================================================
44 /*! 
45  *  Constructor
46  *  \param orb
47  *  Define a CORBA single thread policy for the server, which avoid to deal
48  *  with non thread-safe usage like Change_Directory in SALOME naming service
49  */
50 //=============================================================================
51 Launcher_cpp::Launcher_cpp()
52 {
53   LAUNCHER_MESSAGE("Launcher_cpp constructor");
54   _job_cpt = 0;
55   _job_cpt_mutex = new pthread_mutex_t();
56   pthread_mutex_init(_job_cpt_mutex, NULL);
57 }
58
59 //=============================================================================
60 /*! 
61  * destructor
62  */
63 //=============================================================================
64 Launcher_cpp::~Launcher_cpp()
65 {
66   LAUNCHER_MESSAGE("Launcher_cpp destructor");
67 #ifdef WITH_LIBBATCH
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   std::map<int, Launcher::Job *>::const_iterator it_job;
72   for(it_job = _launcher_job_map.begin(); it_job != _launcher_job_map.end(); it_job++)
73     delete it_job->second;
74 #endif
75
76   pthread_mutex_destroy(_job_cpt_mutex);
77   delete _job_cpt_mutex;
78 }
79
80 #ifdef WITH_LIBBATCH
81
82 //=============================================================================
83 /*!
84  * Add a job into the launcher - check resource and choose one 
85  */ 
86 //=============================================================================
87 void 
88 Launcher_cpp::createJob(Launcher::Job * new_job)
89 {
90   LAUNCHER_MESSAGE("Creating a new job");
91   
92   // First step take a resource
93   std::vector<std::string> ResourceList;
94   resourceParams params = new_job->getResourceRequiredParams();
95   try{
96     ResourceList = _ResManager->GetFittingResources(params);
97   }
98   catch(const ResourcesException &ex){
99     throw LauncherException(ex.msg.c_str());
100   }
101   if (ResourceList.size() == 0)
102   {
103     LAUNCHER_INFOS("No adequate resource found for the job, number " << new_job->getNumber() << " - deleting it");
104     delete new_job;
105     throw LauncherException("No resource found the job");
106   }
107
108   // Second step configure the job with the resource selected - the first of the list
109   ParserResourcesType resource_definition = _ResManager->GetResourcesDescr(ResourceList[0]);
110
111   // Set resource definition to the job
112   // The job will check if the definitions needed
113   try 
114   {
115     new_job->setResourceDefinition(resource_definition);
116   }
117   catch(const LauncherException &ex)
118   {
119     LAUNCHER_INFOS("Error in the definition of the resource, mess: " << ex.msg);
120     delete new_job;
121     throw ex;
122   }
123
124   // Third step search batch manager for the resource into the map -> instanciate one if does not exist
125   std::string resource_name = resource_definition.Name;
126   std::map<std::string, Batch::BatchManager_eClient *>::const_iterator it = _batchmap.find(resource_name);
127   if(it == _batchmap.end())
128   {
129     try 
130     {
131       // Warning cannot write on one line like this, because map object is constructed before
132       // the method is called...
133       //_batchmap.[resource_name] = FactoryBatchManager(resource_definition);
134       Batch::BatchManager_eClient * batch_client = FactoryBatchManager(resource_definition);
135       _batchmap[resource_name] = batch_client;
136     }
137     catch(const LauncherException &ex)
138     {
139       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.msg);
140       delete new_job;
141       throw ex;
142     }
143     catch(const Batch::EmulationException &ex)
144     {
145       LAUNCHER_INFOS("Error during creation of the batch manager of the resource, mess: " << ex.message);
146       delete new_job;
147       throw LauncherException(ex.message);
148     }
149   }
150
151
152   // Final step - add job to the jobs map
153   pthread_mutex_lock(_job_cpt_mutex);
154   new_job->setNumber(_job_cpt);
155   _job_cpt++;
156   pthread_mutex_unlock(_job_cpt_mutex);
157   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(new_job->getNumber());
158   if (it_job == _launcher_job_map.end())
159     _launcher_job_map[new_job->getNumber()] = new_job;
160   else
161   {
162     LAUNCHER_INFOS("A job as already the same id: " << new_job->getNumber());
163     delete new_job;
164     throw LauncherException("A job as already the same id - job is not created !");
165   }
166   LAUNCHER_MESSAGE("New Job created");
167 }
168
169 //=============================================================================
170 /*!
171  * Launch a job 
172  */ 
173 //=============================================================================
174 void 
175 Launcher_cpp::launchJob(int job_id)
176 {
177   LAUNCHER_MESSAGE("Launch a job");
178
179   // Check if job exist
180   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
181   if (it_job == _launcher_job_map.end())
182   {
183     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
184     throw LauncherException("Cannot find the job, is it created ?");
185   }
186
187   Launcher::Job * job = it_job->second;
188
189   // Check job state (cannot launch a job already launched...)
190   if (job->getState() != "CREATED")
191   {
192     LAUNCHER_INFOS("Bad state of the job: " << job->getState());
193     throw LauncherException("Bad state of the job: " + job->getState());
194   }
195
196   std::string resource_name = job->getResourceDefinition().Name;
197   try {
198     Batch::JobId batch_manager_job_id = _batchmap[resource_name]->submitJob(*(job->getBatchJob()));
199     job->setBatchManagerJobId(batch_manager_job_id);
200     job->setState("QUEUED");
201   }
202   catch(const Batch::EmulationException &ex)
203   {
204     LAUNCHER_INFOS("Job is not launched, exception in submitJob: " << ex.message);
205     throw LauncherException(ex.message.c_str());
206   }
207   LAUNCHER_MESSAGE("Job launched");
208 }
209
210 //=============================================================================
211 /*!
212  * Get job state
213  */ 
214 //=============================================================================
215 const char *
216 Launcher_cpp::getJobState(int job_id)
217 {
218   LAUNCHER_MESSAGE("Get job state");
219
220   // Check if job exist
221   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
222   if (it_job == _launcher_job_map.end())
223   {
224     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
225     throw LauncherException("Cannot find the job, is it created ?");
226   }
227
228   Launcher::Job * job = it_job->second;
229   std::string state = job->updateJobState();
230
231   return state.c_str();
232 }
233
234 //=============================================================================
235 /*!
236  * Get Job result - the result directory could be changed
237  */ 
238 //=============================================================================
239 void
240 Launcher_cpp::getJobResults(int job_id, std::string directory)
241 {
242   LAUNCHER_MESSAGE("Get Job results");
243
244   // Check if job exist
245   std::map<int, Launcher::Job *>::const_iterator it_job = _launcher_job_map.find(job_id);
246   if (it_job == _launcher_job_map.end())
247   {
248     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
249     throw LauncherException("Cannot find the job, is it created ?");
250   }
251
252   Launcher::Job * job = it_job->second;
253   std::string resource_name = job->getResourceDefinition().Name;
254   try 
255   {
256     if (directory != "")
257       _batchmap[resource_name]->importOutputFiles(*(job->getBatchJob()), directory);
258     else
259       _batchmap[resource_name]->importOutputFiles(*(job->getBatchJob()), job->getResultDirectory());
260   }
261   catch(const Batch::EmulationException &ex)
262   {
263     LAUNCHER_INFOS("getJobResult is maybe incomplete, exception: " << ex.message);
264     throw LauncherException(ex.message.c_str());
265   }
266   LAUNCHER_MESSAGE("getJobResult ended");
267 }
268
269 //=============================================================================
270 /*!
271  * Remove the job - into the Launcher and its batch manager
272  */ 
273 //=============================================================================
274 void
275 Launcher_cpp::removeJob(int job_id)
276 {
277   LAUNCHER_MESSAGE("Remove Job");
278
279   // Check if job exist
280   std::map<int, Launcher::Job *>::iterator it_job = _launcher_job_map.find(job_id);
281   if (it_job == _launcher_job_map.end())
282   {
283     LAUNCHER_INFOS("Cannot find the job, is it created ? job number: " << job_id);
284     throw LauncherException("Cannot find the job, is it created ?");
285   }
286
287   delete it_job->second;
288   _launcher_job_map.erase(it_job);
289 }
290
291 //=============================================================================
292 /*! 
293  *  create a launcher job based on a file
294  *  \param xmlExecuteFile     : to define the execution on the batch cluster
295  */
296 //=============================================================================
297 long 
298 Launcher_cpp::createJobWithFile(const std::string xmlExecuteFile, 
299                                 const std::string clusterName)
300 {
301   LAUNCHER_MESSAGE("Begin of Launcher_cpp::createJobWithFile");
302
303   // Parsing xml file
304   ParserLauncherType job_params = ParseXmlFile(xmlExecuteFile);
305
306   // Creating a new job
307   Launcher::Job_Command * new_job = new Launcher::Job_Command();
308
309   std::string cmdFile = Kernel_Utils::GetTmpFileName();  
310 #ifndef WIN32
311   cmdFile += ".sh";
312 #else
313   cmdFile += ".bat";
314 #endif
315   std::ofstream os;
316   os.open(cmdFile.c_str(), std::ofstream::out );
317   os << "#! /bin/sh" << std::endl;
318   os << job_params.Command;
319   os.close();
320
321   new_job->setJobFile(cmdFile);
322   new_job->setLocalDirectory(job_params.RefDirectory);
323   new_job->setWorkDirectory(job_params.MachinesList[clusterName].WorkDirectory);
324   new_job->setEnvFile(job_params.MachinesList[clusterName].EnvFile);
325
326   for(int i=0; i < job_params.InputFile.size(); i++)
327     new_job->add_in_file(job_params.InputFile[i]);
328   for(int i=0; i < job_params.OutputFile.size();i++)
329     new_job->add_out_file(job_params.OutputFile[i]);
330
331   resourceParams p;
332   p.hostname = clusterName;
333   p.name = "";
334   p.OS = "";
335   p.nb_proc = job_params.NbOfProcesses;
336   p.nb_node = 0;
337   p.nb_proc_per_node = 0;
338   p.cpu_clock = 0;
339   p.mem_mb = 0;
340   new_job->setResourceRequiredParams(p);
341
342   createJob(new_job);
343   return new_job->getNumber();
344 }
345
346 //=============================================================================
347 /*!
348  *  Factory to instanciate the good batch manager for choosen cluster.
349  */ 
350 //=============================================================================
351 Batch::BatchManager_eClient *
352 Launcher_cpp::FactoryBatchManager(ParserResourcesType& params)
353 {
354   std::string mpi;
355   Batch::CommunicationProtocolType protocol;
356   Batch::FactBatchManager_eClient* fact;
357
358   int nb_proc_per_node = params.DataForSort._nbOfProcPerNode;
359   std::string hostname = params.HostName;
360
361   switch(params.Protocol)
362   {
363     case rsh:
364       protocol = Batch::RSH;
365       break;
366     case ssh:
367       protocol = Batch::SSH;
368       break;
369     default:
370       throw LauncherException("Unknown protocol for this resource");
371       break;
372   }
373
374   switch(params.mpi)
375   {
376     case lam:
377       mpi = "lam";
378       break;
379     case mpich1:
380       mpi = "mpich1";
381       break;
382     case mpich2:
383       mpi = "mpich2";
384       break;
385     case openmpi:
386       mpi = "openmpi";
387       break;
388     case slurm:
389       mpi = "slurm";
390       break;
391     case prun:
392       mpi = "prun";
393       break;
394     default:
395       mpi = "nompi";
396   }
397
398   std::string message = "Instanciation of batch manager of type: ";
399   switch( params.Batch )
400   {
401     case pbs:
402       message += "ePBS";
403       fact = new Batch::FactBatchManager_ePBS;
404       break;
405     case lsf:
406       message += "eLSF";
407       fact = new Batch::FactBatchManager_eLSF;
408       break;
409     case sge:
410       message += "eSGE";
411       fact = new Batch::FactBatchManager_eSGE;
412       break;
413     case ccc:
414       message += "eCCC";
415       fact = new Batch::FactBatchManager_eCCC;
416       break;
417     case ssh_batch:
418       message += "eSSH";
419       fact = new Batch::FactBatchManager_eSSH;
420       break;
421     default:
422       LAUNCHER_MESSAGE("Bad batch description of the resource: Batch = " << params.Batch);
423       throw LauncherException("No batchmanager for that cluster - Bad batch description of the resource");
424   }
425   LAUNCHER_MESSAGE(message);
426   return (*fact)(hostname.c_str(), protocol, mpi.c_str(), nb_proc_per_node);
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