Salome HOME
Join modifications from BR_Dev_For_4_0 tag V4_1_1.
[modules/kernel.git] / src / ResourcesManager / SALOME_ResourcesManager.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 // 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either 
7 // version 2.1 of the License.
8 // 
9 // This library is distributed in the hope that it will be useful 
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public  
15 // License along with this library; if not, write to the Free Software 
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20 #include "SALOME_ResourcesManager.hxx" 
21 #include "Utils_ExceptHandlers.hxx"
22 #include "Utils_CorbaException.hxx"
23 #include "OpUtil.hxx"
24
25 #include <stdlib.h>
26 #ifndef WNT
27 #include <unistd.h>
28 #else
29 #include <io.h>
30 #include <process.h>
31 #endif
32 #include <fstream>
33 #include <iostream>
34 #include <sstream>
35 #include <string.h>
36 #include <map>
37 #include <list>
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include "utilities.h"
42
43 #define MAX_SIZE_FOR_HOSTNAME 256;
44
45 using namespace std;
46
47 const char *SALOME_ResourcesManager::_ResourcesManagerNameInNS = "/ResourcesManager";
48
49 //=============================================================================
50 /*!
51  * just for test
52  */ 
53 //=============================================================================
54
55 SALOME_ResourcesManager::
56 SALOME_ResourcesManager(CORBA::ORB_ptr orb, 
57                         PortableServer::POA_var poa, 
58                         SALOME_NamingService *ns,
59                         const char *xmlFilePath) :
60     _path_resources(xmlFilePath)
61 {
62   MESSAGE("constructor");
63   _NS = ns;
64   _orb = CORBA::ORB::_duplicate(orb) ;
65   _poa = PortableServer::POA::_duplicate(poa) ;
66   PortableServer::ObjectId_var id = _poa->activate_object(this);
67   CORBA::Object_var obj = _poa->id_to_reference(id);
68   Engines::SalomeLauncher_var refContMan =
69     Engines::SalomeLauncher::_narrow(obj);
70
71   _NS->Register(refContMan,_ResourcesManagerNameInNS);
72   _MpiStarted = false;
73   MESSAGE("constructor end");
74 }
75
76 //=============================================================================
77 /*!
78  *  Standard constructor, parse resource file.
79  *  - if ${APPLI} exists in environment,
80  *    look for ${HOME}/${APPLI}/CatalogResources.xml
81  *  - else look for default:
82  *    ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
83  *  - parse XML resource file.
84  */ 
85 //=============================================================================
86
87 SALOME_ResourcesManager::SALOME_ResourcesManager(CORBA::ORB_ptr orb, 
88                                                  PortableServer::POA_var poa, 
89                                                  SALOME_NamingService *ns)
90 {
91   MESSAGE("constructor");
92   _NS = ns;
93   _orb = CORBA::ORB::_duplicate(orb) ;
94   _poa = PortableServer::POA::_duplicate(poa) ;
95   PortableServer::ObjectId_var id = _poa->activate_object(this);
96   CORBA::Object_var obj = _poa->id_to_reference(id);
97   Engines::ResourcesManager_var refContMan = Engines::ResourcesManager::_narrow(obj);
98   _NS->Register(refContMan,_ResourcesManagerNameInNS);
99
100   _isAppliSalomeDefined = (getenv("APPLI") != 0);
101   _MpiStarted = false;
102
103   if (_isAppliSalomeDefined)
104     {
105       _path_resources = getenv("HOME");
106       _path_resources += "/";
107       _path_resources += getenv("APPLI");
108       _path_resources += "/CatalogResources.xml";
109     }
110
111   else
112     {
113       _path_resources = getenv("KERNEL_ROOT_DIR");
114       _path_resources += "/share/salome/resources/kernel/CatalogResources.xml";
115     }
116
117   ParseXmlFile();
118   MESSAGE("constructor end");
119 }
120
121 //=============================================================================
122 /*!
123  *  Standard Destructor
124  */ 
125 //=============================================================================
126
127 SALOME_ResourcesManager::~SALOME_ResourcesManager()
128 {
129   MESSAGE("destructor");
130 }
131
132
133 //=============================================================================
134 /*! CORBA method:
135  *  shutdown all the containers, then the ContainerManager servant
136  */
137 //=============================================================================
138
139 void SALOME_ResourcesManager::Shutdown()
140 {
141   MESSAGE("Shutdown");
142   _NS->Destroy_Name(_ResourcesManagerNameInNS);
143   PortableServer::ObjectId_var oid = _poa->servant_to_id(this);
144   _poa->deactivate_object(oid);
145   //_remove_ref();
146 }
147
148 //=============================================================================
149 /*!
150  *  get the list of name of ressources fitting for the specified module.
151  *  If hostname specified, check it is local or known in resources catalog.
152  *
153  *  Else
154  *  - select first machines with corresponding OS (all machines if
155  *    parameter OS empty),
156  *  - then select the sublist of machines on witch the module is known
157  *    (if the result is empty, that probably means that the inventory of
158  *    modules is probably not done, so give complete list from previous step)
159  */ 
160 //=============================================================================
161
162 Engines::MachineList *
163 SALOME_ResourcesManager::GetFittingResources(const Engines::MachineParameters& params,
164                                              const Engines::CompoList& componentList)
165 //throw(SALOME_Exception)
166 {
167 //   MESSAGE("ResourcesManager::GetFittingResources");
168   vector <std::string> vec;
169   Engines::MachineList *ret=new Engines::MachineList;
170
171   try{
172     // --- To be sure that we search in a correct list.
173     ParseXmlFile();
174
175     const char *hostname = (const char *)params.hostname;
176     MESSAGE("GetFittingResources " << hostname << " " << GetHostname().c_str());
177
178     if (hostname[0] != '\0')
179       {
180 //       MESSAGE("ResourcesManager::GetFittingResources : hostname specified" );
181
182         if ( strcmp(hostname, "localhost") == 0 ||
183              strcmp(hostname, GetHostname().c_str()) == 0 )
184           {
185             //           MESSAGE("ResourcesManager::GetFittingResources : localhost" );
186             vec.push_back(GetHostname().c_str());
187             //    MESSAGE("ResourcesManager::GetFittingResources : " << vec.size());
188           }
189         
190         else if (_resourcesList.find(hostname) != _resourcesList.end())
191           {
192             // --- params.hostname is in the list of resources so return it.
193             vec.push_back(hostname);
194           }
195         
196         else
197           {
198             // Cas d'un cluster: nombre de noeuds > 1
199             int cpt=0;
200             for (map<string, ParserResourcesType>::const_iterator iter = _resourcesList.begin(); iter != _resourcesList.end(); iter++){
201               if( (*iter).second.DataForSort._nbOfNodes > 1 ){
202                 if( strncmp(hostname,(*iter).first.c_str(),strlen(hostname)) == 0 ){
203                   vec.push_back((*iter).first.c_str());
204                   //cout << "SALOME_ResourcesManager::GetFittingResources vector["
205                   //     << cpt << "] = " << (*iter).first.c_str() << endl ;
206                   cpt++;
207                 }
208               }
209             }
210             if(cpt==0){
211               // --- user specified an unknown hostame so notify him.
212               MESSAGE("ResourcesManager::GetFittingResources : SALOME_Exception");
213               throw SALOME_Exception("unknown host");
214             }
215           }
216       }
217     
218     else
219       // --- Search for available resources sorted by priority
220       {
221         SelectOnlyResourcesWithOS(vec, params.OS);
222         
223         KeepOnlyResourcesWithModule(vec, componentList);
224         
225         if (vec.size() == 0)
226           SelectOnlyResourcesWithOS(vec, params.OS);
227         
228         // --- set wanted parameters
229         ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
230         
231         ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
232         
233         ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
234         
235         ResourceDataToSort::_memInMBWanted = params.mem_mb;
236         
237         // --- end of set
238         
239         list<ResourceDataToSort> li;
240         
241         for (vector<string>::iterator iter = vec.begin();
242            iter != vec.end();
243              iter++)
244           li.push_back(_resourcesList[(*iter)].DataForSort);
245         
246         li.sort();
247         
248         unsigned int i = 0;
249         
250         for (list<ResourceDataToSort>::iterator iter2 = li.begin();
251              iter2 != li.end();
252              iter2++)
253           vec[i++] = (*iter2)._hostName;
254       }
255     
256     //  MESSAGE("ResourcesManager::GetFittingResources : return" << ret.size());
257     ret->length(vec.size());
258     for(unsigned int i=0;i<vec.size();i++)
259       (*ret)[i]=(vec[i]).c_str();
260
261   }
262   catch(const SALOME_Exception &ex)
263     {
264       INFOS("Caught exception.");
265       THROW_SALOME_CORBA_EXCEPTION(ex.what(),SALOME::BAD_PARAM);
266       //return ret;
267     }  
268
269   return ret;
270 }
271
272 //=============================================================================
273 /*!
274  *  add an entry in the ressources catalog  xml file.
275  *  Return 0 if OK (KERNEL found in new resources modules) else throw exception
276  */ 
277 //=============================================================================
278
279 int
280 SALOME_ResourcesManager::
281 AddResourceInCatalog(const Engines::MachineParameters& paramsOfNewResources,
282                      const vector<string>& modulesOnNewResources,
283                      const char *alias,
284                      const char *userName,
285                      AccessModeType mode,
286                      AccessProtocolType prot)
287 throw(SALOME_Exception)
288 {
289   vector<string>::const_iterator iter = find(modulesOnNewResources.begin(),
290                                              modulesOnNewResources.end(),
291                                              "KERNEL");
292
293   if (iter != modulesOnNewResources.end())
294     {
295       ParserResourcesType newElt;
296       newElt.DataForSort._hostName = paramsOfNewResources.hostname;
297       newElt.Alias = alias;
298       newElt.Protocol = prot;
299       newElt.Mode = mode;
300       newElt.UserName = userName;
301       newElt.ModulesList = modulesOnNewResources;
302       newElt.OS = paramsOfNewResources.OS;
303       newElt.DataForSort._memInMB = paramsOfNewResources.mem_mb;
304       newElt.DataForSort._CPUFreqMHz = paramsOfNewResources.cpu_clock;
305       newElt.DataForSort._nbOfNodes = paramsOfNewResources.nb_node;
306       newElt.DataForSort._nbOfProcPerNode =
307         paramsOfNewResources.nb_proc_per_node;
308       _resourcesList[newElt.DataForSort._hostName] = newElt;
309       return 0;
310     }
311
312   else
313     throw SALOME_Exception("KERNEL is not present in this resource");
314 }
315
316 //=============================================================================
317 /*!
318  *  Deletes a resource from the catalog
319  */ 
320 //=============================================================================
321
322 void SALOME_ResourcesManager::DeleteResourceInCatalog(const char *hostname)
323 {
324   _resourcesList.erase(hostname);
325 }
326
327 //=============================================================================
328 /*!
329  *  write the current data in memory in file.
330  */ 
331 //=============================================================================
332
333 void SALOME_ResourcesManager::WriteInXmlFile()
334 {
335   const char* aFilePath = _path_resources.c_str();
336   
337   FILE* aFile = fopen(aFilePath, "w");
338
339   if (aFile == NULL)
340     {
341       INFOS("Error opening file !");
342       return;
343     }
344   
345   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
346   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
347
348   SALOME_ResourcesCatalog_Handler* handler =
349     new SALOME_ResourcesCatalog_Handler(_resourcesList);
350   handler->PrepareDocToXmlFile(aDoc);
351   delete handler;
352
353   int isOk = xmlSaveFile(aFilePath, aDoc);
354   
355   if (!isOk)
356     INFOS("Error while XML file saving.");
357   
358   // Free the document
359   xmlFreeDoc(aDoc);
360
361   fclose(aFile);
362   
363   MESSAGE("WRITING DONE!");
364 }
365
366 //=============================================================================
367 /*!
368  *  parse the data type catalog
369  */ 
370 //=============================================================================
371
372 const MapOfParserResourcesType& SALOME_ResourcesManager::ParseXmlFile()
373 {
374   SALOME_ResourcesCatalog_Handler* handler =
375     new SALOME_ResourcesCatalog_Handler(_resourcesList);
376
377   const char* aFilePath = _path_resources.c_str();
378   FILE* aFile = fopen(aFilePath, "r");
379   
380   if (aFile != NULL)
381     {
382       xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
383       
384       if (aDoc != NULL)
385         handler->ProcessXmlDocument(aDoc);
386       else
387         INFOS("ResourcesManager: could not parse file "<<aFilePath);
388       
389       // Free the document
390       xmlFreeDoc(aDoc);
391
392       fclose(aFile);
393     }
394   else
395     INFOS("ResourcesManager: file "<<aFilePath<<" is not readable.");
396   
397   delete handler;
398
399   return _resourcesList;
400 }
401
402 //=============================================================================
403 /*!
404  *   consult the content of the list
405  */ 
406 //=============================================================================
407
408 const MapOfParserResourcesType& SALOME_ResourcesManager::GetList() const
409   {
410     return _resourcesList;
411   }
412
413
414 //=============================================================================
415 /*!
416  *  dynamically obtains the first machines
417  */ 
418 //=============================================================================
419
420 char *
421 SALOME_ResourcesManager::FindFirst(const Engines::MachineList& listOfMachines)
422 {
423   return CORBA::string_dup(_dynamicResourcesSelecter.FindFirst(listOfMachines).c_str());
424 }
425
426 //=============================================================================
427 /*!
428  *  dynamically obtains the best machines
429  */ 
430 //=============================================================================
431
432 string
433 SALOME_ResourcesManager::FindNext(const Engines::MachineList& listOfMachines)
434 {
435   return _dynamicResourcesSelecter.FindNext(listOfMachines,_resourcesList,_NS);
436 }
437 //=============================================================================
438 /*!
439  *  dynamically obtains the best machines
440  */ 
441 //=============================================================================
442
443 string
444 SALOME_ResourcesManager::FindBest(const Engines::MachineList& listOfMachines)
445 {
446   return _dynamicResourcesSelecter.FindBest(listOfMachines);
447 }
448
449 //=============================================================================
450 /*!
451  *  This is no longer valid (C++ container are also python containers)
452  */ 
453 //=============================================================================
454
455 bool isPythonContainer(const char* ContainerName)
456 {
457   bool ret = false;
458   int len = strlen(ContainerName);
459
460   if (len >= 2)
461     if (strcmp(ContainerName + len - 2, "Py") == 0)
462       ret = true;
463
464   return ret;
465 }
466
467
468 //=============================================================================
469 /*!
470  *  Builds the script to be launched
471  *
472  *  If SALOME Application not defined ($APPLI),
473  *  see BuildTempFileToLaunchRemoteContainer()
474  *
475  *  Else rely on distant configuration. Command is under the form (example):
476  *  ssh user@machine distantPath/runRemote.sh hostNS portNS workingdir \
477  *                   SALOME_Container containerName &"
478
479  *  - where user is ommited if not specified in CatalogResources,
480  *  - where distant path is always relative to user@machine $HOME, and
481  *    equal to $APPLI if not specified in CatalogResources,
482  *  - where hostNS is the hostname of CORBA naming server (set by scripts to
483  *    use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
484  *  - where portNS is the port used by CORBA naming server (set by scripts to
485  *    use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
486  *  - where workingdir is the requested working directory for the container
487  */ 
488 //=============================================================================
489
490 string
491 SALOME_ResourcesManager::BuildCommandToLaunchRemoteContainer
492 (const string& machine,
493  const Engines::MachineParameters& params, const long id)
494 {
495   string command;
496   int nbproc;
497   char idc[3*sizeof(long)];
498           
499   if ( ! _isAppliSalomeDefined )
500     command = BuildTempFileToLaunchRemoteContainer(machine, params);
501
502   else
503     {
504       const ParserResourcesType& resInfo = _resourcesList[machine];
505
506       if (params.isMPI)
507         {
508           if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
509             nbproc = 1;
510           else if ( params.nb_node == 0 )
511             nbproc = params.nb_proc_per_node;
512           else if ( params.nb_proc_per_node == 0 )
513             nbproc = params.nb_node;
514           else
515             nbproc = params.nb_node * params.nb_proc_per_node;
516         }
517
518       // "ssh user@machine distantPath/runRemote.sh hostNS portNS workingdir \
519       //  SALOME_Container containerName &"
520
521       if (resInfo.Protocol == rsh)
522         command = "rsh ";
523       else if (resInfo.Protocol == ssh)
524         command = "ssh ";
525       else
526         throw SALOME_Exception("Unknown protocol");
527
528       if (resInfo.UserName != "")
529         {
530           command += resInfo.UserName;
531           command += "@";
532         }
533
534       command += machine;
535       command += " ";
536
537       if (resInfo.AppliPath != "")
538         command += resInfo.AppliPath; // path relative to user@machine $HOME
539       else
540         {
541           ASSERT(getenv("APPLI"));
542           command += getenv("APPLI"); // path relative to user@machine $HOME
543         }
544
545       command += "/runRemote.sh ";
546
547       ASSERT(getenv("NSHOST")); 
548       command += getenv("NSHOST"); // hostname of CORBA name server
549
550       command += " ";
551       ASSERT(getenv("NSPORT"));
552       command += getenv("NSPORT"); // port of CORBA name server
553
554       command += " '";
555       std::string wdir=params.workingdir.in();
556       if(wdir == "$TEMPDIR")
557         wdir="\\$TEMPDIR";
558       command += wdir; // requested working directory
559       command += "'"; 
560
561       if(params.isMPI)
562         {
563           command += " mpirun -np ";
564           std::ostringstream o;
565           o << nbproc << " ";
566           command += o.str();
567 #ifdef WITHLAM
568           command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
569 #endif  
570           command += " SALOME_MPIContainer ";
571         }
572       else
573         command += " SALOME_Container ";
574
575       command += _NS->ContainerName(params);
576       command += " -id ";
577       sprintf(idc,"%ld",id);
578       command += idc;
579       command += " -";
580       AddOmninamesParams(command);
581
582       MESSAGE("command =" << command);
583     }
584
585   return command;
586 }
587
588 //=============================================================================
589 /*!
590  *  builds the command to be launched.
591  */ 
592 //=============================================================================
593
594 string
595 SALOME_ResourcesManager::BuildCommandToLaunchLocalContainer
596 (const Engines::MachineParameters& params, const long id)
597 {
598   _TmpFileName = "";
599   string command;
600   int nbproc = 0;
601   char idc[3*sizeof(long)];
602
603   if (params.isMPI)
604     {
605       command = "mpirun -np ";
606
607       if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
608         nbproc = 1;
609       else if ( params.nb_node == 0 )
610         nbproc = params.nb_proc_per_node;
611       else if ( params.nb_proc_per_node == 0 )
612         nbproc = params.nb_node;
613       else
614         nbproc = params.nb_node * params.nb_proc_per_node;
615
616       std::ostringstream o;
617
618       o << nbproc << " ";
619
620       command += o.str();
621 #ifdef WITHLAM
622       command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
623 #endif
624
625       if (isPythonContainer(params.container_name))
626         command += "pyMPI SALOME_ContainerPy.py ";
627       else
628         command += "SALOME_MPIContainer ";
629     }
630
631   else
632     {
633       command="";
634       std::string wdir=params.workingdir.in();
635       std::cerr << wdir << std::endl;
636       if(wdir != "")
637         {
638           // a working directory is requested
639           if(wdir == "$TEMPDIR")
640             {
641               // a new temporary directory is requested
642               char dir[]="/tmp/salomeXXXXXX";
643               char* mdir=mkdtemp(dir);
644               if(mdir==NULL)
645                 std::cerr << "Problem in mkdtemp " << dir << " " << mdir << std::endl;
646               else
647                 command="cd "+std::string(dir)+";";
648             }
649           else
650             {
651               // a permanent directory is requested use it or create it
652               command="mkdir -p " + wdir + " && cd " + wdir + ";";
653             }
654         }
655       if (isPythonContainer(params.container_name))
656         command += "SALOME_ContainerPy.py ";
657       else
658         command += "SALOME_Container ";
659     }
660
661   command += _NS->ContainerName(params);
662   command += " -id ";
663   sprintf(idc,"%ld",id);
664   command += idc;
665   command += " -";
666   AddOmninamesParams(command);
667
668   MESSAGE("Command is ... " << command);
669   return command;
670 }
671
672
673 //=============================================================================
674 /*!
675  *  removes the generated temporary file in case of a remote launch.
676  */ 
677 //=============================================================================
678
679 void SALOME_ResourcesManager::RmTmpFile()
680 {
681   if (_TmpFileName != "")
682     {
683 #ifndef WNT
684       string command = "rm ";
685 #else
686       string command = "del /F ";
687 #endif
688       command += _TmpFileName;
689       char *temp = strdup(command.c_str());
690       int lgthTemp = strlen(temp);
691       temp[lgthTemp - 3] = '*';
692       temp[lgthTemp - 2] = '\0';
693       system(temp);
694       free(temp);
695     }
696 }
697
698
699 //=============================================================================
700 /*!
701  *  builds the script to be launched
702  */ 
703 //=============================================================================
704
705 string
706 SALOME_ResourcesManager::BuildCommand
707 (const string& machine,
708  const char *containerName)
709 {
710   // rsh -n ikkyo /export/home/rahuel/SALOME_ROOT/bin/runSession SALOME_Container -ORBInitRef NameService=corbaname::dm2s0017:1515 &
711   const ParserResourcesType& resInfo = _resourcesList[machine];
712   bool pyCont = isPythonContainer(containerName);
713
714   string command;
715
716   if (resInfo.Protocol == rsh)
717     command = "rsh -n " ;
718   else if (resInfo.Protocol == ssh)
719     command = "ssh -f -n ";
720   else
721     throw SALOME_Exception("Not implemented yet...");
722
723   command += machine;
724   command += " ";
725   string path = getenv("KERNEL_ROOT_DIR");
726   command += path;
727   command += "/bin/salome/";
728
729   if ( pyCont )
730     command += "SALOME_ContainerPy.py ";
731   else
732     command += "SALOME_Container ";
733
734   command += containerName;
735   command += " -";
736   AddOmninamesParams(command);
737
738   SCRUTE( command );
739   return command;
740 }
741
742 //=============================================================================
743 /*!
744  *  Gives a sublist of machines with matching OS.
745  *  If parameter OS is empty, gives the complete list of machines
746  */ 
747 //=============================================================================
748
749 // Warning need an updated parsed list : _resourcesList
750 void
751 SALOME_ResourcesManager::SelectOnlyResourcesWithOS
752 ( vector<string>& hosts,
753   const char *OS) const
754 throw(SALOME_Exception)
755 {
756   string base(OS);
757
758   for (map<string, ParserResourcesType>::const_iterator iter =
759          _resourcesList.begin();
760        iter != _resourcesList.end();
761        iter++)
762     {
763       if ( (*iter).second.OS == base || base.size() == 0)
764         hosts.push_back((*iter).first);
765     }
766 }
767
768
769 //=============================================================================
770 /*!
771  *  Gives a sublist of machines on which the module is known.
772  */ 
773 //=============================================================================
774
775 //Warning need an updated parsed list : _resourcesList
776 void
777 SALOME_ResourcesManager::KeepOnlyResourcesWithModule
778 ( vector<string>& hosts,
779   const Engines::CompoList& componentList) const
780 throw(SALOME_Exception)
781 {
782   for (vector<string>::iterator iter = hosts.begin(); iter != hosts.end();)
783     {
784       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
785       const vector<string>& mapOfModulesOfCurrentHost = (((*it).second).ModulesList);
786
787       bool erasedHost = false;
788       if( mapOfModulesOfCurrentHost.size() > 0 ){
789         for(int i=0;i<componentList.length();i++){
790           const char* compoi = componentList[i];
791           vector<string>::const_iterator itt = find(mapOfModulesOfCurrentHost.begin(),
792                                               mapOfModulesOfCurrentHost.end(),
793                                               compoi);
794 //                                            componentList[i]);
795           if (itt == mapOfModulesOfCurrentHost.end()){
796             erasedHost = true;
797             break;
798           }
799         }
800       }
801       if(erasedHost)
802         hosts.erase(iter);
803       else
804         iter++;
805     }
806 }
807
808
809 //=============================================================================
810 /*!
811  *   add to command all options relative to naming service.
812  */ 
813 //=============================================================================
814
815 void SALOME_ResourcesManager::AddOmninamesParams(string& command) const
816   {
817     // If env variable OMNIORB_CONFIG is not defined or the file is more complex than one line
818     // does not work
819     // Even if we use it we have to check if env variable exists
820     //string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
821     //ifstream omniORBfile( omniORBcfg.c_str() ) ;
822     //char ORBInitRef[11] ;
823     //char egal[3] ;
824     //char nameservice[132] ;
825     //omniORBfile >> ORBInitRef ;
826     //command += "ORBInitRef " ;
827     //omniORBfile >> egal ;
828     //omniORBfile >> nameservice ;
829     //omniORBfile.close() ;
830     //char * bsn = strchr( nameservice , '\n' ) ;
831     //if ( bsn ) {
832     //bsn[ 0 ] = '\0' ;
833     //}
834     //command += nameservice ;
835
836     CORBA::String_var iorstr = _NS->getIORaddr();
837     command += "ORBInitRef NameService=";
838     command += iorstr;
839   }
840
841
842 //=============================================================================
843 /*!
844  *  add to command all options relative to naming service.
845  */ 
846 //=============================================================================
847
848 void SALOME_ResourcesManager::AddOmninamesParams(ofstream& fileStream) const
849   {
850     CORBA::String_var iorstr = _NS->getIORaddr();
851     fileStream << "ORBInitRef NameService=";
852     fileStream << iorstr;
853   }
854
855
856 //=============================================================================
857 /*!
858  *  generate a file name in /tmp directory
859  */ 
860 //=============================================================================
861
862 string SALOME_ResourcesManager::BuildTemporaryFileName() const
863   {
864     //build more complex file name to support multiple salome session
865     char *temp = new char[19];
866     strcpy(temp, "/tmp/command");
867     strcat(temp, "XXXXXX");
868 #ifndef WNT
869
870     mkstemp(temp);
871 #else
872
873     char aPID[80];
874     itoa(getpid(), aPID, 10);
875     strcat(temp, aPID);
876 #endif
877
878     string command(temp);
879     delete [] temp;
880     command += ".sh";
881     return command;
882   }
883
884
885 //=============================================================================
886 /*!
887  *  Builds in a temporary file the script to be launched.
888  *  
889  *  Used if SALOME Application ($APPLI) is not defined.
890  *  The command is build with data from CatalogResources, in which every path
891  *  used on remote computer must be defined.
892  */ 
893 //=============================================================================
894
895 string
896 SALOME_ResourcesManager::BuildTempFileToLaunchRemoteContainer
897 (const string& machine,
898  const Engines::MachineParameters& params) throw(SALOME_Exception)
899 {
900   int status;
901
902   _TmpFileName = BuildTemporaryFileName();
903   ofstream tempOutputFile;
904   tempOutputFile.open(_TmpFileName.c_str(), ofstream::out );
905   const ParserResourcesType& resInfo = _resourcesList[machine];
906   tempOutputFile << "#! /bin/sh" << endl;
907
908   // --- set env vars
909
910   tempOutputFile << "export SALOME_trace=local" << endl; // mkr : 27.11.2006 : PAL13967 - Distributed supervision graphs - Problem with "SALOME_trace"
911   //tempOutputFile << "source " << resInfo.PreReqFilePath << endl;
912
913   // ! env vars
914
915   if (params.isMPI)
916     {
917       tempOutputFile << "mpirun -np ";
918       int nbproc;
919
920       if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
921         nbproc = 1;
922       else if ( params.nb_node == 0 )
923         nbproc = params.nb_proc_per_node;
924       else if ( params.nb_proc_per_node == 0 )
925         nbproc = params.nb_node;
926       else
927         nbproc = params.nb_node * params.nb_proc_per_node;
928
929       std::ostringstream o;
930
931       tempOutputFile << nbproc << " ";
932 #ifdef WITHLAM
933       tempOutputFile << "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
934 #endif
935     }
936
937   tempOutputFile << getenv("KERNEL_ROOT_DIR") << "/bin/salome/";
938
939   if (params.isMPI)
940     {
941       if (isPythonContainer(params.container_name))
942         tempOutputFile << "pyMPI SALOME_ContainerPy.py ";
943       else
944         tempOutputFile << "SALOME_MPIContainer ";
945     }
946
947   else
948     {
949       if (isPythonContainer(params.container_name))
950         tempOutputFile << "SALOME_ContainerPy.py ";
951       else
952         tempOutputFile << "SALOME_Container ";
953     }
954
955   tempOutputFile << _NS->ContainerName(params) << " -";
956   AddOmninamesParams(tempOutputFile);
957   tempOutputFile << " &" << endl;
958   tempOutputFile.flush();
959   tempOutputFile.close();
960   chmod(_TmpFileName.c_str(), 0x1ED);
961
962   // --- Build command
963
964   string command;
965
966   if (resInfo.Protocol == rsh)
967     {
968       command = "rsh ";
969       string commandRcp = "rcp ";
970       commandRcp += _TmpFileName;
971       commandRcp += " ";
972       commandRcp += machine;
973       commandRcp += ":";
974       commandRcp += _TmpFileName;
975       status = system(commandRcp.c_str());
976     }
977
978   else if (resInfo.Protocol == ssh)
979     {
980       command = "ssh ";
981       string commandRcp = "scp ";
982       commandRcp += _TmpFileName;
983       commandRcp += " ";
984       commandRcp += machine;
985       commandRcp += ":";
986       commandRcp += _TmpFileName;
987       status = system(commandRcp.c_str());
988     }
989   else
990     throw SALOME_Exception("Unknown protocol");
991
992   if(status)
993     throw SALOME_Exception("Error of connection on remote host");    
994
995   command += machine;
996   _CommandForRemAccess = command;
997   command += " ";
998   command += _TmpFileName;
999
1000   SCRUTE(command);
1001
1002   return command;
1003
1004 }
1005
1006 //=============================================================================
1007 /*! Creates a command line that the container manager uses to launch
1008  * a parallel container.
1009  */ 
1010 //=============================================================================
1011 string 
1012 SALOME_ResourcesManager::BuildCommandToLaunchLocalParallelContainer(const std::string& exe_name,
1013                                                                     const Engines::MachineParameters& params,
1014                                                                     const std::string& log)
1015 {
1016   // This method knows the differences between the proxy and the nodes.
1017   // nb_component_nodes is not used in the same way if it is a proxy or 
1018   // a node.
1019
1020   string command;
1021   string parallelLib(CORBA::string_dup(params.parallelLib));
1022   string hostname(CORBA::string_dup(params.hostname));
1023   int par = exe_name.find("Proxy");
1024   int nbproc = params.nb_component_nodes;
1025   char buffer [33];
1026   sprintf(buffer,"%d",nbproc);
1027
1028   Engines::MachineParameters_var rtn = new Engines::MachineParameters();
1029   rtn->container_name = params.container_name;
1030   rtn->hostname = params.hostname;
1031   rtn->OS = params.OS;
1032   rtn->mem_mb = params.mem_mb;
1033   rtn->cpu_clock = params.cpu_clock;
1034   rtn->nb_proc_per_node = params.nb_proc_per_node;
1035   rtn->nb_node = params.nb_node;
1036   rtn->isMPI = params.isMPI;
1037
1038   string real_exe_name  = exe_name + parallelLib;
1039
1040   if (parallelLib == "Dummy")
1041   {
1042     //command = "gdb --args ";
1043     //command = "valgrind --tool=memcheck --log-file=val_log ";
1044     //command += real_exe_name;
1045
1046     command = real_exe_name;
1047
1048     command += " " + _NS->ContainerName(rtn);
1049     command += " " + parallelLib;
1050     command += " " + hostname;
1051     command += " -";
1052     AddOmninamesParams(command);
1053   }
1054
1055   else if (parallelLib == "Mpi")
1056   {
1057     // Step 1 : check if MPI is started
1058     if (_MpiStarted == false)
1059     {
1060       startMPI();
1061     }
1062
1063     if (par < 0)
1064     {
1065       // Nodes case
1066
1067       command = "mpiexec -np " + string(buffer) + " ";
1068 //      command += "gdb --args ";
1069       command += real_exe_name;
1070       command += " " + _NS->ContainerName(rtn);
1071       command += " " + parallelLib;
1072       command += " " + hostname;
1073       command += " -";
1074       AddOmninamesParams(command);
1075     }
1076     else                                          
1077     {
1078       // Proxy case
1079       command = "mpiexec -np 1 ";
1080       command += real_exe_name;
1081       command += " " + _NS->ContainerName(rtn);
1082       command += " " + string(buffer);
1083       command += " " + parallelLib;
1084       command += " " + hostname;
1085       command += " -";
1086       AddOmninamesParams(command);
1087     }
1088   }
1089   else
1090   {
1091     std::string message("Unknown parallelLib" + parallelLib);
1092     throw SALOME_Exception(message.c_str());
1093   }
1094
1095   // log choice
1096   if (log == "default")
1097   {
1098     command += " > /tmp/";
1099     command += _NS->ContainerName(rtn);
1100     command += "_";
1101     command += GetHostname();
1102     command += "_";
1103     command += getenv( "USER" ) ;
1104     command += ".log 2>&1 &" ;
1105   }
1106   if (log == "xterm")
1107   {
1108     command = "/usr/X11R6/bin/xterm -e \"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; export PATH=$PATH;  " 
1109               + command + " \" &";
1110 //            + command + "; echo $LD_LIBRARY_PATH; cat \" &";
1111   }
1112   return command;
1113
1114 /*  if (log == "xterm")
1115   {
1116     command = "/usr/X11R6/bin/xterm -e \"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; export PATH=$PATH; echo $LD_LIBRARY_PATH; echo $PATH; " + command + "; cat \" &";
1117   }
1118 */
1119 /*  command = "cd ; rm " + fichier_commande + "; touch " + \
1120              fichier_commande + "; echo \" export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; " + \
1121              command + " >& /tmp/ribes_" + fichier_commande + " & \" > " + fichier_commande + ";";
1122   command += "ssh cn01 sh " + fichier_commande + " &";
1123   cerr << "La commande : " << command << endl;
1124 */
1125 }
1126
1127 void SALOME_ResourcesManager::startMPI()
1128 {
1129   cerr << "----------------------------------------------" << endl;
1130   cerr << "----------------------------------------------" << endl;
1131   cerr << "----------------------------------------------" << endl;
1132   cerr << "-Only Lam on Localhost is currently supported-" << endl;
1133   cerr << "----------------------------------------------" << endl;
1134   cerr << "----------------------------------------------" << endl;
1135   cerr << "----------------------------------------------" << endl;
1136
1137   int status = system("lamboot");
1138   if (status == -1)
1139   {
1140     INFOS("lamboot failed : system command status -1");
1141   }
1142   else if (status == 217)
1143   {
1144     INFOS("lamboot failed : system command status 217");
1145   }
1146   else
1147   {
1148     _MpiStarted = true;
1149   }
1150 }
1151
1152 Engines::MachineParameters* SALOME_ResourcesManager::GetMachineParameters(const char *hostname)
1153 {
1154   ParserResourcesType resource = _resourcesList[string(hostname)];
1155   Engines::MachineParameters *p_ptr = new Engines::MachineParameters;
1156   p_ptr->container_name = CORBA::string_dup("");
1157   p_ptr->hostname = CORBA::string_dup("hostname");
1158   p_ptr->alias = CORBA::string_dup(resource.Alias.c_str());
1159   if( resource.Protocol == rsh )
1160     p_ptr->protocol = "rsh";
1161   else if( resource.Protocol == ssh )
1162     p_ptr->protocol = "ssh";
1163   p_ptr->username = CORBA::string_dup(resource.UserName.c_str());
1164   p_ptr->applipath = CORBA::string_dup(resource.AppliPath.c_str());
1165   p_ptr->modList.length(resource.ModulesList.size());
1166   for(int i=0;i<resource.ModulesList.size();i++)
1167     p_ptr->modList[i] = CORBA::string_dup(resource.ModulesList[i].c_str());
1168   p_ptr->OS = CORBA::string_dup(resource.OS.c_str());
1169   p_ptr->mem_mb = resource.DataForSort._memInMB;
1170   p_ptr->cpu_clock = resource.DataForSort._CPUFreqMHz;
1171   p_ptr->nb_proc_per_node = resource.DataForSort._nbOfProcPerNode;
1172   p_ptr->nb_node = resource.DataForSort._nbOfNodes;
1173   if( resource.mpi == indif )
1174     p_ptr->mpiImpl = "indif";
1175   else if( resource.mpi == lam )
1176     p_ptr->mpiImpl = "lam";
1177   else if( resource.mpi == mpich1 )
1178     p_ptr->mpiImpl = "mpich1";
1179   else if( resource.mpi == mpich2 )
1180     p_ptr->mpiImpl = "mpich2";
1181   else if( resource.mpi == openmpi )
1182     p_ptr->mpiImpl = "openmpi";
1183   if( resource.Batch == pbs )
1184     p_ptr->batch = "pbs";
1185   else if( resource.Batch == lsf )
1186     p_ptr->batch = "lsf";
1187   else if( resource.Batch == slurm )
1188     p_ptr->batch = "slurm";
1189   return p_ptr;
1190 }