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;
465 if (isPythonContainer(params.container_name))
466 command += "pyMPI SALOME_ContainerPy.py ";
468 command += "SALOME_MPIContainer ";
473 if (isPythonContainer(params.container_name))
474 command = "SALOME_ContainerPy.py ";
476 command = "SALOME_Container ";
479 command += _NS->ContainerName(params);
481 AddOmninamesParams(command);
482 command += " > /tmp/";
483 command += _NS->ContainerName(params);
485 command += GetHostname();
487 command += getenv( "USER" ) ;
488 command += ".log 2>&1 &" ;
489 MESSAGE("Command is ... " << command);
494 //=============================================================================
496 * removes the generated temporary file in case of a remote launch.
498 //=============================================================================
500 void SALOME_ResourcesManager::RmTmpFile()
502 if (_TmpFileName != "")
504 string command = "rm ";
505 command += _TmpFileName;
506 char *temp = strdup(command.c_str());
507 int lgthTemp = strlen(temp);
508 temp[lgthTemp - 3] = '*';
509 temp[lgthTemp - 2] = '\0';
516 //=============================================================================
518 * builds the script to be launched
520 //=============================================================================
523 SALOME_ResourcesManager::BuildCommand
524 (const string& machine,
525 const char *containerName)
527 // rsh -n ikkyo /export/home/rahuel/SALOME_ROOT/bin/runSession SALOME_Container -ORBInitRef NameService=corbaname::dm2s0017:1515 &
528 const ParserResourcesType& resInfo = _resourcesList[machine];
529 bool pyCont = isPythonContainer(containerName);
533 if (resInfo.Protocol == rsh)
534 command = "rsh -n " ;
535 else if (resInfo.Protocol == ssh)
536 command = "ssh -f -n ";
538 throw SALOME_Exception("Not implemented yet...");
542 string path = (*(resInfo.ModulesPath.find("KERNEL"))).second;
544 command += "/bin/salome/";
547 command += "SALOME_ContainerPy.py ";
549 command += "SALOME_Container ";
551 command += containerName;
553 AddOmninamesParams(command);
554 command += " > /tmp/";
555 command += containerName;
558 command += ".log 2>&1 &" ;
564 //=============================================================================
566 * Gives a sublist of machines with matching OS.
567 * If parameter OS is empty, gives the complete list of machines
569 //=============================================================================
571 // Warning need an updated parsed list : _resourcesList
573 SALOME_ResourcesManager::SelectOnlyResourcesWithOS
574 ( vector<string>& hosts,
575 const char *OS) const
576 throw(SALOME_Exception)
580 for (map<string, ParserResourcesType>::const_iterator iter =
581 _resourcesList.begin();
582 iter != _resourcesList.end();
585 if ( (*iter).second.OS == base || base.size() == 0)
586 hosts.push_back((*iter).first);
591 //=============================================================================
593 * Gives a sublist of machines on which the module is known.
595 //=============================================================================
597 //Warning need an updated parsed list : _resourcesList
599 SALOME_ResourcesManager::KeepOnlyResourcesWithModule
600 ( vector<string>& hosts,
601 const char *moduleName) const
602 throw(SALOME_Exception)
604 for (vector<string>::iterator iter = hosts.begin(); iter != hosts.end();)
606 MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
607 const map<string, string>& mapOfModulesOfCurrentHost =
608 (((*it).second).ModulesPath);
610 if (mapOfModulesOfCurrentHost.find(moduleName) ==
611 mapOfModulesOfCurrentHost.end())
619 //=============================================================================
621 * add to command all options relative to naming service.
623 //=============================================================================
625 void SALOME_ResourcesManager::AddOmninamesParams(string& command) const
627 // If env variable OMNIORB_CONFIG is not defined or the file is more complex than one line
629 // Even if we use it we have to check if env variable exists
630 //string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
631 //ifstream omniORBfile( omniORBcfg.c_str() ) ;
632 //char ORBInitRef[11] ;
634 //char nameservice[132] ;
635 //omniORBfile >> ORBInitRef ;
636 //command += "ORBInitRef " ;
637 //omniORBfile >> egal ;
638 //omniORBfile >> nameservice ;
639 //omniORBfile.close() ;
640 //char * bsn = strchr( nameservice , '\n' ) ;
644 //command += nameservice ;
646 char *iorstr = _NS->getIORaddr();
647 command += "ORBInitRef NameService=";
652 //=============================================================================
654 * add to command all options relative to naming service.
656 //=============================================================================
658 void SALOME_ResourcesManager::AddOmninamesParams(ofstream& fileStream) const
660 string omniORBcfg( getenv( "OMNIORB_CONFIG" ) ) ;
661 ifstream omniORBfile( omniORBcfg.c_str() ) ;
662 char ORBInitRef[11] ;
664 char nameservice[132] ;
665 omniORBfile >> ORBInitRef ;
666 fileStream << "ORBInitRef ";
667 omniORBfile >> egal ;
668 omniORBfile >> nameservice ;
669 omniORBfile.close() ;
670 char * bsn = strchr( nameservice , '\n' ) ;
677 fileStream << nameservice;
681 //=============================================================================
683 * generate a file name in /tmp directory
685 //=============================================================================
687 string SALOME_ResourcesManager::BuildTemporaryFileName() const
689 //build more complex file name to support multiple salome session
690 char *temp = new char[19];
691 strcpy(temp, "/tmp/command");
692 strcat(temp, "XXXXXX");
699 itoa(getpid(), aPID, 10);
703 string command(temp);
710 //=============================================================================
712 * Builds in a temporary file the script to be launched.
714 * Used if SALOME Application ($APPLI) is not defined.
715 * The command is build with data from CatalogResources, in which every path
716 * used on remote computer must be defined.
718 //=============================================================================
721 SALOME_ResourcesManager::BuildTempFileToLaunchRemoteContainer
722 (const string& machine,
723 const Engines::MachineParameters& params)
725 _TmpFileName = BuildTemporaryFileName();
726 ofstream tempOutputFile;
727 tempOutputFile.open(_TmpFileName.c_str(), ofstream::out );
728 const ParserResourcesType& resInfo = _resourcesList[machine];
729 tempOutputFile << "#! /bin/sh" << endl;
733 for (map<string, string>::const_iterator iter = resInfo.ModulesPath.begin();
734 iter != resInfo.ModulesPath.end();
737 string curModulePath((*iter).second);
738 tempOutputFile << (*iter).first << "_ROOT_DIR=" << curModulePath << endl;
739 tempOutputFile << "export " << (*iter).first << "_ROOT_DIR" << endl;
740 tempOutputFile << "LD_LIBRARY_PATH=" << curModulePath
741 << "/lib/salome" << ":${LD_LIBRARY_PATH}" << endl;
742 tempOutputFile << "PYTHONPATH=" << curModulePath << "/bin/salome:"
743 << curModulePath << "/lib/salome:" << curModulePath
744 << "/lib/python2.2/site-packages/salome:";
745 tempOutputFile << curModulePath
746 << "/lib/python2.2/site-packages/salome/shared_modules:${PYTHONPATH}"
750 tempOutputFile << "export LD_LIBRARY_PATH" << endl;
751 tempOutputFile << "export PYTHONPATH" << endl;
752 tempOutputFile << "source " << resInfo.PreReqFilePath << endl;
758 tempOutputFile << "mpirun -np ";
761 if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
763 else if ( params.nb_node == 0 )
764 nbproc = params.nb_proc_per_node;
765 else if ( params.nb_proc_per_node == 0 )
766 nbproc = params.nb_node;
768 nbproc = params.nb_node * params.nb_proc_per_node;
770 std::ostringstream o;
772 tempOutputFile << nbproc << " ";
775 tempOutputFile << (*(resInfo.ModulesPath.find("KERNEL"))).second
780 if (isPythonContainer(params.container_name))
781 tempOutputFile << "pyMPI SALOME_ContainerPy.py ";
783 tempOutputFile << "SALOME_MPIContainer ";
788 if (isPythonContainer(params.container_name))
789 tempOutputFile << "SALOME_ContainerPy.py ";
791 tempOutputFile << "SALOME_Container ";
794 tempOutputFile << _NS->ContainerName(params) << " -";
795 AddOmninamesParams(tempOutputFile);
796 tempOutputFile << " &" << endl;
797 tempOutputFile.flush();
798 tempOutputFile.close();
799 chmod(_TmpFileName.c_str(), 0x1ED);
805 if (resInfo.Protocol == rsh)
808 string commandRcp = "rcp ";
809 commandRcp += _TmpFileName;
811 commandRcp += machine;
813 commandRcp += _TmpFileName;
814 system(commandRcp.c_str());
817 else if (resInfo.Protocol == ssh)
820 throw SALOME_Exception("Unknown protocol");
823 _CommandForRemAccess = command;
825 command += _TmpFileName;
828 command += _NS->ContainerName(params);
831 command += ".log 2>&1 &";