1 // Copyright (C) 2007-2024 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include "ResourcesManager.hxx"
25 #include "SALOME_ResourcesCatalog_Handler.hxx"
26 #include <Basics_Utils.hxx>
27 #include <Basics_DirUtils.hxx>
28 #include "utilities.h"
36 #include <sys/types.h>
42 #include <libxml/parser.h>
47 #define MAX_SIZE_FOR_HOSTNAME 256;
51 const string ResourcesManager_cpp::DEFAULT_RESOURCE_NAME = "localhost";
53 static LoadRateManagerFirst first;
54 static LoadRateManagerCycl cycl;
55 static LoadRateManagerAltCycl altcycl;
57 resourceParams::resourceParams()
58 : can_launch_batch_jobs(false),
59 can_run_containers(false),
68 //=============================================================================
72 //=============================================================================
74 ResourcesManager_cpp::
75 ResourcesManager_cpp(const char *xmlFilePath)
77 _path_resources.push_back(xmlFilePath);
78 #if defined(_DEBUG_) || defined(_DEBUG)
79 std::cerr << "ResourcesManager_cpp constructor" << std::endl;
81 _resourceManagerMap["first"]=&first;
82 _resourceManagerMap["cycl"]=&cycl;
83 _resourceManagerMap["altcycl"]=&altcycl;
84 _resourceManagerMap["best"]=&altcycl;
85 _resourceManagerMap[""]=&altcycl;
87 AddDefaultResourceInCatalog();
91 //=============================================================================
93 * Standard constructor, parse resource file.
94 * - if ${APPLI} exists in environment,
95 * look for ${HOME}/${APPLI}/CatalogResources.xml
96 * - else look for default:
97 * ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
98 * - parse XML resource file.
100 //=============================================================================
102 ResourcesManager_cpp::ResourcesManager_cpp()
104 RES_MESSAGE("ResourcesManager_cpp constructor");
106 _resourceManagerMap["first"]=&first;
107 _resourceManagerMap["cycl"]=&cycl;
108 _resourceManagerMap["altcycl"]=&altcycl;
109 _resourceManagerMap["best"]=&altcycl;
110 _resourceManagerMap[""]=&altcycl;
112 AddDefaultResourceInCatalog();
114 bool default_catalog_resource = true;
115 if (getenv("USER_CATALOG_RESOURCES_FILE") != 0)
117 default_catalog_resource = false;
118 std::string user_file("");
119 user_file = getenv("USER_CATALOG_RESOURCES_FILE");
120 std::ifstream ifile(user_file.c_str(), std::ifstream::in );
122 // The file exists, and is open for input
123 DEBUG_MESSAGE("USER_CATALOG_RESOURCES_FILE positioned -> add it into resourcefiles list");
124 _path_resources.push_back(user_file);
127 default_catalog_resource = false;
128 WARNING_MESSAGE("Warning: USER_CATALOG_RESOURCES_FILE is set and file cannot be found.")
129 WARNING_MESSAGE("Warning: That's why we try to create a new one.")
130 std::ofstream user_catalog_file;
131 user_catalog_file.open(user_file.c_str());
132 if (user_catalog_file.fail())
134 WARNING_MESSAGE("Error: cannot write in the user catalog resources files");
135 WARNING_MESSAGE("Error: using default CatalogResources.xml file");
136 default_catalog_resource = true;
140 user_catalog_file << "<!-- File created by SALOME -->" << std::endl;
141 user_catalog_file << "<!DOCTYPE ResourcesCatalog>" << std::endl;
142 user_catalog_file << "<resources>" << std::endl;
143 user_catalog_file << " <machine name=\"localhost\" hostname=\"localhost\" />" << std::endl;
144 user_catalog_file << "</resources>" << std::endl;
145 user_catalog_file.close();
149 if (default_catalog_resource)
151 std::string default_file("");
152 if (getenv("APPLI") != 0)
154 default_file += Kernel_Utils::HomePath();
156 default_file += getenv("APPLI");
157 default_file += "/CatalogResources.xml";
158 std::ifstream ifile(default_file.c_str(), std::ifstream::in );
160 // The file exists, and is open for input
161 DEBUG_MESSAGE("${APPLI}/CatalogResources.xml exists -> add it into resourcefiles list");
162 _path_resources.push_back(default_file);
163 default_catalog_resource=false;
167 if (default_catalog_resource)
169 std::string default_file("");
170 if(!getenv("KERNEL_ROOT_DIR"))
171 throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
172 default_file = getenv("KERNEL_ROOT_DIR");
173 default_file += "/share/salome/resources/kernel/CatalogResources.xml";
174 DEBUG_MESSAGE("${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml -> add it into resourcefiles list");
175 _path_resources.push_back(default_file);
179 RES_MESSAGE("ResourcesManager_cpp constructor end");
182 //=============================================================================
184 * Standard Destructor
186 //=============================================================================
188 ResourcesManager_cpp::~ResourcesManager_cpp()
190 RES_MESSAGE("ResourcesManager_cpp destructor");
193 //=============================================================================
194 //! get the list of resource names fitting constraints given by params
197 * 1: Restrict list with resourceList if defined
198 * 2: If name is defined -> check resource list
199 * 3: If not 2:, if hostname is defined -> check resource list
200 * 4: If not 3:, sort resource with nb_proc, etc...
201 * 5: In all cases remove resource that does not correspond with OS
202 * 6: And remove resource with componentList - if list is empty ignored it...
204 //=============================================================================
206 std::vector<std::string>
207 ResourcesManager_cpp::GetFittingResources(const resourceParams& params)
209 RES_MESSAGE("[GetFittingResources] on computer " << Kernel_Utils::GetHostname().c_str());
210 RES_MESSAGE("[GetFittingResources] with resource name: " << params.name);
211 RES_MESSAGE("[GetFittingResources] with hostname: "<< params.hostname);
214 std::vector<std::string> vec;
216 // Parse Again CalatogResource File
220 // 1: If name is defined -> check resource list
221 // 2: Restrict list with resourceList if defined
222 // 3: If not 2:, if hostname is defined -> check resource list
223 // 4: If not 3:, sort resource with nb_proc, etc...
224 // 5: In all cases remove resource that does not correspond with OS
225 // 6: And remove resource with componentList - if list is empty ignored it...
228 if (params.name != "")
230 RES_MESSAGE("[GetFittingResources] name parameter found !");
231 if (_resourcesList.find(params.name) != _resourcesList.end())
233 vec.push_back(params.name);
237 RES_MESSAGE("[GetFittingResources] resource name was not found on resource list ! name requested was " << params.name);
238 std::string error("[GetFittingResources] resource name was not found on resource list ! name requested was " + params.name);
239 throw ResourcesException(error);
242 MapOfParserResourcesType local_resourcesList = _resourcesList;
244 if (params.resourceList.size() > 0)
246 RES_MESSAGE("[GetFittingResources] Restricted resource list found !");
247 local_resourcesList.clear();
248 std::vector<std::string>::size_type sz = params.resourceList.size();
250 for (unsigned int i=0; i < sz; i++)
252 if (_resourcesList.find(params.resourceList[i]) != _resourcesList.end())
253 local_resourcesList[params.resourceList[i]] = _resourcesList[params.resourceList[i]];
258 if (params.hostname != "")
260 RES_MESSAGE("[GetFittingResources] Entering in hostname case !");
262 std::string hostname = params.hostname;
263 if (hostname == "localhost")
264 hostname = Kernel_Utils::GetHostname().c_str();
266 std::map<std::string, ParserResourcesType>::const_iterator iter = _resourcesList.begin();
267 for (; iter != _resourcesList.end(); iter++)
269 if ((*iter).second.HostName == hostname)
270 vec.push_back((*iter).first);
276 // --- Search for available resources sorted by priority
277 MapOfParserResourcesType_it i = local_resourcesList.begin();
278 for (; i != local_resourcesList.end(); ++i)
279 vec.push_back(i->first);
281 // --- set wanted parameters
282 ResourceDataToSort::_nbOfProcWanted = params.nb_proc;
283 ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
284 ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
285 ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
286 ResourceDataToSort::_memInMBWanted = params.mem_mb;
290 std::list<ResourceDataToSort> li;
291 std::vector<std::string>::iterator iter = vec.begin();
292 for (; iter != vec.end(); iter++)
293 li.push_back(local_resourcesList[(*iter)].DataForSort);
297 for (std::list<ResourceDataToSort>::iterator iter2 = li.begin(); iter2 != li.end(); iter2++)
298 vec.push_back((*iter2)._Name);
302 SelectOnlyResourcesWithOS(vec, params.OS.c_str());
305 std::vector<std::string> vec_save(vec);
306 KeepOnlyResourcesWithComponent(vec, params.componentList);
310 // Step 7 : Filter on possible usage
311 vector<string> prev_list(vec);
313 for (vector<string>::iterator iter = prev_list.begin() ; iter != prev_list.end() ; iter++)
315 MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
316 if (it != _resourcesList.end() &&
317 (!params.can_launch_batch_jobs || it->second.can_launch_batch_jobs) &&
318 (!params.can_run_containers || it->second.can_run_containers))
319 vec.push_back(*iter);
323 // Send an exception if return list is empty...
326 std::string error("[GetFittingResources] ResourcesManager doesn't find any resource that fits to your parameters");
327 throw ResourcesException(error);
333 void ResourcesManager_cpp::AddResourceInCatalogNoQuestion (const ParserResourcesType & new_resource)
335 _resourcesList[new_resource.Name] = new_resource;
338 //=============================================================================
340 * add an entry in the resources catalog xml file.
342 //=============================================================================
345 ResourcesManager_cpp::AddResourceInCatalog(const ParserResourcesType & new_resource)
347 if (new_resource.Name == DEFAULT_RESOURCE_NAME){
348 ParserResourcesType default_resource = _resourcesList[DEFAULT_RESOURCE_NAME];
349 // some of the properties of the default resource shouldn't be modified
351 if( default_resource.HostName != new_resource.HostName)
352 check += "The Hostname property of the default resource can not be modified.\n";
353 if( default_resource.AppliPath != new_resource.AppliPath)
354 check += "The Applipath property of the default resource can not be modified.\n";
355 if( !new_resource.can_run_containers)
356 check += "The default resource should be able to run containers.\n";
357 if( !new_resource.can_launch_batch_jobs)
358 check += "The default resource should be able to launch batch jobs.\n";
359 if( default_resource.Protocol != new_resource.Protocol)
360 check += "The Protocol property of the default resource can not be modified.\n";
362 throw ResourcesException(check);
364 // TODO - Add minimal check
365 this->AddResourceInCatalogNoQuestion( new_resource );
368 void ResourcesManager_cpp::DeleteAllResourcesInCatalog()
370 _resourcesList.clear();
373 //=============================================================================
375 * Deletes a resource from the catalog
377 //=============================================================================
379 void ResourcesManager_cpp::DeleteResourceInCatalog(const char * name)
381 if (DEFAULT_RESOURCE_NAME == name){
382 std::string error("Cannot delete default local resource \"" + DEFAULT_RESOURCE_NAME + "\"");
383 throw ResourcesException(error);
385 MapOfParserResourcesType_it it = _resourcesList.find(name);
386 if (it != _resourcesList.end())
387 _resourcesList.erase(name);
389 RES_INFOS("You try to delete a resource that does not exist... : " << name);
392 //=============================================================================
394 * write the current data in memory in file.
396 //=============================================================================
398 void ResourcesManager_cpp::WriteInXmlFile(std::string xml_file)
400 RES_MESSAGE("WriteInXmlFile : start");
402 MapOfParserResourcesType resourceListToSave(_resourcesList);
403 if (resourceListToSave.empty())
405 RES_MESSAGE("WriteInXmlFile: nothing to do, no resource to save!");
411 _path_resources_it = _path_resources.begin();
412 xml_file = *_path_resources_it;
415 const char* aFilePath = xml_file.c_str();
416 FILE* aFile = fopen(aFilePath, "w");
420 std::cerr << "Error opening file in WriteInXmlFile : " << xml_file << std::endl;
424 xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
425 xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
427 SALOME_ResourcesCatalog_Handler* handler =
428 new SALOME_ResourcesCatalog_Handler(resourceListToSave);
429 handler->PrepareDocToXmlFile(aDoc);
432 int isOk = xmlSaveFormatFile(aFilePath, aDoc, 1);
434 std::cerr << "Error while XML file saving : " << xml_file << std::endl;
439 RES_MESSAGE("WriteInXmlFile : WRITING DONE!");
442 //=============================================================================
444 * parse the data type catalog
446 //=============================================================================
448 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
450 // Parse file only if its modification time is greater than lasttime (last registered modification time)
451 bool to_parse = false;
452 for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
454 struct stat statinfo;
455 int result = stat((*_path_resources_it).c_str(), &statinfo);
458 WARNING_MESSAGE("Resource file " << *_path_resources_it << " does not exist -> no parsing");
459 return _resourcesList;
462 if(_lasttime == 0 || statinfo.st_mtime > _lasttime)
464 DEBUG_MESSAGE("Resource file " << *_path_resources_it << " has been detected to be present and newer than Resources in memory");
466 _lasttime = statinfo.st_mtime;
472 DEBUG_MESSAGE("After analyze of resoure files time meta data, a load of resources from scratch from files is necessary.");
473 _resourcesList.clear();
474 AddDefaultResourceInCatalog();
475 // On parse tous les fichiers
476 for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
478 MapOfParserResourcesType _resourcesList_tmp;
479 MapOfParserResourcesType _resourcesBatchList_tmp;
480 std::unique_ptr<SALOME_ResourcesCatalog_Handler> handler( new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp) );
481 const char *aFilePath( (*_path_resources_it).c_str() );
482 FILE* aFile = fopen(aFilePath, "r");
485 xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
488 DEBUG_MESSAGE("XML parsing of Resource file \"" << aFilePath << "\"");
489 handler->ProcessXmlDocument(aDoc);
491 // adding new resources to the file
492 for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
494 MapOfParserResourcesType_it j = _resourcesList.find(i->first);
495 if (i->second.HostName == DEFAULT_RESOURCE_NAME || i->second.HostName == Kernel_Utils::GetHostname())
497 DEBUG_MESSAGE("Resource \"" << i->first << "\" in file \"" << aFilePath << "\" is detected as localhost");
498 MapOfParserResourcesType_it it0(_resourcesList.find(DEFAULT_RESOURCE_NAME));
499 if(it0!=_resourcesList.end())
501 DEBUG_MESSAGE("Resource \"" << i->first << "\" in file \"" << aFilePath << "\" detected as localhost is already in memory -> update resource with content in file ( for attributes : nbOfNodes, nbOfProcPerNode, CPUFreqMHz and memInMB)");
502 ParserResourcesType& localhostElt((*it0).second);
503 localhostElt.DataForSort._nbOfNodes=(*i).second.DataForSort._nbOfNodes;
504 localhostElt.DataForSort._nbOfProcPerNode=(*i).second.DataForSort._nbOfProcPerNode;
505 localhostElt.DataForSort._CPUFreqMHz=(*i).second.DataForSort._CPUFreqMHz;
506 localhostElt.DataForSort._memInMB=(*i).second.DataForSort._memInMB;
508 DEBUG_MESSAGE("Resource \"" << i->first << "\" is not added because it is the same machine as default local resource \"" << DEFAULT_RESOURCE_NAME << "\"");
510 else if (j != _resourcesList.end())
512 WARNING_MESSAGE("ParseXmlFiles Warning, two resources with the same name were found, taking the first declaration : " << i->first );
516 DEBUG_MESSAGE("Resource \"" << i->first << "\" added");
517 _resourcesList[i->first] = i->second;
522 ERROR_MESSAGE( "ResourcesManager_cpp: could not parse file " << aFilePath );
528 ERROR_MESSAGE( "ResourcesManager_cpp: file " << aFilePath << " is not readable." );
531 return _resourcesList;
534 //=============================================================================
536 * consult the content of the list
538 //=============================================================================
540 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
542 return _resourcesList;
546 std::string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources) const
548 std::map<std::string , LoadRateManager*>::const_iterator it(_resourceManagerMap.find(policy));
549 if(it==_resourceManagerMap.end())
551 it=_resourceManagerMap.find("");
552 return ((*it).second)->Find(listOfResources, _resourcesList);
554 return ((*it).second)->Find(listOfResources, _resourcesList);
557 //=============================================================================
559 * Gives a sublist of resources with matching OS.
560 * If parameter OS is empty, gives the complete list of resources
562 //=============================================================================
564 ResourcesManager_cpp::SelectOnlyResourcesWithOS(std::vector<std::string>& resources, std::string OS)
568 // a computer list is given : take only resources with OS on those computers
569 std::vector<std::string> vec_tmp = resources;
571 std::vector<std::string>::iterator iter = vec_tmp.begin();
572 for (; iter != vec_tmp.end(); iter++)
574 MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
575 if(it != _resourcesList.end())
576 if ( (*it).second.OS == OS)
577 resources.push_back(*iter);
583 //=============================================================================
585 * Gives a sublist of machines on which the component is known.
587 //=============================================================================
589 ResourcesManager_cpp::KeepOnlyResourcesWithComponent(std::vector<std::string>& resources,
590 const std::vector<std::string>& componentList)
592 std::vector<std::string> kept_resources;
594 std::vector<std::string>::iterator iter = resources.begin();
595 for (; iter != resources.end(); iter++)
597 const std::vector<std::string>& mapOfComponentsOfCurrentHost = _resourcesList[*iter].ComponentsList;
599 bool erasedHost = false;
600 if( mapOfComponentsOfCurrentHost.size() > 0 )
602 for(unsigned int i=0; i<componentList.size(); i++)
604 std::vector<std::string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
605 mapOfComponentsOfCurrentHost.end(),
607 if (itt == mapOfComponentsOfCurrentHost.end())
615 kept_resources.push_back(*iter);
617 resources=kept_resources;
621 ParserResourcesType ResourcesManager_cpp::GetResourcesDescr(const std::string & name) const
623 MapOfParserResourcesType::const_iterator it(_resourcesList.find(name));
624 if (it != _resourcesList.end())
628 std::string error("[GetResourcesDescr] Resource does not exist: ");
630 throw ResourcesException(error);
634 void ResourcesManager_cpp::AddDefaultResourceInCatalog()
636 ParserResourcesType resource;
637 resource.Name = DEFAULT_RESOURCE_NAME;
638 // We can't use "localhost" for parameter hostname because the containers are registered in the
639 // naming service with the real hostname, not "localhost"
640 resource.HostName = Kernel_Utils::GetHostname();
641 resource.DataForSort._Name = DEFAULT_RESOURCE_NAME;
642 resource.Protocol = sh;
643 resource.Batch = none;
646 std::string aHomePath = Kernel_Utils::HomePath();
647 if (aHomePath != "" && getenv("APPLI") != NULL)
649 if (stat(getenv("APPLI"), &statbuf) ==0 && S_ISREG(statbuf.st_mode))
651 // if $APPLI is a regular file, we asume it's a salome Launcher file
652 resource.AppliPath = string(getenv("APPLI"));
656 resource.AppliPath = aHomePath + "/" + getenv("APPLI");
659 string tmpdir = "/tmp";
660 if (getenv("TMPDIR") != NULL)
661 tmpdir = getenv("TMPDIR");
662 resource.working_directory = tmpdir + "/salome_localres_workdir";
663 if (getenv("USER") != NULL)
664 resource.working_directory += string("_") + getenv("USER");
666 if (getenv("USERPROFILE") != NULL && getenv("APPLI") != NULL)
668 resource.AppliPath = string(getenv("USERPROFILE")) + "\\" + getenv("APPLI");
670 string tmpdir = "C:\\tmp";
671 if (getenv("TEMP") != NULL)
672 tmpdir = getenv("TEMP");
673 resource.working_directory = tmpdir + "\\salome_localres_workdir";
674 if (getenv("USERNAME") != NULL)
675 resource.working_directory += string("_") + getenv("USERNAME");
677 resource.can_launch_batch_jobs = true;
678 resource.can_run_containers = true;
679 _resourcesList[resource.Name] = resource;
680 DEBUG_MESSAGE("Put Ressource \"" << resource.Name << "\" in dictionary of resources. This resource will be present even if resource files define it later.");