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)
364 if ( ! _isAppliSalomeDefined )
365 command = BuildTempFileToLaunchRemoteContainer(machine, params);
369 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
421 command += " SALOME_Container ";
422 command += _NS->ContainerName(params);
425 MESSAGE("command =" << command);
432 //=============================================================================
434 * builds the command to be launched.
436 //=============================================================================
439 SALOME_ResourcesManager::BuildCommandToLaunchLocalContainer
440 (const Engines::MachineParameters& params)
448 command = "mpirun -np ";
450 if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
452 else if ( params.nb_node == 0 )
453 nbproc = params.nb_proc_per_node;
454 else if ( params.nb_proc_per_node == 0 )
455 nbproc = params.nb_node;
457 nbproc = params.nb_node * params.nb_proc_per_node;
459 std::ostringstream o;
464 command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
466 if (isPythonContainer(params.container_name))
467 command += "pyMPI SALOME_ContainerPy.py ";
469 command += "SALOME_MPIContainer ";
474 if (isPythonContainer(params.container_name))
475 command = "SALOME_ContainerPy.py ";
477 command = "SALOME_Container ";
480 command += _NS->ContainerName(params);
482 AddOmninamesParams(command);
483 command += " > /tmp/";
484 command += _NS->ContainerName(params);
486 command += GetHostname();
488 command += getenv( "USER" ) ;
489 command += ".log 2>&1 &" ;
490 MESSAGE("Command is ... " << command);
495 //=============================================================================
497 * removes the generated temporary file in case of a remote launch.
499 //=============================================================================
501 void SALOME_ResourcesManager::RmTmpFile()
503 if (_TmpFileName != "")
505 string command = "rm ";
506 command += _TmpFileName;
507 char *temp = strdup(command.c_str());
508 int lgthTemp = strlen(temp);
509 temp[lgthTemp - 3] = '*';
510 temp[lgthTemp - 2] = '\0';
517 //=============================================================================
519 * builds the script to be launched
521 //=============================================================================
524 SALOME_ResourcesManager::BuildCommand
525 (const string& machine,
526 const char *containerName)
528 // rsh -n ikkyo /export/home/rahuel/SALOME_ROOT/bin/runSession SALOME_Container -ORBInitRef NameService=corbaname::dm2s0017:1515 &
529 const ParserResourcesType& resInfo = _resourcesList[machine];
530 bool pyCont = isPythonContainer(containerName);
534 if (resInfo.Protocol == rsh)
535 command = "rsh -n " ;
536 else if (resInfo.Protocol == ssh)
537 command = "ssh -f -n ";
539 throw SALOME_Exception("Not implemented yet...");
543 string path = (*(resInfo.ModulesPath.find("KERNEL"))).second;
545 command += "/bin/salome/";
548 command += "SALOME_ContainerPy.py ";
550 command += "SALOME_Container ";
552 command += containerName;
554 AddOmninamesParams(command);
555 command += " > /tmp/";
556 command += containerName;
559 command += ".log 2>&1 &" ;
565 //=============================================================================
567 * Gives a sublist of machines with matching OS.
568 * If parameter OS is empty, gives the complete list of machines
570 //=============================================================================
572 // Warning need an updated parsed list : _resourcesList
574 SALOME_ResourcesManager::SelectOnlyResourcesWithOS
575 ( vector<string>& hosts,
576 const char *OS) const
577 throw(SALOME_Exception)
581 for (map<string, ParserResourcesType>::const_iterator iter =
582 _resourcesList.begin();
583 iter != _resourcesList.end();
586 if ( (*iter).second.OS == base || base.size() == 0)
587 hosts.push_back((*iter).first);
592 //=============================================================================
594 * Gives a sublist of machines on which the module is known.
596 //=============================================================================
598 //Warning need an updated parsed list : _resourcesList
600 SALOME_ResourcesManager::KeepOnlyResourcesWithModule
601 ( vector<string>& hosts,
602 const char *moduleName) const
603 throw(SALOME_Exception)
605 for (vector<string>::iterator iter = hosts.begin(); iter != hosts.end();)
607 MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
608 const map<string, string>& mapOfModulesOfCurrentHost =
609 (((*it).second).ModulesPath);
611 if (mapOfModulesOfCurrentHost.find(moduleName) ==
612 mapOfModulesOfCurrentHost.end())
620 //=============================================================================
622 * add to command all options relative to naming service.
624 //=============================================================================
626 void SALOME_ResourcesManager::AddOmninamesParams(string& command) const
628 // If env variable OMNIORB_CONFIG is not defined or the file is more complex than one line
630 // Even if we use it we have to check if env variable exists
631 //string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
632 //ifstream omniORBfile( omniORBcfg.c_str() ) ;
633 //char ORBInitRef[11] ;
635 //char nameservice[132] ;
636 //omniORBfile >> ORBInitRef ;
637 //command += "ORBInitRef " ;
638 //omniORBfile >> egal ;
639 //omniORBfile >> nameservice ;
640 //omniORBfile.close() ;
641 //char * bsn = strchr( nameservice , '\n' ) ;
645 //command += nameservice ;
647 char *iorstr = _NS->getIORaddr();
648 command += "ORBInitRef NameService=";
653 //=============================================================================
655 * add to command all options relative to naming service.
657 //=============================================================================
659 void SALOME_ResourcesManager::AddOmninamesParams(ofstream& fileStream) const
661 string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
662 ifstream omniORBfile( omniORBcfg.c_str() ) ;
663 char ORBInitRef[11] ;
665 char nameservice[132] ;
666 omniORBfile >> ORBInitRef ;
667 fileStream << "ORBInitRef ";
668 omniORBfile >> egal ;
669 omniORBfile >> nameservice ;
670 omniORBfile.close() ;
671 char * bsn = strchr( nameservice , '\n' ) ;
678 fileStream << nameservice;
682 //=============================================================================
684 * generate a file name in /tmp directory
686 //=============================================================================
688 string SALOME_ResourcesManager::BuildTemporaryFileName() const
690 //build more complex file name to support multiple salome session
691 char *temp = new char[19];
692 strcpy(temp, "/tmp/command");
693 strcat(temp, "XXXXXX");
700 itoa(getpid(), aPID, 10);
704 string command(temp);
711 //=============================================================================
713 * Builds in a temporary file the script to be launched.
715 * Used if SALOME Application ($APPLI) is not defined.
716 * The command is build with data from CatalogResources, in which every path
717 * used on remote computer must be defined.
719 //=============================================================================
722 SALOME_ResourcesManager::BuildTempFileToLaunchRemoteContainer
723 (const string& machine,
724 const Engines::MachineParameters& params)
726 _TmpFileName = BuildTemporaryFileName();
727 ofstream tempOutputFile;
728 tempOutputFile.open(_TmpFileName.c_str(), ofstream::out );
729 const ParserResourcesType& resInfo = _resourcesList[machine];
730 tempOutputFile << "#! /bin/sh" << endl;
734 for (map<string, string>::const_iterator iter = resInfo.ModulesPath.begin();
735 iter != resInfo.ModulesPath.end();
738 string curModulePath((*iter).second);
739 tempOutputFile << (*iter).first << "_ROOT_DIR=" << curModulePath << endl;
740 tempOutputFile << "export " << (*iter).first << "_ROOT_DIR" << endl;
741 tempOutputFile << "LD_LIBRARY_PATH=" << curModulePath
742 << "/lib/salome" << ":${LD_LIBRARY_PATH}" << endl;
743 tempOutputFile << "PYTHONPATH=" << curModulePath << "/bin/salome:"
744 << curModulePath << "/lib/salome:" << curModulePath
745 << "/lib/python2.2/site-packages/salome:";
746 tempOutputFile << curModulePath
747 << "/lib/python2.2/site-packages/salome/shared_modules:${PYTHONPATH}"
751 tempOutputFile << "export LD_LIBRARY_PATH" << endl;
752 tempOutputFile << "export PYTHONPATH" << endl;
753 tempOutputFile << "source " << resInfo.PreReqFilePath << endl;
759 tempOutputFile << "mpirun -np ";
762 if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
764 else if ( params.nb_node == 0 )
765 nbproc = params.nb_proc_per_node;
766 else if ( params.nb_proc_per_node == 0 )
767 nbproc = params.nb_node;
769 nbproc = params.nb_node * params.nb_proc_per_node;
771 std::ostringstream o;
773 tempOutputFile << nbproc << " ";
776 tempOutputFile << (*(resInfo.ModulesPath.find("KERNEL"))).second
781 if (isPythonContainer(params.container_name))
782 tempOutputFile << "pyMPI SALOME_ContainerPy.py ";
784 tempOutputFile << "SALOME_MPIContainer ";
789 if (isPythonContainer(params.container_name))
790 tempOutputFile << "SALOME_ContainerPy.py ";
792 tempOutputFile << "SALOME_Container ";
795 tempOutputFile << _NS->ContainerName(params) << " -";
796 AddOmninamesParams(tempOutputFile);
797 tempOutputFile << " &" << endl;
798 tempOutputFile.flush();
799 tempOutputFile.close();
800 chmod(_TmpFileName.c_str(), 0x1ED);
806 if (resInfo.Protocol == rsh)
809 string commandRcp = "rcp ";
810 commandRcp += _TmpFileName;
812 commandRcp += machine;
814 commandRcp += _TmpFileName;
815 system(commandRcp.c_str());
818 else if (resInfo.Protocol == ssh)
821 throw SALOME_Exception("Unknown protocol");
824 _CommandForRemAccess = command;
826 command += _TmpFileName;
829 command += _NS->ContainerName(params);
832 command += ".log 2>&1 &";