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