Salome HOME
merge from branch BR_V511_PR 15 12 2009
[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   RES_MESSAGE("ResourcesManager_cpp constructor");
81
82   _resourceManagerMap["first"]=&first;
83   _resourceManagerMap["cycl"]=&cycl;
84   _resourceManagerMap["altcycl"]=&altcycl;
85   _resourceManagerMap["best"]=&altcycl;
86   _resourceManagerMap[""]=&altcycl;
87
88   if (getenv("USER_CATALOG_RESOURCES_FILE") != 0)
89   {
90     std::string user_file("");
91     user_file = getenv("USER_CATALOG_RESOURCES_FILE");
92     _path_resources.push_back(user_file);
93   }
94   else
95   {
96     std::string default_file("");
97     if (getenv("APPLI") != 0)
98     {
99       default_file += getenv("HOME");
100       default_file += "/";
101       default_file += getenv("APPLI");
102       default_file += "/CatalogResources.xml";
103       _path_resources.push_back(default_file);
104     }
105     else
106     {
107       if(!getenv("KERNEL_ROOT_DIR"))
108         throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
109       default_file = getenv("KERNEL_ROOT_DIR");
110       default_file += "/share/salome/resources/kernel/CatalogResources.xml";
111       _path_resources.push_back(default_file);
112     }
113   }
114
115   _lasttime=0;
116
117   ParseXmlFiles();
118   RES_MESSAGE("ResourcesManager_cpp constructor end");
119 }
120
121 //=============================================================================
122 /*!
123  *  Standard Destructor
124  */ 
125 //=============================================================================
126
127 ResourcesManager_cpp::~ResourcesManager_cpp()
128 {
129   RES_MESSAGE("ResourcesManager_cpp destructor");
130 }
131
132 //=============================================================================
133 //! get the list of resource names fitting constraints given by params
134 /*!
135  * Steps:
136  * 1: Restrict list with resourceList if defined
137  * 2: If name is defined -> check resource list
138  * 3: If not 2:, if hostname is defined -> check resource list
139  * 4: If not 3:, sort resource with nb_proc, etc...
140  * 5: In all cases remove resource that does not correspond with OS
141  * 6: And remove resource with componentList - if list is empty ignored it...
142  */ 
143 //=============================================================================
144
145 std::vector<std::string> 
146 ResourcesManager_cpp::GetFittingResources(const resourceParams& params) throw(ResourcesException)
147 {
148   RES_MESSAGE("[GetFittingResources] on computer " << Kernel_Utils::GetHostname().c_str());
149   RES_MESSAGE("[GetFittingResources] with resource name: " << params.name);
150   RES_MESSAGE("[GetFittingResources] with hostname: "<< params.hostname);
151
152   // Result
153   std::vector<std::string> vec;
154
155   // Parse Again CalatogResource File
156   ParseXmlFiles();
157
158   // Steps:
159   // 1: Restrict list with resourceList if defined
160   // 2: If name is defined -> check resource list
161   // 3: If not 2:, if hostname is defined -> check resource list
162   // 4: If not 3:, sort resource with nb_proc, etc...
163   // 5: In all cases remove resource that does not correspond with OS
164   // 6: And remove resource with componentList - if list is empty ignored it...
165   
166  
167   MapOfParserResourcesType local_resourcesList = _resourcesList;
168   // Step 1
169   if (params.resourceList.size() > 0)
170   {
171     RES_MESSAGE("[GetFittingResources] Restricted resource list found !");
172     local_resourcesList.clear();
173     std::vector<std::string>::size_type sz = params.resourceList.size();
174
175     for (unsigned int i=0; i < sz; i++)
176     {
177       if (_resourcesList.find(params.resourceList[i]) != _resourcesList.end())
178         local_resourcesList[params.resourceList[i]] = _resourcesList[params.resourceList[i]];
179     }
180   }
181
182   // Step 2
183   if (params.name != "")
184   {
185     RES_MESSAGE("[GetFittingResources] name parameter found !");
186     if (_resourcesList.find(params.name) != _resourcesList.end())
187     {
188       vec.push_back(params.name);
189     }
190     else
191       RES_MESSAGE("[GetFittingResources] name was not found on resource list ! name was " << params.name);
192   }
193
194   // Step 3
195   else if (params.hostname != "")
196   {
197     RES_MESSAGE("[GetFittingResources] Entering in hostname case !");
198
199     std::string hostname = params.hostname;
200     if (hostname ==  "localhost")
201       hostname = Kernel_Utils::GetHostname().c_str();
202
203     std::map<std::string, ParserResourcesType>::const_iterator iter = _resourcesList.begin();
204     for (; iter != _resourcesList.end(); iter++)
205     {
206       if ((*iter).second.HostName == hostname)
207         vec.push_back((*iter).first);
208     }
209   }
210
211   // Step 4
212   else
213   {
214     // --- Search for available resources sorted by priority
215     MapOfParserResourcesType_it i = local_resourcesList.begin();
216     for (; i != local_resourcesList.end(); ++i)
217       vec.push_back(i->first);
218
219     // --- set wanted parameters
220     ResourceDataToSort::_nbOfProcWanted = params.nb_proc;
221     ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
222     ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
223     ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
224     ResourceDataToSort::_memInMBWanted = params.mem_mb;
225     // --- end of set
226         
227     // Sort
228     std::list<ResourceDataToSort> li;
229     std::vector<std::string>::iterator iter = vec.begin();
230     for (; iter != vec.end(); iter++)
231       li.push_back(local_resourcesList[(*iter)].DataForSort);
232     li.sort();
233
234     vec.clear();
235     for (list<ResourceDataToSort>::iterator iter2 = li.begin(); iter2 != li.end(); iter2++)
236       vec.push_back((*iter2)._Name);
237   }
238
239   // Step 5
240   SelectOnlyResourcesWithOS(vec, params.OS.c_str());
241     
242   // Step 6
243   std::vector<std::string> vec_save(vec);
244   KeepOnlyResourcesWithComponent(vec, params.componentList);
245   if (vec.size() == 0)
246     vec = vec_save;
247
248   // End
249   // Send an exception if return list is empty...
250   if (vec.size() == 0)
251   {
252     std::string error("[GetFittingResources] ResourcesManager doesn't find any resource that feets to your parameters");
253     throw ResourcesException(error);
254   }
255
256   return vec;
257 }
258
259 //=============================================================================
260 /*!
261  *  add an entry in the ressources catalog  xml file.
262  *  Return 0 if OK (KERNEL found in new resources components) else throw exception
263  */ 
264 //=============================================================================
265
266 int
267 ResourcesManager_cpp::AddResourceInCatalog(const resourceParams& paramsOfNewResources,
268                                            const vector<string>& componentsOnNewResources,
269                                            const char *userName,
270                                            AccessModeType mode,
271                                            AccessProtocolType prot,
272                                            AccessProtocolType iprot) throw(ResourcesException)
273 {
274   vector<string>::const_iterator iter = find(componentsOnNewResources.begin(),
275                                              componentsOnNewResources.end(),
276                                              "KERNEL");
277
278   if (iter != componentsOnNewResources.end())
279     {
280       ParserResourcesType newElt;
281       newElt.DataForSort._Name = paramsOfNewResources.name;
282       newElt.HostName = paramsOfNewResources.hostname;
283       newElt.Protocol = prot;
284       newElt.ClusterInternalProtocol = iprot;
285       newElt.Mode = mode;
286       newElt.UserName = userName;
287       newElt.ComponentsList = componentsOnNewResources;
288       newElt.OS = paramsOfNewResources.OS;
289       newElt.DataForSort._memInMB = paramsOfNewResources.mem_mb;
290       newElt.DataForSort._CPUFreqMHz = paramsOfNewResources.cpu_clock;
291       newElt.DataForSort._nbOfNodes = paramsOfNewResources.nb_node;
292       newElt.DataForSort._nbOfProcPerNode =
293         paramsOfNewResources.nb_proc_per_node;
294       _resourcesList[newElt.DataForSort._Name] = newElt;
295       return 0;
296     }
297   else
298     throw ResourcesException("KERNEL is not present in this resource");
299 }
300
301 //=============================================================================
302 /*!
303  *  Deletes a resource from the catalog
304  */ 
305 //=============================================================================
306
307 void ResourcesManager_cpp::DeleteResourceInCatalog(const char * name)
308 {
309   _resourcesList.erase(name);
310 }
311
312 //=============================================================================
313 /*!
314  *  write the current data in memory in file.
315  */ 
316 //=============================================================================
317
318 void ResourcesManager_cpp::WriteInXmlFile(std::string & xml_file)
319 {
320   RES_MESSAGE("WriteInXmlFile : start");
321
322   const char* aFilePath = xml_file.c_str();
323   FILE* aFile = fopen(aFilePath, "w");
324
325   if (aFile == NULL)
326   {
327     std::cerr << "Error opening file in WriteInXmlFile : " << xml_file << std::endl;
328     return;
329   }
330   
331   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
332   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
333
334   SALOME_ResourcesCatalog_Handler* handler =
335     new SALOME_ResourcesCatalog_Handler(_resourcesList);
336   handler->PrepareDocToXmlFile(aDoc);
337   delete handler;
338
339   int isOk = xmlSaveFile(aFilePath, aDoc);
340   if (!isOk) 
341      std::cerr << "Error while XML file saving : " << xml_file << std::endl;
342   
343   // Free the document
344   xmlFreeDoc(aDoc);
345   fclose(aFile);
346   RES_MESSAGE("WriteInXmlFile : WRITING DONE!");
347 }
348
349 //=============================================================================
350 /*!
351  *  parse the data type catalog
352  */ 
353 //=============================================================================
354
355 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
356 {
357   // Parse file only if its modification time is greater than lasttime (last registered modification time)
358   bool to_parse = false;
359   for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
360   {
361     struct stat statinfo;
362     int result = stat((*_path_resources_it).c_str(), &statinfo);
363     if (result < 0)
364     {
365       std::cerr << "Error in method stat for file : " << (*_path_resources_it).c_str() << " no new xml file is parsed" << std::endl;
366       return _resourcesList;
367     }
368
369     if(statinfo.st_mtime > _lasttime)
370     {
371       to_parse = true;
372       _lasttime = statinfo.st_mtime;
373     }
374   }
375
376   if (to_parse)
377   {
378     _resourcesList.clear();
379     // On parse tous les fichiers
380     for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
381     {
382       MapOfParserResourcesType _resourcesList_tmp;
383       MapOfParserResourcesType _resourcesBatchList_tmp;
384       SALOME_ResourcesCatalog_Handler* handler =
385         new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp);
386       const char* aFilePath = (*_path_resources_it).c_str();
387       FILE* aFile = fopen(aFilePath, "r");
388
389       if (aFile != NULL)
390       {
391         xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
392         if (aDoc != NULL)
393         {
394           handler->ProcessXmlDocument(aDoc);
395
396           // adding new resources to the file
397           for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
398           {
399             MapOfParserResourcesType_it j = _resourcesList.find(i->first);
400             if (j == _resourcesList.end())
401             {
402               _resourcesList[i->first] = i->second;
403             }
404             else
405             {
406               std::cerr << "ParseXmlFiles Warning, to resource with the same name was found, taking the first declaration : " << i->first << std::endl;
407             }
408           }
409         }
410         else
411           std::cerr << "ResourcesManager_cpp: could not parse file " << aFilePath << std::endl;
412         // Free the document
413         xmlFreeDoc(aDoc);
414         fclose(aFile);
415       }
416       else
417         std::cerr << "ResourcesManager_cpp: file " << aFilePath << " is not readable." << std::endl;
418
419       delete handler;
420     }
421   }
422   return _resourcesList;
423 }
424
425 //=============================================================================
426 /*!
427  *   consult the content of the list
428  */ 
429 //=============================================================================
430
431 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
432 {
433   return _resourcesList;
434 }
435
436 string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources)
437 {
438   if(_resourceManagerMap.count(policy)==0)
439     return _resourceManagerMap[""]->Find(listOfResources, _resourcesList);
440   return _resourceManagerMap[policy]->Find(listOfResources, _resourcesList);
441 }
442
443 //=============================================================================
444 /*!
445  *  Gives a sublist of resources with matching OS.
446  *  If parameter OS is empty, gives the complete list of resources
447  */ 
448 //=============================================================================
449 void 
450 ResourcesManager_cpp::SelectOnlyResourcesWithOS(std::vector<std::string>& resources, std::string OS)
451 {
452   if (OS != "")
453   {
454     // a computer list is given : take only resources with OS on those computers
455     std::vector<std::string> vec_tmp = resources;
456     resources.clear();
457     vector<string>::iterator iter = vec_tmp.begin();
458     for (; iter != vec_tmp.end(); iter++)
459     {
460       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
461       if(it != _resourcesList.end())
462         if ( (*it).second.OS == OS)
463           resources.push_back(*iter);
464     }
465   }
466 }
467
468
469 //=============================================================================
470 /*!
471  *  Gives a sublist of machines on which the component is known.
472  */ 
473 //=============================================================================
474 void 
475 ResourcesManager_cpp::KeepOnlyResourcesWithComponent(std::vector<std::string>& resources, 
476                                                      const vector<string>& componentList)
477 {
478   std::vector<std::string>::iterator iter = resources.begin();
479   for (; iter != resources.end(); iter++)
480   {
481     MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
482     const vector<string>& mapOfComponentsOfCurrentHost = (*it).second.ComponentsList;
483
484     bool erasedHost = false;
485     if( mapOfComponentsOfCurrentHost.size() > 0 )
486     {
487       for(unsigned int i=0; i<componentList.size(); i++)
488       {
489         const char* compoi = componentList[i].c_str();
490         vector<string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
491                                                   mapOfComponentsOfCurrentHost.end(),
492                                                   compoi);
493         if (itt == mapOfComponentsOfCurrentHost.end())
494         {
495           erasedHost = true;
496           break;
497         }
498       }
499     }
500     if(erasedHost)
501       resources.erase(iter);
502   }
503 }
504
505
506 ParserResourcesType 
507 ResourcesManager_cpp::GetResourcesDescr(const std::string & name)
508 {
509   if (_resourcesList.find(name) != _resourcesList.end())
510     return _resourcesList[name];
511   else
512   {
513     std::string error("[GetResourcesDescr] Resource does not exist: ");
514     error += name;
515     throw ResourcesException(error);
516   }
517 }