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