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