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