]> SALOME platform Git repositories - modules/yacs.git/blob - src/ResourcesManager/ResourcesManager.cxx
Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/yacs.git] / src / ResourcesManager / ResourcesManager.cxx
1 // Copyright (C) 2007-2012  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
23 #include "ResourcesManager.hxx" 
24 #include <Basics_Utils.hxx>
25 #include <fstream>
26 #include <iostream>
27 #include <sstream>
28 #include <string.h>
29 #include <map>
30 #include <list>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #ifdef WNT
34 #else
35 #include <unistd.h>
36 #endif
37 #include <libxml/parser.h>
38
39 #include <algorithm>
40
41 #define MAX_SIZE_FOR_HOSTNAME 256;
42
43 static LoadRateManagerFirst first;
44 static LoadRateManagerCycl cycl;
45 static LoadRateManagerAltCycl altcycl;
46 //=============================================================================
47 /*!
48  * just for test
49  */ 
50 //=============================================================================
51
52 ResourcesManager_cpp::
53 ResourcesManager_cpp(const char *xmlFilePath)
54 {
55   _path_resources.push_back(xmlFilePath);
56 #if defined(_DEBUG_) || defined(_DEBUG)
57   std::cerr << "ResourcesManager_cpp constructor" << std::endl;
58 #endif
59   _resourceManagerMap["first"]=&first;
60   _resourceManagerMap["cycl"]=&cycl;
61   _resourceManagerMap["altcycl"]=&altcycl;
62   _resourceManagerMap["best"]=&altcycl;
63   _resourceManagerMap[""]=&altcycl;
64 }
65
66 //=============================================================================
67 /*!
68  *  Standard constructor, parse resource file.
69  *  - if ${APPLI} exists in environment,
70  *    look for ${HOME}/${APPLI}/CatalogResources.xml
71  *  - else look for default:
72  *    ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
73  *  - parse XML resource file.
74  */ 
75 //=============================================================================
76
77 ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
78 {
79   RES_MESSAGE("ResourcesManager_cpp constructor");
80
81   _resourceManagerMap["first"]=&first;
82   _resourceManagerMap["cycl"]=&cycl;
83   _resourceManagerMap["altcycl"]=&altcycl;
84   _resourceManagerMap["best"]=&altcycl;
85   _resourceManagerMap[""]=&altcycl;
86
87   bool default_catalog_resource = true;
88   if (getenv("USER_CATALOG_RESOURCES_FILE") != 0)
89   {
90     default_catalog_resource = false;
91     std::string user_file("");
92     user_file = getenv("USER_CATALOG_RESOURCES_FILE");
93     std::ifstream ifile(user_file.c_str(), std::ifstream::in );
94     if (ifile) {
95       // The file exists, and is open for input
96       _path_resources.push_back(user_file);
97     }
98     else {
99       default_catalog_resource = false;
100       RES_INFOS("Warning: USER_CATALOG_RESOURCES_FILE is set and file cannot be found.")
101       RES_INFOS("Warning: That's why we try to create a new one.")
102       std::ofstream user_catalog_file;
103       user_catalog_file.open(user_file.c_str());
104       if (user_catalog_file.fail())
105       {
106         RES_INFOS("Error: cannot write in the user catalog resouces files");
107         RES_INFOS("Error: using default CatalogResources.xml file");
108         default_catalog_resource = true;
109       }
110       else
111       {
112         user_catalog_file << "<!-- File created by SALOME -->" << std::endl;
113         user_catalog_file << "<!DOCTYPE ResourcesCatalog>" << std::endl;
114         user_catalog_file << "<resources>" << std::endl;
115         user_catalog_file << "   <machine name=\"localhost\" hostname=\"localhost\" />" << std::endl;
116         user_catalog_file << "</resources>" << std::endl;
117         user_catalog_file.close();
118       }
119     }
120   }
121   if (default_catalog_resource)
122   {
123     std::string default_file("");
124     if (getenv("APPLI") != 0)
125     {
126       default_file += getenv("HOME");
127       default_file += "/";
128       default_file += getenv("APPLI");
129       default_file += "/CatalogResources.xml";
130       _path_resources.push_back(default_file);
131     }
132     else
133     {
134       if(!getenv("KERNEL_ROOT_DIR"))
135         throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
136       default_file = getenv("KERNEL_ROOT_DIR");
137       default_file += "/share/salome/resources/kernel/CatalogResources.xml";
138       _path_resources.push_back(default_file);
139     }
140   }
141
142   _lasttime=0;
143
144   ParseXmlFiles();
145   RES_MESSAGE("ResourcesManager_cpp constructor end");
146 }
147
148 //=============================================================================
149 /*!
150  *  Standard Destructor
151  */ 
152 //=============================================================================
153
154 ResourcesManager_cpp::~ResourcesManager_cpp()
155 {
156   RES_MESSAGE("ResourcesManager_cpp destructor");
157 }
158
159 //=============================================================================
160 //! get the list of resource names fitting constraints given by params
161 /*!
162  * Steps:
163  * 1: Restrict list with resourceList if defined
164  * 2: If name is defined -> check resource list
165  * 3: If not 2:, if hostname is defined -> check resource list
166  * 4: If not 3:, sort resource with nb_proc, etc...
167  * 5: In all cases remove resource that does not correspond with OS
168  * 6: And remove resource with componentList - if list is empty ignored it...
169  */ 
170 //=============================================================================
171
172 std::vector<std::string> 
173 ResourcesManager_cpp::GetFittingResources(const resourceParams& params) throw(ResourcesException)
174 {
175   RES_MESSAGE("[GetFittingResources] on computer " << Kernel_Utils::GetHostname().c_str());
176   RES_MESSAGE("[GetFittingResources] with resource name: " << params.name);
177   RES_MESSAGE("[GetFittingResources] with hostname: "<< params.hostname);
178
179   // Result
180   std::vector<std::string> vec;
181
182   // Parse Again CalatogResource File
183   ParseXmlFiles();
184
185   // Steps:
186   // 1: If name is defined -> check resource list
187   // 2: Restrict list with resourceList if defined
188   // 3: If not 2:, if hostname is defined -> check resource list
189   // 4: If not 3:, sort resource with nb_proc, etc...
190   // 5: In all cases remove resource that does not correspond with OS
191   // 6: And remove resource with componentList - if list is empty ignored it...
192
193   // Step 1
194   if (params.name != "")
195   {
196     RES_MESSAGE("[GetFittingResources] name parameter found !");
197     if (_resourcesList.find(params.name) != _resourcesList.end())
198     {
199       vec.push_back(params.name);
200       return vec;
201     }
202     else
203       RES_MESSAGE("[GetFittingResources] resource name was not found on resource list ! name requested was " << params.name);
204       std::string error("[GetFittingResources] resource name was not found on resource list ! name requested was " + params.name);
205       throw ResourcesException(error);
206   }
207
208   MapOfParserResourcesType local_resourcesList = _resourcesList;
209   // Step 2
210   if (params.resourceList.size() > 0)
211   {
212     RES_MESSAGE("[GetFittingResources] Restricted resource list found !");
213     local_resourcesList.clear();
214     std::vector<std::string>::size_type sz = params.resourceList.size();
215
216     for (unsigned int i=0; i < sz; i++)
217     {
218       if (_resourcesList.find(params.resourceList[i]) != _resourcesList.end())
219         local_resourcesList[params.resourceList[i]] = _resourcesList[params.resourceList[i]];
220     }
221   }
222
223   // Step 3
224   if (params.hostname != "")
225   {
226     RES_MESSAGE("[GetFittingResources] Entering in hostname case !");
227
228     std::string hostname = params.hostname;
229     if (hostname ==  "localhost")
230       hostname = Kernel_Utils::GetHostname().c_str();
231
232     std::map<std::string, ParserResourcesType>::const_iterator iter = _resourcesList.begin();
233     for (; iter != _resourcesList.end(); iter++)
234     {
235       if ((*iter).second.HostName == hostname)
236         vec.push_back((*iter).first);
237     }
238   }
239   // Step 4
240   else
241   {
242     // --- Search for available resources sorted by priority
243     MapOfParserResourcesType_it i = local_resourcesList.begin();
244     for (; i != local_resourcesList.end(); ++i)
245       vec.push_back(i->first);
246
247     // --- set wanted parameters
248     ResourceDataToSort::_nbOfProcWanted = params.nb_proc;
249     ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
250     ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
251     ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
252     ResourceDataToSort::_memInMBWanted = params.mem_mb;
253     // --- end of set
254         
255     // Sort
256     std::list<ResourceDataToSort> li;
257     std::vector<std::string>::iterator iter = vec.begin();
258     for (; iter != vec.end(); iter++)
259       li.push_back(local_resourcesList[(*iter)].DataForSort);
260     li.sort();
261
262     vec.clear();
263     for (std::list<ResourceDataToSort>::iterator iter2 = li.begin(); iter2 != li.end(); iter2++)
264       vec.push_back((*iter2)._Name);
265   }
266
267   // Step 5
268   SelectOnlyResourcesWithOS(vec, params.OS.c_str());
269     
270   // Step 6
271   std::vector<std::string> vec_save(vec);
272   KeepOnlyResourcesWithComponent(vec, params.componentList);
273   if (vec.size() == 0)
274     vec = vec_save;
275
276   // End
277   // Send an exception if return list is empty...
278   if (vec.size() == 0)
279   {
280     std::string error("[GetFittingResources] ResourcesManager doesn't find any resource that fits to your parameters");
281     throw ResourcesException(error);
282   }
283
284   return vec;
285 }
286
287 //=============================================================================
288 /*!
289  *  add an entry in the ressources catalog xml file.
290  */ 
291 //=============================================================================
292
293 void
294 ResourcesManager_cpp::AddResourceInCatalog(const ParserResourcesType & new_resource) throw(ResourcesException)
295 {
296   // TODO - Add minimal check
297   _resourcesList[new_resource.Name] = new_resource;
298 }
299
300 //=============================================================================
301 /*!
302  *  Deletes a resource from the catalog
303  */ 
304 //=============================================================================
305
306 void ResourcesManager_cpp::DeleteResourceInCatalog(const char * name)
307 {
308   MapOfParserResourcesType_it it = _resourcesList.find(name);
309   if (it != _resourcesList.end())
310     _resourcesList.erase(name);
311   else
312     RES_INFOS("You try to delete a resource that does not exist... : " << name);
313 }
314
315 //=============================================================================
316 /*!
317  *  write the current data in memory in file.
318  */ 
319 //=============================================================================
320
321 void ResourcesManager_cpp::WriteInXmlFile(std::string xml_file)
322 {
323   RES_MESSAGE("WriteInXmlFile : start");
324
325   if (xml_file == "")
326   {
327     _path_resources_it = _path_resources.begin();
328     xml_file = *_path_resources_it;
329   }
330
331   const char* aFilePath = xml_file.c_str();
332   FILE* aFile = fopen(aFilePath, "w");
333
334   if (aFile == NULL)
335   {
336     std::cerr << "Error opening file in WriteInXmlFile : " << xml_file << std::endl;
337     return;
338   }
339   
340   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
341   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
342
343   SALOME_ResourcesCatalog_Handler* handler =
344     new SALOME_ResourcesCatalog_Handler(_resourcesList);
345   handler->PrepareDocToXmlFile(aDoc);
346   delete handler;
347
348   int isOk = xmlSaveFormatFile(aFilePath, aDoc, 1);
349   if (!isOk) 
350      std::cerr << "Error while XML file saving : " << xml_file << std::endl;
351   
352   // Free the document
353   xmlFreeDoc(aDoc);
354   fclose(aFile);
355   RES_MESSAGE("WriteInXmlFile : WRITING DONE!");
356 }
357
358 //=============================================================================
359 /*!
360  *  parse the data type catalog
361  */ 
362 //=============================================================================
363
364 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
365 {
366   // Parse file only if its modification time is greater than lasttime (last registered modification time)
367   bool to_parse = false;
368   for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
369   {
370     struct stat statinfo;
371     int result = stat((*_path_resources_it).c_str(), &statinfo);
372     if (result < 0)
373     {
374       std::cerr << "Error in method stat for file : " << (*_path_resources_it).c_str() << " no new xml file is parsed" << std::endl;
375       return _resourcesList;
376     }
377
378     if(statinfo.st_mtime > _lasttime)
379     {
380       to_parse = true;
381       _lasttime = statinfo.st_mtime;
382     }
383   }
384
385   if (to_parse)
386   {
387     _resourcesList.clear();
388     // On parse tous les fichiers
389     for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
390     {
391       MapOfParserResourcesType _resourcesList_tmp;
392       MapOfParserResourcesType _resourcesBatchList_tmp;
393       SALOME_ResourcesCatalog_Handler* handler =
394         new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp);
395       const char* aFilePath = (*_path_resources_it).c_str();
396       FILE* aFile = fopen(aFilePath, "r");
397
398       if (aFile != NULL)
399       {
400         xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
401         if (aDoc != NULL)
402         {
403           handler->ProcessXmlDocument(aDoc);
404
405           // adding new resources to the file
406           for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
407           {
408             MapOfParserResourcesType_it j = _resourcesList.find(i->first);
409             if (j == _resourcesList.end())
410             {
411               _resourcesList[i->first] = i->second;
412             }
413             else
414             {
415               std::cerr << "ParseXmlFiles Warning, two resources with the same name were found, taking the first declaration : " << i->first << std::endl;
416             }
417           }
418         }
419         else
420           std::cerr << "ResourcesManager_cpp: could not parse file " << aFilePath << std::endl;
421         // Free the document
422         xmlFreeDoc(aDoc);
423         fclose(aFile);
424       }
425       else
426         std::cerr << "ResourcesManager_cpp: file " << aFilePath << " is not readable." << std::endl;
427
428       delete handler;
429     }
430   }
431   return _resourcesList;
432 }
433
434 //=============================================================================
435 /*!
436  *   consult the content of the list
437  */ 
438 //=============================================================================
439
440 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
441 {
442   return _resourcesList;
443 }
444
445 std::string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources)
446 {
447   if(_resourceManagerMap.count(policy)==0)
448     return _resourceManagerMap[""]->Find(listOfResources, _resourcesList);
449   return _resourceManagerMap[policy]->Find(listOfResources, _resourcesList);
450 }
451
452 //=============================================================================
453 /*!
454  *  Gives a sublist of resources with matching OS.
455  *  If parameter OS is empty, gives the complete list of resources
456  */ 
457 //=============================================================================
458 void 
459 ResourcesManager_cpp::SelectOnlyResourcesWithOS(std::vector<std::string>& resources, std::string OS)
460 {
461   if (OS != "")
462   {
463     // a computer list is given : take only resources with OS on those computers
464     std::vector<std::string> vec_tmp = resources;
465     resources.clear();
466     std::vector<std::string>::iterator iter = vec_tmp.begin();
467     for (; iter != vec_tmp.end(); iter++)
468     {
469       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
470       if(it != _resourcesList.end())
471         if ( (*it).second.OS == OS)
472           resources.push_back(*iter);
473     }
474   }
475 }
476
477
478 //=============================================================================
479 /*!
480  *  Gives a sublist of machines on which the component is known.
481  */ 
482 //=============================================================================
483 void 
484 ResourcesManager_cpp::KeepOnlyResourcesWithComponent(std::vector<std::string>& resources, 
485                                                      const std::vector<std::string>& componentList)
486 {
487   std::vector<std::string> kept_resources;
488
489   std::vector<std::string>::iterator iter = resources.begin();
490   for (; iter != resources.end(); iter++)
491   {
492     const std::vector<std::string>& mapOfComponentsOfCurrentHost = _resourcesList[*iter].ComponentsList;
493
494     bool erasedHost = false;
495     if( mapOfComponentsOfCurrentHost.size() > 0 )
496     {
497       for(unsigned int i=0; i<componentList.size(); i++)
498       {
499         std::vector<std::string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
500                                                             mapOfComponentsOfCurrentHost.end(),
501                                                             componentList[i]);
502         if (itt == mapOfComponentsOfCurrentHost.end())
503         {
504           erasedHost = true;
505           break;
506         }
507       }
508     }
509     if(!erasedHost)
510       kept_resources.push_back(*iter);
511   }
512   resources=kept_resources;
513 }
514
515
516 ParserResourcesType 
517 ResourcesManager_cpp::GetResourcesDescr(const std::string & name)
518 {
519   if (_resourcesList.find(name) != _resourcesList.end())
520     return _resourcesList[name];
521   else
522   {
523     std::string error("[GetResourcesDescr] Resource does not exist: ");
524     error += name;
525     throw ResourcesException(error);
526   }
527 }