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