1 #include "SALOME_ResourcesManager.hxx"
2 //#include "SALOME_Container_i.hxx"
3 #include "Utils_ExceptHandlers.hxx"
22 #include <sys/types.h>
24 #include "utilities.h"
26 #define MAX_SIZE_FOR_HOSTNAME 256;
30 //=============================================================================
34 //=============================================================================
36 SALOME_ResourcesManager::
37 SALOME_ResourcesManager(CORBA::ORB_ptr orb,
38 const char *xmlFilePath) :
39 _path_resources(xmlFilePath)
41 _NS = new SALOME_NamingService(orb);
44 //=============================================================================
46 * Standard constructor, parse resource file.
47 * - if ${APPLI} exists in environment,
48 * look for ${HOME}/*{APPLI}/CatalogResources.xml
49 * - else look for default:
50 * ${KERNEL_ROOT_DIR}/share/salome/resources/CatalogResources.xml
51 * - parse XML resource file.
53 //=============================================================================
55 SALOME_ResourcesManager::SALOME_ResourcesManager(CORBA::ORB_ptr orb)
57 _NS = new SALOME_NamingService(orb);
58 _isAppliSalomeDefined = (getenv("APPLI") != 0);
60 if (_isAppliSalomeDefined)
62 _path_resources = getenv("HOME");
63 _path_resources += "/";
64 _path_resources += getenv("APPLI");
65 _path_resources += "/CatalogResources.xml";
70 _path_resources = getenv("KERNEL_ROOT_DIR");
71 _path_resources += "/share/salome/resources/CatalogResources.xml";
77 //=============================================================================
81 //=============================================================================
83 SALOME_ResourcesManager::~SALOME_ResourcesManager()
88 //=============================================================================
90 * get the list of name of ressources fitting for the specified module.
91 * If hostname specified, check it is local or known in resources catalog.
94 * - select first machines with corresponding OS (all machines if
95 * parameter OS empty),
96 * - then select the sublist of machines on witch the module is known
97 * (if the result is empty, that probably means that the inventory of
98 * modules is probably not done, so give complete list from previous step)
100 //=============================================================================
103 SALOME_ResourcesManager::
104 GetFittingResources(const Engines::MachineParameters& params,
105 const char *moduleName)
106 throw(SALOME_Exception)
108 MESSAGE("ResourcesManager::GetFittingResources");
109 vector <std::string> ret;
111 // --- To be sure that we search in a correct list.
114 const char *hostname = (const char *)params.hostname;
115 MESSAGE("GetFittingResources " << hostname << " " << GetHostname().c_str());
117 if (hostname[0] != '\0')
119 MESSAGE("ResourcesManager::GetFittingResources : hostname specified" );
121 if ( strcmp(hostname, "localhost") == 0 ||
122 strcmp(hostname, GetHostname().c_str()) == 0 )
124 MESSAGE("ResourcesManager::GetFittingResources : localhost" );
125 ret.push_back(GetHostname().c_str());
126 MESSAGE("ResourcesManager::GetFittingResources : " << ret.size());
129 else if (_resourcesList.find(hostname) != _resourcesList.end())
131 // --- params.hostname is in the list of resources so return it.
132 ret.push_back(hostname);
137 // --- user specified an unknown hostame so notify him.
138 MESSAGE("ResourcesManager::GetFittingResources : SALOME_Exception");
139 throw SALOME_Exception("unknown host");
144 // --- Search for available resources sorted by priority
146 SelectOnlyResourcesWithOS(ret, params.OS);
148 KeepOnlyResourcesWithModule(ret, moduleName);
151 SelectOnlyResourcesWithOS(ret, params.OS);
153 // --- set wanted parameters
154 ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
156 ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
158 ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
160 ResourceDataToSort::_memInMBWanted = params.mem_mb;
164 list<ResourceDataToSort> li;
166 for (vector<string>::iterator iter = ret.begin();
169 li.push_back(_resourcesList[(*iter)].DataForSort);
175 for (list<ResourceDataToSort>::iterator iter2 = li.begin();
178 ret[i++] = (*iter2)._hostName;
181 MESSAGE("ResourcesManager::GetFittingResources : return" << ret.size());
185 //=============================================================================
187 * add an entry in the ressources catalog xml file.
188 * Return 0 if OK (KERNEL found in new resources modules) else throw exception
190 //=============================================================================
193 SALOME_ResourcesManager::
194 AddResourceInCatalog(const Engines::MachineParameters& paramsOfNewResources,
195 const map<string, string>& modulesOnNewResources,
196 const char *environPathOfPrerequired,
198 const char *userName,
200 AccessProtocolType prot)
201 throw(SALOME_Exception)
203 map<string, string>::const_iterator iter =
204 modulesOnNewResources.find("KERNEL");
206 if (iter != modulesOnNewResources.end())
208 ParserResourcesType newElt;
209 newElt.DataForSort._hostName = paramsOfNewResources.hostname;
210 newElt.Alias = alias;
211 newElt.Protocol = prot;
213 newElt.UserName = userName;
214 newElt.ModulesPath = modulesOnNewResources;
215 newElt.PreReqFilePath = environPathOfPrerequired;
216 newElt.OS = paramsOfNewResources.OS;
217 newElt.DataForSort._memInMB = paramsOfNewResources.mem_mb;
218 newElt.DataForSort._CPUFreqMHz = paramsOfNewResources.cpu_clock;
219 newElt.DataForSort._nbOfNodes = paramsOfNewResources.nb_node;
220 newElt.DataForSort._nbOfProcPerNode =
221 paramsOfNewResources.nb_proc_per_node;
222 _resourcesList[newElt.DataForSort._hostName] = newElt;
227 throw SALOME_Exception("KERNEL is not present in this resource");
230 //=============================================================================
232 * Deletes a resource from the catalog
234 //=============================================================================
236 void SALOME_ResourcesManager::DeleteResourceInCatalog(const char *hostname)
238 _resourcesList.erase(hostname);
241 //=============================================================================
243 * write the current data in memory in file.
245 //=============================================================================
247 void SALOME_ResourcesManager::WriteInXmlFile()
249 QDomDocument doc("ResourcesCatalog");
250 SALOME_ResourcesCatalog_Handler* handler =
251 new SALOME_ResourcesCatalog_Handler(_resourcesList);
252 handler->PrepareDocToXmlFile(doc);
255 QFile file( _path_resources );
257 if ( !file.open( IO_WriteOnly ) )
258 INFOS("WRITING ERROR !");
260 QTextStream ts( &file );
262 ts << doc.toString();
266 MESSAGE("WRITING DONE!");
269 //=============================================================================
271 * parse the data type catalog
273 //=============================================================================
275 const MapOfParserResourcesType& SALOME_ResourcesManager::ParseXmlFile()
277 SALOME_ResourcesCatalog_Handler* handler =
278 new SALOME_ResourcesCatalog_Handler(_resourcesList);
279 QFile xmlFile(_path_resources);
281 QXmlInputSource source(xmlFile);
283 QXmlSimpleReader reader;
284 reader.setContentHandler( handler );
285 reader.setErrorHandler( handler );
286 reader.parse( source );
289 return _resourcesList;
292 //=============================================================================
294 * consult the content of the list
296 //=============================================================================
298 const MapOfParserResourcesType& SALOME_ResourcesManager::GetList() const
300 return _resourcesList;
304 //=============================================================================
306 * dynamically obtains the best machines
308 //=============================================================================
311 SALOME_ResourcesManager::FindBest(const Engines::MachineList& listOfMachines)
313 return _dynamicResourcesSelecter.FindBest(listOfMachines);
317 //=============================================================================
319 * This is no longer valid (C++ container are also python containers)
321 //=============================================================================
323 bool isPythonContainer(const char* ContainerName)
326 int len = strlen(ContainerName);
329 if (strcmp(ContainerName + len - 2, "Py") == 0)
336 //=============================================================================
338 * Builds the script to be launched
340 * If SALOME Application not defined ($APPLI),
341 * see BuildTempFileToLaunchRemoteContainer()
343 * Else rely on distant configuration. Command is under the form (example):
344 * ssh user@machine distantPath/runRemote.sh hostNS portNS \
345 * SALOME_Container containerName &"
347 * - where user is ommited if not specified in CatalogResources,
348 * - where distant path is always relative to user@machine $HOME, and
349 * equal to $APPLI if not specified in CatalogResources,
350 * - where hostNS is the hostname of CORBA naming server (set by scripts to
351 * use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
352 * - where portNS is the port used by CORBA naming server (set by scripts to
353 * use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
355 //=============================================================================
358 SALOME_ResourcesManager::BuildCommandToLaunchRemoteContainer
359 (const string& machine,
360 const Engines::MachineParameters& params, const long id)
364 char idc[3*sizeof(long)];
366 if ( ! _isAppliSalomeDefined )
367 command = BuildTempFileToLaunchRemoteContainer(machine, params);
371 const ParserResourcesType& resInfo = _resourcesList[machine];
375 if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
377 else if ( params.nb_node == 0 )
378 nbproc = params.nb_proc_per_node;
379 else if ( params.nb_proc_per_node == 0 )
380 nbproc = params.nb_node;
382 nbproc = params.nb_node * params.nb_proc_per_node;
385 // "ssh user@machine distantPath/runRemote.sh hostNS portNS \
386 // SALOME_Container containerName &"
388 if (resInfo.Protocol == rsh)
390 else if (resInfo.Protocol == ssh)
393 throw SALOME_Exception("Unknown protocol");
395 if (resInfo.UserName != "")
397 command += resInfo.UserName;
404 if (resInfo.AppliPath != "")
405 command += resInfo.AppliPath; // path relative to user@machine $HOME
408 ASSERT(getenv("APPLI"));
409 command += getenv("APPLI"); // path relative to user@machine $HOME
412 command += "/runRemote.sh ";
414 ASSERT(getenv("NSHOST"));
415 command += getenv("NSHOST"); // hostname of CORBA name server
418 ASSERT(getenv("NSPORT"));
419 command += getenv("NSPORT"); // port of CORBA name server
423 command += " mpirun -np ";
424 std::ostringstream o;
428 command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
430 command += " SALOME_MPIContainer ";
433 command += " SALOME_Container ";
435 command += _NS->ContainerName(params);
437 sprintf(idc,"%ld",id);
440 AddOmninamesParams(command);
441 command += " > /tmp/";
442 command += _NS->ContainerName(params);
444 command += GetHostname();
446 command += getenv( "USER" ) ;
447 command += ".log 2>&1 &" ;
449 MESSAGE("command =" << command);
456 //=============================================================================
458 * builds the command to be launched.
460 //=============================================================================
463 SALOME_ResourcesManager::BuildCommandToLaunchLocalContainer
464 (const Engines::MachineParameters& params, const long id)
469 char idc[3*sizeof(long)];
473 command = "mpirun -np ";
475 if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
477 else if ( params.nb_node == 0 )
478 nbproc = params.nb_proc_per_node;
479 else if ( params.nb_proc_per_node == 0 )
480 nbproc = params.nb_node;
482 nbproc = params.nb_node * params.nb_proc_per_node;
484 std::ostringstream o;
490 command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
493 if (isPythonContainer(params.container_name))
494 command += "pyMPI SALOME_ContainerPy.py ";
496 command += "SALOME_MPIContainer ";
501 if (isPythonContainer(params.container_name))
502 command = "SALOME_ContainerPy.py ";
504 command = "SALOME_Container ";
507 command += _NS->ContainerName(params);
509 sprintf(idc,"%ld",id);
512 AddOmninamesParams(command);
513 command += " > /tmp/";
514 command += _NS->ContainerName(params);
516 command += GetHostname();
518 command += getenv( "USER" ) ;
519 command += ".log 2>&1 &" ;
520 MESSAGE("Command is ... " << command);
525 //=============================================================================
527 * removes the generated temporary file in case of a remote launch.
529 //=============================================================================
531 void SALOME_ResourcesManager::RmTmpFile()
533 if (_TmpFileName != "")
535 string command = "rm ";
536 command += _TmpFileName;
537 char *temp = strdup(command.c_str());
538 int lgthTemp = strlen(temp);
539 temp[lgthTemp - 3] = '*';
540 temp[lgthTemp - 2] = '\0';
547 //=============================================================================
549 * builds the script to be launched
551 //=============================================================================
554 SALOME_ResourcesManager::BuildCommand
555 (const string& machine,
556 const char *containerName)
558 // rsh -n ikkyo /export/home/rahuel/SALOME_ROOT/bin/runSession SALOME_Container -ORBInitRef NameService=corbaname::dm2s0017:1515 &
559 const ParserResourcesType& resInfo = _resourcesList[machine];
560 bool pyCont = isPythonContainer(containerName);
564 if (resInfo.Protocol == rsh)
565 command = "rsh -n " ;
566 else if (resInfo.Protocol == ssh)
567 command = "ssh -f -n ";
569 throw SALOME_Exception("Not implemented yet...");
573 string path = (*(resInfo.ModulesPath.find("KERNEL"))).second;
575 command += "/bin/salome/";
578 command += "SALOME_ContainerPy.py ";
580 command += "SALOME_Container ";
582 command += containerName;
584 AddOmninamesParams(command);
585 command += " > /tmp/";
586 command += containerName;
589 command += ".log 2>&1 &" ;
595 //=============================================================================
597 * Gives a sublist of machines with matching OS.
598 * If parameter OS is empty, gives the complete list of machines
600 //=============================================================================
602 // Warning need an updated parsed list : _resourcesList
604 SALOME_ResourcesManager::SelectOnlyResourcesWithOS
605 ( vector<string>& hosts,
606 const char *OS) const
607 throw(SALOME_Exception)
611 for (map<string, ParserResourcesType>::const_iterator iter =
612 _resourcesList.begin();
613 iter != _resourcesList.end();
616 if ( (*iter).second.OS == base || base.size() == 0)
617 hosts.push_back((*iter).first);
622 //=============================================================================
624 * Gives a sublist of machines on which the module is known.
626 //=============================================================================
628 //Warning need an updated parsed list : _resourcesList
630 SALOME_ResourcesManager::KeepOnlyResourcesWithModule
631 ( vector<string>& hosts,
632 const char *moduleName) const
633 throw(SALOME_Exception)
635 for (vector<string>::iterator iter = hosts.begin(); iter != hosts.end();)
637 MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
638 const map<string, string>& mapOfModulesOfCurrentHost =
639 (((*it).second).ModulesPath);
641 if (mapOfModulesOfCurrentHost.find(moduleName) ==
642 mapOfModulesOfCurrentHost.end())
650 //=============================================================================
652 * add to command all options relative to naming service.
654 //=============================================================================
656 void SALOME_ResourcesManager::AddOmninamesParams(string& command) const
658 // If env variable OMNIORB_CONFIG is not defined or the file is more complex than one line
660 // Even if we use it we have to check if env variable exists
661 //string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
662 //ifstream omniORBfile( omniORBcfg.c_str() ) ;
663 //char ORBInitRef[11] ;
665 //char nameservice[132] ;
666 //omniORBfile >> ORBInitRef ;
667 //command += "ORBInitRef " ;
668 //omniORBfile >> egal ;
669 //omniORBfile >> nameservice ;
670 //omniORBfile.close() ;
671 //char * bsn = strchr( nameservice , '\n' ) ;
675 //command += nameservice ;
677 char *iorstr = _NS->getIORaddr();
678 command += "ORBInitRef NameService=";
683 //=============================================================================
685 * add to command all options relative to naming service.
687 //=============================================================================
689 void SALOME_ResourcesManager::AddOmninamesParams(ofstream& fileStream) const
691 string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
692 ifstream omniORBfile( omniORBcfg.c_str() ) ;
693 char ORBInitRef[11] ;
695 char nameservice[132] ;
696 omniORBfile >> ORBInitRef ;
697 fileStream << "ORBInitRef ";
698 omniORBfile >> egal ;
699 omniORBfile >> nameservice ;
700 omniORBfile.close() ;
701 char * bsn = strchr( nameservice , '\n' ) ;
708 fileStream << nameservice;
712 //=============================================================================
714 * generate a file name in /tmp directory
716 //=============================================================================
718 string SALOME_ResourcesManager::BuildTemporaryFileName() const
720 //build more complex file name to support multiple salome session
721 char *temp = new char[19];
722 strcpy(temp, "/tmp/command");
723 strcat(temp, "XXXXXX");
730 itoa(getpid(), aPID, 10);
734 string command(temp);
741 //=============================================================================
743 * Builds in a temporary file the script to be launched.
745 * Used if SALOME Application ($APPLI) is not defined.
746 * The command is build with data from CatalogResources, in which every path
747 * used on remote computer must be defined.
749 //=============================================================================
752 SALOME_ResourcesManager::BuildTempFileToLaunchRemoteContainer
753 (const string& machine,
754 const Engines::MachineParameters& params)
756 _TmpFileName = BuildTemporaryFileName();
757 ofstream tempOutputFile;
758 tempOutputFile.open(_TmpFileName.c_str(), ofstream::out );
759 const ParserResourcesType& resInfo = _resourcesList[machine];
760 tempOutputFile << "#! /bin/sh" << endl;
764 for (map<string, string>::const_iterator iter = resInfo.ModulesPath.begin();
765 iter != resInfo.ModulesPath.end();
768 string curModulePath((*iter).second);
769 tempOutputFile << (*iter).first << "_ROOT_DIR=" << curModulePath << endl;
770 tempOutputFile << "export " << (*iter).first << "_ROOT_DIR" << endl;
771 tempOutputFile << "LD_LIBRARY_PATH=" << curModulePath
772 << "/lib/salome" << ":${LD_LIBRARY_PATH}" << endl;
773 tempOutputFile << "PYTHONPATH=" << curModulePath << "/bin/salome:"
774 << curModulePath << "/lib/salome:" << curModulePath
775 << "/lib/python2.2/site-packages/salome:";
776 tempOutputFile << curModulePath
777 << "/lib/python2.2/site-packages/salome/shared_modules:${PYTHONPATH}"
781 tempOutputFile << "export LD_LIBRARY_PATH" << endl;
782 tempOutputFile << "export PYTHONPATH" << endl;
783 tempOutputFile << "source " << resInfo.PreReqFilePath << endl;
789 tempOutputFile << "mpirun -np ";
792 if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
794 else if ( params.nb_node == 0 )
795 nbproc = params.nb_proc_per_node;
796 else if ( params.nb_proc_per_node == 0 )
797 nbproc = params.nb_node;
799 nbproc = params.nb_node * params.nb_proc_per_node;
801 std::ostringstream o;
803 tempOutputFile << nbproc << " ";
805 tempOutputFile << "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
809 tempOutputFile << (*(resInfo.ModulesPath.find("KERNEL"))).second
814 if (isPythonContainer(params.container_name))
815 tempOutputFile << "pyMPI SALOME_ContainerPy.py ";
817 tempOutputFile << "SALOME_MPIContainer ";
822 if (isPythonContainer(params.container_name))
823 tempOutputFile << "SALOME_ContainerPy.py ";
825 tempOutputFile << "SALOME_Container ";
828 tempOutputFile << _NS->ContainerName(params) << " -";
829 AddOmninamesParams(tempOutputFile);
830 tempOutputFile << " &" << endl;
831 tempOutputFile.flush();
832 tempOutputFile.close();
833 chmod(_TmpFileName.c_str(), 0x1ED);
839 if (resInfo.Protocol == rsh)
842 string commandRcp = "rcp ";
843 commandRcp += _TmpFileName;
845 commandRcp += machine;
847 commandRcp += _TmpFileName;
848 system(commandRcp.c_str());
851 else if (resInfo.Protocol == ssh)
854 throw SALOME_Exception("Unknown protocol");
857 _CommandForRemAccess = command;
859 command += _TmpFileName;
862 command += _NS->ContainerName(params);
865 command += ".log 2>&1 &";