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