Salome HOME
merge from BR_V51_AR 7 may 09
[modules/kernel.git] / src / ResourcesManager / ResourcesManager.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 #include "ResourcesManager.hxx" 
23 #include <Basics_Utils.hxx>
24 #include <fstream>
25 #include <iostream>
26 #include <sstream>
27 #include <string.h>
28 #include <map>
29 #include <list>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #ifdef WNT
33 #else
34 #include <unistd.h>
35 #endif
36 #include <libxml/parser.h>
37
38 #include <algorithm>
39
40 #define MAX_SIZE_FOR_HOSTNAME 256;
41
42 using namespace std;
43
44 static LoadRateManagerFirst first;
45 static LoadRateManagerCycl cycl;
46 static LoadRateManagerAltCycl altcycl;
47 //=============================================================================
48 /*!
49  * just for test
50  */ 
51 //=============================================================================
52
53 ResourcesManager_cpp::
54 ResourcesManager_cpp(const char *xmlFilePath)
55 {
56   _path_resources.push_back(xmlFilePath);
57 #if defined(_DEBUG_) || defined(_DEBUG)
58   cerr << "ResourcesManager_cpp constructor" << endl;
59 #endif
60   _resourceManagerMap["first"]=&first;
61   _resourceManagerMap["cycl"]=&cycl;
62   _resourceManagerMap["altcycl"]=&altcycl;
63   _resourceManagerMap["best"]=&altcycl;
64   _resourceManagerMap[""]=&altcycl;
65 }
66
67 //=============================================================================
68 /*!
69  *  Standard constructor, parse resource file.
70  *  - if ${APPLI} exists in environment,
71  *    look for ${HOME}/${APPLI}/CatalogResources.xml
72  *  - else look for default:
73  *    ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
74  *  - parse XML resource file.
75  */ 
76 //=============================================================================
77
78 ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
79 {
80 #if defined(_DEBUG_) || defined(_DEBUG)
81   cerr << "ResourcesManager_cpp constructor" << endl;
82 #endif
83   _resourceManagerMap["first"]=&first;
84   _resourceManagerMap["cycl"]=&cycl;
85   _resourceManagerMap["altcycl"]=&altcycl;
86   _resourceManagerMap["best"]=&altcycl;
87   _resourceManagerMap[""]=&altcycl;
88
89   std::string default_file("");
90   if (getenv("APPLI") != 0)
91     {
92       default_file += getenv("HOME");
93       default_file += "/";
94       default_file += getenv("APPLI");
95       default_file += "/CatalogResources.xml";
96       _path_resources.push_back(default_file);
97     }
98   else
99     {
100       if(!getenv("KERNEL_ROOT_DIR"))
101         throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
102       default_file = getenv("KERNEL_ROOT_DIR");
103       default_file += "/share/salome/resources/kernel/CatalogResources.xml";
104       _path_resources.push_back(default_file);
105     }
106
107   if (getenv("USER_CATALOG_RESOURCES_FILE") != 0)
108   {
109     std::string user_file("");
110     user_file = getenv("USER_CATALOG_RESOURCES_FILE");
111     _path_resources.push_back(user_file);
112   }
113
114   _lasttime=0;
115
116   ParseXmlFiles();
117 #if defined(_DEBUG_) || defined(_DEBUG)
118   cerr << "ResourcesManager_cpp constructor end";
119 #endif
120 }
121
122 //=============================================================================
123 /*!
124  *  Standard Destructor
125  */ 
126 //=============================================================================
127
128 ResourcesManager_cpp::~ResourcesManager_cpp()
129 {
130 #if defined(_DEBUG_) || defined(_DEBUG)
131   cerr << "ResourcesManager_cpp destructor" << endl;
132 #endif
133 }
134
135 //=============================================================================
136 //! get the list of resource names fitting constraints given by params
137 /*!
138  *  If hostname is specified, check if it is local or known in resources catalog.
139  *
140  *  Else
141  *  - select first machines with corresponding OS (all machines if
142  *    parameter OS empty),
143  *  - then select the sublist of machines on which the component is known
144  *    (if the result is empty, that probably means that the inventory of
145  *    components is probably not done, so give complete list from previous step)
146  */ 
147 //=============================================================================
148
149 std::vector<std::string> 
150 ResourcesManager_cpp::GetFittingResources(const machineParams& params) throw(ResourcesException)
151 {
152   vector <std::string> vec;
153
154   ParseXmlFiles();
155
156   const char *hostname = params.hostname.c_str();
157 #if defined(_DEBUG_) || defined(_DEBUG)
158   cerr << "GetFittingResources " << hostname << " " << Kernel_Utils::GetHostname().c_str() << endl;
159 #endif
160
161   // PaCO++ parallel container case
162   std::string parallelLib(params.parallelLib);
163   if (params.nb_component_nodes > 0 and parallelLib != "")
164   {
165 #if defined(_DEBUG_) || defined(_DEBUG)
166     std::cerr << "[GetFittingResources] ParallelContainer case" << std::endl;
167     std::cerr << "[GetFittingResources] parallelLib is " << parallelLib << std::endl;
168     std::cerr << "[GetFittingResources] nb_component_nodes is " << params.nb_component_nodes << std::endl;
169 #endif
170
171     // Currently we only support parallel containers that define a hostname target
172     if (hostname[0] != '\0')
173     {
174       // Special case of localhost -> put containers into the real computer name
175       if (strcmp(hostname, "localhost") == 0)
176         vec.push_back(Kernel_Utils::GetHostname().c_str());
177       else 
178       {
179         // Try find the resource into the map
180         if (_resourcesList.find(hostname) != _resourcesList.end())
181           vec.push_back(hostname);
182         else
183           std::cerr << "[GetFittingResources] ParallelContainer hostname does not exist into the resource list !" << std::endl;
184       }
185     }
186     else
187       std::cerr << "[GetFittingResources] ParallelContainer hostname is empty -> cannot find a possible resource" << std::endl;
188     return vec;
189   }
190
191   if (hostname[0] != '\0'){
192
193     if ( strcmp(hostname, "localhost") == 0 ||
194          strcmp(hostname, Kernel_Utils::GetHostname().c_str()) == 0 )
195       {
196 //#if defined(_DEBUG_) || defined(_DEBUG)
197 //      cerr << "ResourcesManager_cpp::GetFittingResources : localhost" << endl;
198 //#endif
199         vec.push_back(Kernel_Utils::GetHostname().c_str());
200 //#if defined(_DEBUG_) || defined(_DEBUG)
201 //      cerr << "ResourcesManager_cpp::GetFittingResources : " << vec.size() << endl;
202 //#endif
203       }
204         
205     else if (_resourcesList.find(hostname) != _resourcesList.end())
206       {
207         // --- params.hostname is in the list of resources so return it.
208         vec.push_back(hostname);
209       }
210         
211     else if (_resourcesBatchList.find(hostname) != _resourcesBatchList.end())
212     {
213       // --- params.hostname is in the list of resources so return it.
214       vec.push_back(hostname);
215     }
216
217     else
218       {
219         // Cas d'un cluster: nombre de noeuds > 1
220         int cpt=0;
221         for (map<string, ParserResourcesType>::const_iterator iter = _resourcesList.begin(); iter != _resourcesList.end(); iter++){
222           if( (*iter).second.DataForSort._nbOfNodes > 1 ){
223             if( strncmp(hostname,(*iter).first.c_str(),strlen(hostname)) == 0 ){
224               vec.push_back((*iter).first.c_str());
225               cpt++;
226             }
227           }
228         }
229         if(cpt==0){
230           // --- user specified an unknown hostame so notify him.
231 #if defined(_DEBUG_) || defined(_DEBUG)
232           cerr << "ResourcesManager_cpp::GetFittingResources : SALOME_Exception" << endl;
233 #endif
234           std::string error("GetFittinResouces : ResourcesManager doesn't find the host requested : ");
235           error += hostname;
236           throw ResourcesException(error);
237         }
238       }
239   }
240     
241   else{
242     // --- Search for available resources sorted by priority
243     vec=params.computerList;
244
245     SelectOnlyResourcesWithOS(vec, params.OS.c_str());
246       
247     KeepOnlyResourcesWithComponent(vec, params.componentList);
248
249     //if hosts list (vec) is empty, ignore componentList constraint and use only OS constraint
250     if (vec.size() == 0)
251       SelectOnlyResourcesWithOS(vec, params.OS.c_str());
252     
253     // --- set wanted parameters
254     ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
255       
256     ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
257         
258     ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
259         
260     ResourceDataToSort::_memInMBWanted = params.mem_mb;
261         
262     // --- end of set
263         
264     list<ResourceDataToSort> li;
265         
266     for (vector<string>::iterator iter = vec.begin();
267          iter != vec.end();
268          iter++)
269       li.push_back(_resourcesList[(*iter)].DataForSort);
270         
271     li.sort();
272         
273     unsigned int i = 0;
274         
275     for (list<ResourceDataToSort>::iterator iter2 = li.begin();
276          iter2 != li.end();
277          iter2++)
278       vec[i++] = (*iter2)._hostName;
279   }
280     
281   return vec;
282
283 }
284
285 //=============================================================================
286 /*!
287  *  add an entry in the ressources catalog  xml file.
288  *  Return 0 if OK (KERNEL found in new resources components) else throw exception
289  */ 
290 //=============================================================================
291
292 int
293 ResourcesManager_cpp::
294 AddResourceInCatalog(const machineParams& paramsOfNewResources,
295                      const vector<string>& componentsOnNewResources,
296                      const char *alias,
297                      const char *userName,
298                      AccessModeType mode,
299                      AccessProtocolType prot)
300 throw(ResourcesException)
301 {
302   vector<string>::const_iterator iter = find(componentsOnNewResources.begin(),
303                                              componentsOnNewResources.end(),
304                                              "KERNEL");
305
306   if (iter != componentsOnNewResources.end())
307     {
308       ParserResourcesType newElt;
309       newElt.DataForSort._hostName = paramsOfNewResources.hostname;
310       newElt.Alias = alias;
311       newElt.Protocol = prot;
312       newElt.Mode = mode;
313       newElt.UserName = userName;
314       newElt.ComponentsList = componentsOnNewResources;
315       newElt.OS = paramsOfNewResources.OS;
316       newElt.DataForSort._memInMB = paramsOfNewResources.mem_mb;
317       newElt.DataForSort._CPUFreqMHz = paramsOfNewResources.cpu_clock;
318       newElt.DataForSort._nbOfNodes = paramsOfNewResources.nb_node;
319       newElt.DataForSort._nbOfProcPerNode =
320         paramsOfNewResources.nb_proc_per_node;
321       _resourcesList[newElt.DataForSort._hostName] = newElt;
322       return 0;
323     }
324
325   else
326     throw ResourcesException("KERNEL is not present in this resource");
327 }
328
329 //=============================================================================
330 /*!
331  *  Deletes a resource from the catalog
332  */ 
333 //=============================================================================
334
335 void ResourcesManager_cpp::DeleteResourceInCatalog(const char *hostname)
336 {
337   _resourcesList.erase(hostname);
338 }
339
340 //=============================================================================
341 /*!
342  *  write the current data in memory in file.
343  */ 
344 //=============================================================================
345
346 void ResourcesManager_cpp::WriteInXmlFile(std::string & xml_file)
347 {
348 #if defined(_DEBUG_) || defined(_DEBUG)
349   std::cerr << "WriteInXmlFile : start" << std::endl;
350 #endif
351   const char* aFilePath = xml_file.c_str();
352   FILE* aFile = fopen(aFilePath, "w");
353
354   if (aFile == NULL)
355   {
356     std::cerr << "Error opening file in WriteInXmlFile : " << xml_file << std::endl;
357     return;
358   }
359   
360   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
361   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
362
363   SALOME_ResourcesCatalog_Handler* handler =
364     new SALOME_ResourcesCatalog_Handler(_resourcesList, _resourcesBatchList);
365   handler->PrepareDocToXmlFile(aDoc);
366   delete handler;
367
368   int isOk = xmlSaveFile(aFilePath, aDoc);
369   if (!isOk) 
370      std::cerr << "Error while XML file saving : " << xml_file << std::endl;
371   
372   // Free the document
373   xmlFreeDoc(aDoc);
374   fclose(aFile);
375 #if defined(_DEBUG_) || defined(_DEBUG)
376   std::cerr << "WriteInXmlFile : WRITING DONE!" << std::endl;
377 #endif
378 }
379
380 //=============================================================================
381 /*!
382  *  parse the data type catalog
383  */ 
384 //=============================================================================
385
386 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
387 {
388   // Parse file only if its modification time is greater than lasttime (last registered modification time)
389   bool to_parse = false;
390   for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
391   {
392     struct stat statinfo;
393     int result = stat((*_path_resources_it).c_str(), &statinfo);
394     if (result < 0)
395     {
396       std::cerr << "Error in method stat for file : " << (*_path_resources_it).c_str() << " no new xml file is parsed" << std::endl;
397       return _resourcesList;
398     }
399
400     if(statinfo.st_mtime > _lasttime)
401     {
402       to_parse = true;
403       _lasttime = statinfo.st_mtime;
404     }
405   }
406
407   if (to_parse)
408   {
409     _resourcesList.clear();
410     _resourcesBatchList.clear();
411     // On parse tous les fichiers
412     for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
413     {
414       MapOfParserResourcesType _resourcesList_tmp;
415       MapOfParserResourcesType _resourcesBatchList_tmp;
416       SALOME_ResourcesCatalog_Handler* handler =
417         new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp, _resourcesBatchList_tmp);
418       const char* aFilePath = (*_path_resources_it).c_str();
419       FILE* aFile = fopen(aFilePath, "r");
420
421       if (aFile != NULL)
422       {
423         xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
424         if (aDoc != NULL)
425         {
426           handler->ProcessXmlDocument(aDoc);
427
428           // adding new resources to the file
429           for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
430           {
431             MapOfParserResourcesType_it j = _resourcesList.find(i->first);
432             if (j == _resourcesList.end())
433             {
434               _resourcesList[i->first] = i->second;
435             }
436             else
437             {
438               std::cerr << "ParseXmlFiles Warning, to resource with the same name was found, taking the first declaration : " << i->first << std::endl;
439             }
440           }
441           for (MapOfParserResourcesType_it i = _resourcesBatchList_tmp.begin(); i != _resourcesBatchList_tmp.end(); ++i)
442           {
443             MapOfParserResourcesType_it j = _resourcesBatchList.find(i->first);
444             if (j == _resourcesBatchList.end())
445             {
446               _resourcesBatchList[i->first] = i->second;
447             }
448             else
449             {
450               std::cerr << "ParseXmlFiles Warning, to resource with the same name was found, taking the first declaration : " << i->first << std::endl;
451             }
452           }
453         }
454         else
455           std::cerr << "ResourcesManager_cpp: could not parse file " << aFilePath << std::endl;
456         // Free the document
457         xmlFreeDoc(aDoc);
458         fclose(aFile);
459       }
460       else
461         std::cerr << "ResourcesManager_cpp: file " << aFilePath << " is not readable." << std::endl;
462
463       delete handler;
464     }
465   }
466   return _resourcesList;
467 }
468
469 //=============================================================================
470 /*!
471  *   consult the content of the list
472  */ 
473 //=============================================================================
474
475 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
476 {
477   return _resourcesList;
478 }
479
480 string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfMachines)
481 {
482   if(_resourceManagerMap.count(policy)==0)
483     return _resourceManagerMap[""]->Find(listOfMachines,_resourcesList);
484   return _resourceManagerMap[policy]->Find(listOfMachines,_resourcesList);
485 }
486
487 //=============================================================================
488 /*!
489  *  Gives a sublist of machines with matching OS.
490  *  If parameter OS is empty, gives the complete list of machines
491  */ 
492 //=============================================================================
493
494 // Warning need an updated parsed list : _resourcesList
495 void ResourcesManager_cpp::SelectOnlyResourcesWithOS( vector<string>& hosts,  const char *OS) const
496 throw(ResourcesException)
497 {
498   string base(OS);
499
500   if(hosts.size()==0)
501     {
502       //No constraint on computer list : take all known resources with OS
503       map<string, ParserResourcesType>::const_iterator iter;
504       for (iter = _resourcesList.begin(); iter != _resourcesList.end(); iter++)
505         {
506           if ( (*iter).second.OS == base || base.size() == 0)
507             hosts.push_back((*iter).first);
508         }
509     }
510   else
511     {
512       //a computer list is given : take only resources with OS on those computers
513       vector<string> vec=hosts;
514       hosts.clear();
515       vector<string>::iterator iter;
516       for (iter = vec.begin(); iter != vec.end(); iter++)
517         {
518           MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
519           if(it != _resourcesList.end())
520             if ( (*it).second.OS == base || base.size() == 0 )
521               hosts.push_back(*iter);
522         }
523     }
524 }
525
526
527 //=============================================================================
528 /*!
529  *  Gives a sublist of machines on which the component is known.
530  */ 
531 //=============================================================================
532
533 //Warning need an updated parsed list : _resourcesList
534 void ResourcesManager_cpp::KeepOnlyResourcesWithComponent( vector<string>& hosts, const vector<string>& componentList) const
535 throw(ResourcesException)
536 {
537   for (vector<string>::iterator iter = hosts.begin(); iter != hosts.end();)
538     {
539       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
540       const vector<string>& mapOfComponentsOfCurrentHost = (((*it).second).ComponentsList);
541
542       bool erasedHost = false;
543       if( mapOfComponentsOfCurrentHost.size() > 0 ){
544         for(unsigned int i=0;i<componentList.size();i++){
545           const char* compoi = componentList[i].c_str();
546           vector<string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
547                                               mapOfComponentsOfCurrentHost.end(),
548                                               compoi);
549           if (itt == mapOfComponentsOfCurrentHost.end()){
550             erasedHost = true;
551             break;
552           }
553         }
554       }
555       if(erasedHost)
556         hosts.erase(iter);
557       else
558         iter++;
559     }
560 }
561
562
563 ParserResourcesType ResourcesManager_cpp::GetResourcesList(const std::string& machine)
564 {
565   if (_resourcesList.find(machine) != _resourcesList.end())
566     return _resourcesList[machine];
567   else
568     return _resourcesBatchList[machine];
569 }