Salome HOME
Patch windows
[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
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 using namespace std;
44
45 static LoadRateManagerFirst first;
46 static LoadRateManagerCycl cycl;
47 static LoadRateManagerAltCycl altcycl;
48 //=============================================================================
49 /*!
50  * just for test
51  */ 
52 //=============================================================================
53
54 ResourcesManager_cpp::
55 ResourcesManager_cpp(const char *xmlFilePath) :
56     _path_resources(xmlFilePath)
57 {
58 #if defined(_DEBUG_) || defined(_DEBUG)
59   cerr << "ResourcesManager_cpp constructor" << endl;
60 #endif
61   _resourceManagerMap["first"]=&first;
62   _resourceManagerMap["cycl"]=&cycl;
63   _resourceManagerMap["altcycl"]=&altcycl;
64   _resourceManagerMap["best"]=&altcycl;
65   _resourceManagerMap[""]=&altcycl;
66 }
67
68 //=============================================================================
69 /*!
70  *  Standard constructor, parse resource file.
71  *  - if ${APPLI} exists in environment,
72  *    look for ${HOME}/${APPLI}/CatalogResources.xml
73  *  - else look for default:
74  *    ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
75  *  - parse XML resource file.
76  */ 
77 //=============================================================================
78
79 ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
80 {
81 #if defined(_DEBUG_) || defined(_DEBUG)
82   cerr << "ResourcesManager_cpp constructor" << endl;
83 #endif
84   _resourceManagerMap["first"]=&first;
85   _resourceManagerMap["cycl"]=&cycl;
86   _resourceManagerMap["altcycl"]=&altcycl;
87   _resourceManagerMap["best"]=&altcycl;
88   _resourceManagerMap[""]=&altcycl;
89
90   _isAppliSalomeDefined = (getenv("APPLI") != 0);
91   if(!getenv("KERNEL_ROOT_DIR"))
92     throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!!");
93
94   if (_isAppliSalomeDefined)
95     {
96       _path_resources = getenv("HOME");
97       _path_resources += "/";
98       _path_resources += getenv("APPLI");
99       _path_resources += "/CatalogResources.xml";
100     }
101
102   else
103     {
104       _path_resources = getenv("KERNEL_ROOT_DIR");
105       _path_resources += "/share/salome/resources/kernel/CatalogResources.xml";
106     }
107
108   ParseXmlFile();
109 #if defined(_DEBUG_) || defined(_DEBUG)
110   cerr << "ResourcesManager_cpp constructor end";
111 #endif
112 }
113
114 //=============================================================================
115 /*!
116  *  Standard Destructor
117  */ 
118 //=============================================================================
119
120 ResourcesManager_cpp::~ResourcesManager_cpp()
121 {
122 #if defined(_DEBUG_) || defined(_DEBUG)
123   cerr << "ResourcesManager_cpp destructor" << endl;
124 #endif
125 }
126
127 //=============================================================================
128 //! get the list of resource names fitting constraints given by params
129 /*!
130  *  If hostname is specified, check if it is local or known in resources catalog.
131  *
132  *  Else
133  *  - select first machines with corresponding OS (all machines if
134  *    parameter OS empty),
135  *  - then select the sublist of machines on which the component is known
136  *    (if the result is empty, that probably means that the inventory of
137  *    components is probably not done, so give complete list from previous step)
138  */ 
139 //=============================================================================
140
141 std::vector<std::string> 
142 ResourcesManager_cpp::GetFittingResources(const machineParams& params) throw(ResourcesException)
143 {
144   vector <std::string> vec;
145
146   ParseXmlFile();
147
148   const char *hostname = params.hostname.c_str();
149 #if defined(_DEBUG_) || defined(_DEBUG)
150   cerr << "GetFittingResources " << hostname << " " << Kernel_Utils::GetHostname().c_str() << endl;
151 #endif
152
153   if (hostname[0] != '\0'){
154
155     if ( strcmp(hostname, "localhost") == 0 ||
156          strcmp(hostname, Kernel_Utils::GetHostname().c_str()) == 0 )
157       {
158 //#if defined(_DEBUG_) || defined(_DEBUG)
159 //      cerr << "ResourcesManager_cpp::GetFittingResources : localhost" << endl;
160 //#endif
161         vec.push_back(Kernel_Utils::GetHostname().c_str());
162 //#if defined(_DEBUG_) || defined(_DEBUG)
163 //      cerr << "ResourcesManager_cpp::GetFittingResources : " << vec.size() << endl;
164 //#endif
165       }
166         
167     else if (_resourcesList.find(hostname) != _resourcesList.end())
168       {
169         // --- params.hostname is in the list of resources so return it.
170         vec.push_back(hostname);
171       }
172         
173     else if (_resourcesBatchList.find(hostname) != _resourcesBatchList.end())
174     {
175       // --- params.hostname is in the list of resources so return it.
176       vec.push_back(hostname);
177     }
178
179     else
180       {
181         // Cas d'un cluster: nombre de noeuds > 1
182         int cpt=0;
183         for (map<string, ParserResourcesType>::const_iterator iter = _resourcesList.begin(); iter != _resourcesList.end(); iter++){
184           if( (*iter).second.DataForSort._nbOfNodes > 1 ){
185             if( strncmp(hostname,(*iter).first.c_str(),strlen(hostname)) == 0 ){
186               vec.push_back((*iter).first.c_str());
187               cpt++;
188             }
189           }
190         }
191         if(cpt==0){
192           // --- user specified an unknown hostame so notify him.
193 #if defined(_DEBUG_) || defined(_DEBUG)
194           cerr << "ResourcesManager_cpp::GetFittingResources : SALOME_Exception" << endl;
195 #endif
196           throw ResourcesException("unknown host");
197         }
198       }
199   }
200     
201   else{
202     // --- Search for available resources sorted by priority
203     vec=params.computerList;
204
205     SelectOnlyResourcesWithOS(vec, params.OS.c_str());
206       
207     KeepOnlyResourcesWithComponent(vec, params.componentList);
208
209     //if hosts list (vec) is empty, ignore componentList constraint and use only OS constraint
210     if (vec.size() == 0)
211       SelectOnlyResourcesWithOS(vec, params.OS.c_str());
212     
213     // --- set wanted parameters
214     ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
215       
216     ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
217         
218     ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
219         
220     ResourceDataToSort::_memInMBWanted = params.mem_mb;
221         
222     // --- end of set
223         
224     list<ResourceDataToSort> li;
225         
226     for (vector<string>::iterator iter = vec.begin();
227          iter != vec.end();
228          iter++)
229       li.push_back(_resourcesList[(*iter)].DataForSort);
230         
231     li.sort();
232         
233     unsigned int i = 0;
234         
235     for (list<ResourceDataToSort>::iterator iter2 = li.begin();
236          iter2 != li.end();
237          iter2++)
238       vec[i++] = (*iter2)._hostName;
239   }
240     
241   return vec;
242
243 }
244
245 //=============================================================================
246 /*!
247  *  add an entry in the ressources catalog  xml file.
248  *  Return 0 if OK (KERNEL found in new resources components) else throw exception
249  */ 
250 //=============================================================================
251
252 int
253 ResourcesManager_cpp::
254 AddResourceInCatalog(const machineParams& paramsOfNewResources,
255                      const vector<string>& componentsOnNewResources,
256                      const char *alias,
257                      const char *userName,
258                      AccessModeType mode,
259                      AccessProtocolType prot)
260 throw(ResourcesException)
261 {
262   vector<string>::const_iterator iter = find(componentsOnNewResources.begin(),
263                                              componentsOnNewResources.end(),
264                                              "KERNEL");
265
266   if (iter != componentsOnNewResources.end())
267     {
268       ParserResourcesType newElt;
269       newElt.DataForSort._hostName = paramsOfNewResources.hostname;
270       newElt.Alias = alias;
271       newElt.Protocol = prot;
272       newElt.Mode = mode;
273       newElt.UserName = userName;
274       newElt.ComponentsList = componentsOnNewResources;
275       newElt.OS = paramsOfNewResources.OS;
276       newElt.DataForSort._memInMB = paramsOfNewResources.mem_mb;
277       newElt.DataForSort._CPUFreqMHz = paramsOfNewResources.cpu_clock;
278       newElt.DataForSort._nbOfNodes = paramsOfNewResources.nb_node;
279       newElt.DataForSort._nbOfProcPerNode =
280         paramsOfNewResources.nb_proc_per_node;
281       _resourcesList[newElt.DataForSort._hostName] = newElt;
282       return 0;
283     }
284
285   else
286     throw ResourcesException("KERNEL is not present in this resource");
287 }
288
289 //=============================================================================
290 /*!
291  *  Deletes a resource from the catalog
292  */ 
293 //=============================================================================
294
295 void ResourcesManager_cpp::DeleteResourceInCatalog(const char *hostname)
296 {
297   _resourcesList.erase(hostname);
298 }
299
300 //=============================================================================
301 /*!
302  *  write the current data in memory in file.
303  */ 
304 //=============================================================================
305
306 void ResourcesManager_cpp::WriteInXmlFile()
307 {
308   const char* aFilePath = _path_resources.c_str();
309   
310   FILE* aFile = fopen(aFilePath, "w");
311
312   if (aFile == NULL)
313     {
314 #if defined(_DEBUG_) || defined(_DEBUG)
315       cerr << "Error opening file !"  << endl;
316 #endif
317       return;
318     }
319   
320   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
321   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
322
323   SALOME_ResourcesCatalog_Handler* handler =
324     new SALOME_ResourcesCatalog_Handler(_resourcesList, _resourcesBatchList);
325   handler->PrepareDocToXmlFile(aDoc);
326   delete handler;
327
328 #if defined(_DEBUG_) || defined(_DEBUG)
329   int isOk = xmlSaveFile(aFilePath, aDoc);
330   if (!isOk) cerr << "Error while XML file saving." << endl;
331 #else
332   xmlSaveFile(aFilePath, aDoc);
333 #endif
334   
335   // Free the document
336   xmlFreeDoc(aDoc);
337
338   fclose(aFile);
339   
340 #if defined(_DEBUG_) || defined(_DEBUG)
341   cerr << "WRITING DONE!" << endl;
342 #endif
343 }
344
345 //=============================================================================
346 /*!
347  *  parse the data type catalog
348  */ 
349 //=============================================================================
350
351 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFile()
352 {
353   //Parse file only if its modification time is greater than lasttime (last registered modification time) 
354   static time_t lasttime=0;
355   struct stat statinfo;
356   int result = stat(_path_resources.c_str(), &statinfo);
357   if (result < 0) return _resourcesList;
358   if(statinfo.st_mtime <= lasttime)
359     return _resourcesList;
360   lasttime=statinfo.st_mtime;
361
362   SALOME_ResourcesCatalog_Handler* handler =
363     new SALOME_ResourcesCatalog_Handler(_resourcesList, _resourcesBatchList);
364
365   const char* aFilePath = _path_resources.c_str();
366   FILE* aFile = fopen(aFilePath, "r");
367   
368   if (aFile != NULL)
369     {
370       xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
371       
372       if (aDoc != NULL)
373         handler->ProcessXmlDocument(aDoc);
374 #if defined(_DEBUG_) || defined(_DEBUG)
375       else
376         cerr << "ResourcesManager_cpp: could not parse file "<< aFilePath << endl;
377 #endif
378       
379       // Free the document
380       xmlFreeDoc(aDoc);
381
382       fclose(aFile);
383     }
384 #if defined(_DEBUG_) || defined(_DEBUG)
385   else
386     cerr << "ResourcesManager_cpp: file "<<aFilePath<<" is not readable." << endl;
387 #endif
388   
389   delete handler;
390
391   return _resourcesList;
392 }
393
394 //=============================================================================
395 /*!
396  *   consult the content of the list
397  */ 
398 //=============================================================================
399
400 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
401 {
402   return _resourcesList;
403 }
404
405 string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfMachines)
406 {
407   if(_resourceManagerMap.count(policy)==0)
408     return _resourceManagerMap[""]->Find(listOfMachines,_resourcesList);
409   return _resourceManagerMap[policy]->Find(listOfMachines,_resourcesList);
410 }
411
412 //=============================================================================
413 /*!
414  *  Gives a sublist of machines with matching OS.
415  *  If parameter OS is empty, gives the complete list of machines
416  */ 
417 //=============================================================================
418
419 // Warning need an updated parsed list : _resourcesList
420 void ResourcesManager_cpp::SelectOnlyResourcesWithOS( vector<string>& hosts,  const char *OS) const
421 throw(ResourcesException)
422 {
423   string base(OS);
424
425   if(hosts.size()==0)
426     {
427       //No constraint on computer list : take all known resources with OS
428       map<string, ParserResourcesType>::const_iterator iter;
429       for (iter = _resourcesList.begin(); iter != _resourcesList.end(); iter++)
430         {
431           if ( (*iter).second.OS == base || base.size() == 0)
432             hosts.push_back((*iter).first);
433         }
434     }
435   else
436     {
437       //a computer list is given : take only resources with OS on those computers
438       vector<string> vec=hosts;
439       hosts.clear();
440       vector<string>::iterator iter;
441       for (iter = vec.begin(); iter != vec.end(); iter++)
442         {
443           MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
444           if(it != _resourcesList.end())
445             if ( (*it).second.OS == base || base.size() == 0 )
446               hosts.push_back(*iter);
447         }
448     }
449 }
450
451
452 //=============================================================================
453 /*!
454  *  Gives a sublist of machines on which the component is known.
455  */ 
456 //=============================================================================
457
458 //Warning need an updated parsed list : _resourcesList
459 void ResourcesManager_cpp::KeepOnlyResourcesWithComponent( vector<string>& hosts, const vector<string>& componentList) const
460 throw(ResourcesException)
461 {
462   for (vector<string>::iterator iter = hosts.begin(); iter != hosts.end();)
463     {
464       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
465       const vector<string>& mapOfComponentsOfCurrentHost = (((*it).second).ComponentsList);
466
467       bool erasedHost = false;
468       if( mapOfComponentsOfCurrentHost.size() > 0 ){
469         for(unsigned int i=0;i<componentList.size();i++){
470           const char* compoi = componentList[i].c_str();
471           vector<string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
472                                               mapOfComponentsOfCurrentHost.end(),
473                                               compoi);
474           if (itt == mapOfComponentsOfCurrentHost.end()){
475             erasedHost = true;
476             break;
477           }
478         }
479       }
480       if(erasedHost)
481         hosts.erase(iter);
482       else
483         iter++;
484     }
485 }
486
487
488 ParserResourcesType ResourcesManager_cpp::GetResourcesList(const std::string& machine)
489 {
490   if (_resourcesList.find(machine) != _resourcesList.end())
491     return _resourcesList[machine];
492   else
493     return _resourcesBatchList[machine];
494 }