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