]> SALOME platform Git repositories - modules/kernel.git/blob - src/ResourcesManager/ResourcesManager.cxx
Salome HOME
Copyright update 2020
[modules/kernel.git] / src / ResourcesManager / ResourcesManager.cxx
1 // Copyright (C) 2007-2020  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, or (at your option) any later version.
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 "SALOME_ResourcesCatalog_Handler.hxx"
25 #include <Basics_Utils.hxx>
26 #include <fstream>
27 #include <iostream>
28 #include <sstream>
29 #include <string.h>
30 #include <map>
31 #include <list>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #ifdef WIN32
35 #else
36 #include <unistd.h>
37 #endif
38 #include <libxml/parser.h>
39
40 #include <algorithm>
41
42 #define MAX_SIZE_FOR_HOSTNAME 256;
43
44 using namespace std;
45
46 const string ResourcesManager_cpp::DEFAULT_RESOURCE_NAME = "localhost";
47
48 static LoadRateManagerFirst first;
49 static LoadRateManagerCycl cycl;
50 static LoadRateManagerAltCycl altcycl;
51
52 resourceParams::resourceParams()
53 : can_launch_batch_jobs(false),
54   can_run_containers(false),
55   nb_proc(-1),
56   nb_node(0),
57   nb_proc_per_node(-1),
58   cpu_clock(-1),
59   mem_mb(-1)
60 {
61 }
62
63 //=============================================================================
64 /*!
65  * just for test
66  */ 
67 //=============================================================================
68
69 ResourcesManager_cpp::
70 ResourcesManager_cpp(const char *xmlFilePath)
71 {
72   _path_resources.push_back(xmlFilePath);
73 #if defined(_DEBUG_) || defined(_DEBUG)
74   std::cerr << "ResourcesManager_cpp constructor" << std::endl;
75 #endif
76   _resourceManagerMap["first"]=&first;
77   _resourceManagerMap["cycl"]=&cycl;
78   _resourceManagerMap["altcycl"]=&altcycl;
79   _resourceManagerMap["best"]=&altcycl;
80   _resourceManagerMap[""]=&altcycl;
81
82   AddDefaultResourceInCatalog();
83   ParseXmlFiles();
84 }
85
86 //=============================================================================
87 /*!
88  *  Standard constructor, parse resource file.
89  *  - if ${APPLI} exists in environment,
90  *    look for ${HOME}/${APPLI}/CatalogResources.xml
91  *  - else look for default:
92  *    ${KERNEL_ROOT_DIR}/share/salome/resources/kernel/CatalogResources.xml
93  *  - parse XML resource file.
94  */ 
95 //=============================================================================
96
97 ResourcesManager_cpp::ResourcesManager_cpp() throw(ResourcesException)
98 {
99   RES_MESSAGE("ResourcesManager_cpp constructor");
100
101   _resourceManagerMap["first"]=&first;
102   _resourceManagerMap["cycl"]=&cycl;
103   _resourceManagerMap["altcycl"]=&altcycl;
104   _resourceManagerMap["best"]=&altcycl;
105   _resourceManagerMap[""]=&altcycl;
106
107   AddDefaultResourceInCatalog();
108
109   bool default_catalog_resource = true;
110   if (getenv("USER_CATALOG_RESOURCES_FILE") != 0)
111   {
112     default_catalog_resource = false;
113     std::string user_file("");
114     user_file = getenv("USER_CATALOG_RESOURCES_FILE");
115     std::ifstream ifile(user_file.c_str(), std::ifstream::in );
116     if (ifile) {
117       // The file exists, and is open for input
118       _path_resources.push_back(user_file);
119     }
120     else {
121       default_catalog_resource = false;
122       RES_INFOS("Warning: USER_CATALOG_RESOURCES_FILE is set and file cannot be found.")
123       RES_INFOS("Warning: That's why we try to create a new one.")
124       std::ofstream user_catalog_file;
125       user_catalog_file.open(user_file.c_str());
126       if (user_catalog_file.fail())
127       {
128         RES_INFOS("Error: cannot write in the user catalog resources files");
129         RES_INFOS("Error: using default CatalogResources.xml file");
130         default_catalog_resource = true;
131       }
132       else
133       {
134         user_catalog_file << "<!-- File created by SALOME -->" << std::endl;
135         user_catalog_file << "<!DOCTYPE ResourcesCatalog>" << std::endl;
136         user_catalog_file << "<resources>" << std::endl;
137         user_catalog_file << "   <machine name=\"localhost\" hostname=\"localhost\" />" << std::endl;
138         user_catalog_file << "</resources>" << std::endl;
139         user_catalog_file.close();
140       }
141     }
142   }
143   if (default_catalog_resource)
144   {
145     std::string default_file("");
146     if (getenv("APPLI") != 0)
147     {
148       default_file += getenv("HOME");
149       default_file += "/";
150       default_file += getenv("APPLI");
151       default_file += "/CatalogResources.xml";
152       std::ifstream ifile(default_file.c_str(), std::ifstream::in );
153       if (ifile) {
154         // The file exists, and is open for input
155         _path_resources.push_back(default_file);
156         default_catalog_resource=false;
157       }
158     }
159   }
160   if (default_catalog_resource)
161   {
162     std::string default_file("");
163     if(!getenv("KERNEL_ROOT_DIR"))
164       throw ResourcesException("you must define KERNEL_ROOT_DIR environment variable!! -> cannot load a CatalogResources.xml");
165     default_file = getenv("KERNEL_ROOT_DIR");
166     default_file += "/share/salome/resources/kernel/CatalogResources.xml";
167     _path_resources.push_back(default_file);
168   }
169
170   ParseXmlFiles();
171   RES_MESSAGE("ResourcesManager_cpp constructor end");
172 }
173
174 //=============================================================================
175 /*!
176  *  Standard Destructor
177  */ 
178 //=============================================================================
179
180 ResourcesManager_cpp::~ResourcesManager_cpp()
181 {
182   RES_MESSAGE("ResourcesManager_cpp destructor");
183 }
184
185 //=============================================================================
186 //! get the list of resource names fitting constraints given by params
187 /*!
188  * Steps:
189  * 1: Restrict list with resourceList if defined
190  * 2: If name is defined -> check resource list
191  * 3: If not 2:, if hostname is defined -> check resource list
192  * 4: If not 3:, sort resource with nb_proc, etc...
193  * 5: In all cases remove resource that does not correspond with OS
194  * 6: And remove resource with componentList - if list is empty ignored it...
195  */ 
196 //=============================================================================
197
198 std::vector<std::string> 
199 ResourcesManager_cpp::GetFittingResources(const resourceParams& params) throw(ResourcesException)
200 {
201   RES_MESSAGE("[GetFittingResources] on computer " << Kernel_Utils::GetHostname().c_str());
202   RES_MESSAGE("[GetFittingResources] with resource name: " << params.name);
203   RES_MESSAGE("[GetFittingResources] with hostname: "<< params.hostname);
204
205   // Result
206   std::vector<std::string> vec;
207
208   // Parse Again CalatogResource File
209   ParseXmlFiles();
210
211   // Steps:
212   // 1: If name is defined -> check resource list
213   // 2: Restrict list with resourceList if defined
214   // 3: If not 2:, if hostname is defined -> check resource list
215   // 4: If not 3:, sort resource with nb_proc, etc...
216   // 5: In all cases remove resource that does not correspond with OS
217   // 6: And remove resource with componentList - if list is empty ignored it...
218
219   // Step 1
220   if (params.name != "")
221   {
222     RES_MESSAGE("[GetFittingResources] name parameter found !");
223     if (_resourcesList.find(params.name) != _resourcesList.end())
224     {
225       vec.push_back(params.name);
226       return vec;
227     }
228     else
229       RES_MESSAGE("[GetFittingResources] resource name was not found on resource list ! name requested was " << params.name);
230       std::string error("[GetFittingResources] resource name was not found on resource list ! name requested was " + params.name);
231       throw ResourcesException(error);
232   }
233
234   MapOfParserResourcesType local_resourcesList = _resourcesList;
235   // Step 2
236   if (params.resourceList.size() > 0)
237   {
238     RES_MESSAGE("[GetFittingResources] Restricted resource list found !");
239     local_resourcesList.clear();
240     std::vector<std::string>::size_type sz = params.resourceList.size();
241
242     for (unsigned int i=0; i < sz; i++)
243     {
244       if (_resourcesList.find(params.resourceList[i]) != _resourcesList.end())
245         local_resourcesList[params.resourceList[i]] = _resourcesList[params.resourceList[i]];
246     }
247   }
248
249   // Step 3
250   if (params.hostname != "")
251   {
252     RES_MESSAGE("[GetFittingResources] Entering in hostname case !");
253
254     std::string hostname = params.hostname;
255     if (hostname ==  "localhost")
256       hostname = Kernel_Utils::GetHostname().c_str();
257
258     std::map<std::string, ParserResourcesType>::const_iterator iter = _resourcesList.begin();
259     for (; iter != _resourcesList.end(); iter++)
260     {
261       if ((*iter).second.HostName == hostname)
262         vec.push_back((*iter).first);
263     }
264   }
265   // Step 4
266   else
267   {
268     // --- Search for available resources sorted by priority
269     MapOfParserResourcesType_it i = local_resourcesList.begin();
270     for (; i != local_resourcesList.end(); ++i)
271       vec.push_back(i->first);
272
273     // --- set wanted parameters
274     ResourceDataToSort::_nbOfProcWanted = params.nb_proc;
275     ResourceDataToSort::_nbOfNodesWanted = params.nb_node;
276     ResourceDataToSort::_nbOfProcPerNodeWanted = params.nb_proc_per_node;
277     ResourceDataToSort::_CPUFreqMHzWanted = params.cpu_clock;
278     ResourceDataToSort::_memInMBWanted = params.mem_mb;
279     // --- end of set
280         
281     // Sort
282     std::list<ResourceDataToSort> li;
283     std::vector<std::string>::iterator iter = vec.begin();
284     for (; iter != vec.end(); iter++)
285       li.push_back(local_resourcesList[(*iter)].DataForSort);
286     li.sort();
287
288     vec.clear();
289     for (std::list<ResourceDataToSort>::iterator iter2 = li.begin(); iter2 != li.end(); iter2++)
290       vec.push_back((*iter2)._Name);
291   }
292
293   // Step 5
294   SelectOnlyResourcesWithOS(vec, params.OS.c_str());
295
296   // Step 6
297   std::vector<std::string> vec_save(vec);
298   KeepOnlyResourcesWithComponent(vec, params.componentList);
299   if (vec.size() == 0)
300     vec = vec_save;
301
302   // Step 7 : Filter on possible usage
303   vector<string> prev_list(vec);
304   vec.clear();
305   for (vector<string>::iterator iter = prev_list.begin() ; iter != prev_list.end() ; iter++)
306   {
307     MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
308     if (it != _resourcesList.end() &&
309         (!params.can_launch_batch_jobs || it->second.can_launch_batch_jobs) &&
310         (!params.can_run_containers || it->second.can_run_containers))
311       vec.push_back(*iter);
312   }
313
314   // End
315   // Send an exception if return list is empty...
316   if (vec.size() == 0)
317   {
318     std::string error("[GetFittingResources] ResourcesManager doesn't find any resource that fits to your parameters");
319     throw ResourcesException(error);
320   }
321
322   return vec;
323 }
324
325 //=============================================================================
326 /*!
327  *  add an entry in the resources catalog xml file.
328  */ 
329 //=============================================================================
330
331 void
332 ResourcesManager_cpp::AddResourceInCatalog(const ParserResourcesType & new_resource)
333 {
334   if (new_resource.Name == DEFAULT_RESOURCE_NAME){
335     ParserResourcesType default_resource = _resourcesList[DEFAULT_RESOURCE_NAME];
336     // some of the properties of the default resource shouldn't be modified
337     std::string check;
338     if( default_resource.HostName != new_resource.HostName)
339       check += "The Hostname property of the default resource can not be modified.\n";
340     if( default_resource.AppliPath != new_resource.AppliPath)
341       check += "The Applipath property of the default resource can not be modified.\n";
342     if( !new_resource.can_run_containers)
343       check += "The default resource should be able to run containers.\n";
344     if( !new_resource.can_launch_batch_jobs)
345       check += "The default resource should be able to launch batch jobs.\n";
346     if( default_resource.Protocol != new_resource.Protocol)
347       check += "The Protocol property of the default resource can not be modified.\n";
348     if(!check.empty())
349       throw ResourcesException(check);
350   }
351   // TODO - Add minimal check
352   _resourcesList[new_resource.Name] = new_resource;
353 }
354
355 //=============================================================================
356 /*!
357  *  Deletes a resource from the catalog
358  */ 
359 //=============================================================================
360
361 void ResourcesManager_cpp::DeleteResourceInCatalog(const char * name)
362 {
363   if (DEFAULT_RESOURCE_NAME == name){
364     std::string error("Cannot delete default local resource \"" + DEFAULT_RESOURCE_NAME + "\"");
365     throw ResourcesException(error);
366   }
367   MapOfParserResourcesType_it it = _resourcesList.find(name);
368   if (it != _resourcesList.end())
369     _resourcesList.erase(name);
370   else
371     RES_INFOS("You try to delete a resource that does not exist... : " << name);
372 }
373
374 //=============================================================================
375 /*!
376  *  write the current data in memory in file.
377  */ 
378 //=============================================================================
379
380 void ResourcesManager_cpp::WriteInXmlFile(std::string xml_file)
381 {
382   RES_MESSAGE("WriteInXmlFile : start");
383
384   MapOfParserResourcesType resourceListToSave(_resourcesList);
385   if (resourceListToSave.empty())
386   {
387     RES_MESSAGE("WriteInXmlFile: nothing to do, no resource to save!");
388     return;
389   }
390
391   if (xml_file == "")
392   {
393     _path_resources_it = _path_resources.begin();
394     xml_file = *_path_resources_it;
395   }
396
397   const char* aFilePath = xml_file.c_str();
398   FILE* aFile = fopen(aFilePath, "w");
399
400   if (aFile == NULL)
401   {
402     std::cerr << "Error opening file in WriteInXmlFile : " << xml_file << std::endl;
403     return;
404   }
405   
406   xmlDocPtr aDoc = xmlNewDoc(BAD_CAST "1.0");
407   xmlNewDocComment(aDoc, BAD_CAST "ResourcesCatalog");
408
409   SALOME_ResourcesCatalog_Handler* handler =
410     new SALOME_ResourcesCatalog_Handler(resourceListToSave);
411   handler->PrepareDocToXmlFile(aDoc);
412   delete handler;
413
414   int isOk = xmlSaveFormatFile(aFilePath, aDoc, 1);
415   if (!isOk) 
416      std::cerr << "Error while XML file saving : " << xml_file << std::endl;
417   
418   // Free the document
419   xmlFreeDoc(aDoc);
420   fclose(aFile);
421   RES_MESSAGE("WriteInXmlFile : WRITING DONE!");
422 }
423
424 //=============================================================================
425 /*!
426  *  parse the data type catalog
427  */ 
428 //=============================================================================
429
430 const MapOfParserResourcesType& ResourcesManager_cpp::ParseXmlFiles()
431 {
432   // Parse file only if its modification time is greater than lasttime (last registered modification time)
433   bool to_parse = false;
434   for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
435   {
436     struct stat statinfo;
437     int result = stat((*_path_resources_it).c_str(), &statinfo);
438     if (result < 0)
439     {
440       RES_MESSAGE("Resource file " << *_path_resources_it << " does not exist");
441       return _resourcesList;
442     }
443
444     if(_lasttime == 0 || statinfo.st_mtime > _lasttime)
445     {
446       to_parse = true;
447       _lasttime = statinfo.st_mtime;
448     }
449   }
450
451   if (to_parse)
452   {
453     _resourcesList.clear();
454     AddDefaultResourceInCatalog();
455     // On parse tous les fichiers
456     for(_path_resources_it = _path_resources.begin(); _path_resources_it != _path_resources.end(); ++_path_resources_it)
457     {
458       MapOfParserResourcesType _resourcesList_tmp;
459       MapOfParserResourcesType _resourcesBatchList_tmp;
460       SALOME_ResourcesCatalog_Handler *handler( new SALOME_ResourcesCatalog_Handler(_resourcesList_tmp) );
461       const char *aFilePath( (*_path_resources_it).c_str() );
462       FILE* aFile = fopen(aFilePath, "r");
463
464       if (aFile != NULL)
465       {
466         xmlDocPtr aDoc = xmlReadFile(aFilePath, NULL, 0);
467         if (aDoc != NULL)
468         {
469           handler->ProcessXmlDocument(aDoc);
470
471           // adding new resources to the file
472           for (MapOfParserResourcesType_it i = _resourcesList_tmp.begin(); i != _resourcesList_tmp.end(); ++i)
473           {
474             MapOfParserResourcesType_it j = _resourcesList.find(i->first);
475             if (i->second.HostName == DEFAULT_RESOURCE_NAME || i->second.HostName == Kernel_Utils::GetHostname())
476             {
477               MapOfParserResourcesType_it it0(_resourcesList.find(DEFAULT_RESOURCE_NAME));
478               if(it0!=_resourcesList.end())
479                 {
480                   ParserResourcesType& localhostElt((*it0).second);
481                   localhostElt.DataForSort._nbOfNodes=(*i).second.DataForSort._nbOfNodes;
482                   localhostElt.DataForSort._nbOfProcPerNode=(*i).second.DataForSort._nbOfProcPerNode;
483                   localhostElt.DataForSort._CPUFreqMHz=(*i).second.DataForSort._CPUFreqMHz;
484                   localhostElt.DataForSort._memInMB=(*i).second.DataForSort._memInMB;
485                 }
486               RES_MESSAGE("Resource " << i->first << " is not added because it is the same "
487                           "machine as default local resource \"" << DEFAULT_RESOURCE_NAME << "\"");
488             }
489             else if (j != _resourcesList.end())
490             {
491               cerr << "ParseXmlFiles Warning, two resources with the same name were found, "
492                       "taking the first declaration : " << i->first << endl;
493             }
494             else
495             {
496               _resourcesList[i->first] = i->second;
497             }
498           }
499         }
500         else
501           std::cerr << "ResourcesManager_cpp: could not parse file " << aFilePath << std::endl;
502         // Free the document
503         xmlFreeDoc(aDoc);
504         fclose(aFile);
505       }
506       else
507         std::cerr << "ResourcesManager_cpp: file " << aFilePath << " is not readable." << std::endl;
508
509       delete handler;
510     }
511   }
512   return _resourcesList;
513 }
514
515 //=============================================================================
516 /*!
517  *   consult the content of the list
518  */ 
519 //=============================================================================
520
521 const MapOfParserResourcesType& ResourcesManager_cpp::GetList() const
522 {
523   return _resourcesList;
524 }
525
526 //! threadsafe
527 std::string ResourcesManager_cpp::Find(const std::string& policy, const std::vector<std::string>& listOfResources) const
528 {
529   std::map<std::string , LoadRateManager*>::const_iterator it(_resourceManagerMap.find(policy));
530   if(it==_resourceManagerMap.end())
531         {
532           it=_resourceManagerMap.find("");
533           return ((*it).second)->Find(listOfResources, _resourcesList);
534         }
535   return ((*it).second)->Find(listOfResources, _resourcesList);
536 }
537
538 //=============================================================================
539 /*!
540  *  Gives a sublist of resources with matching OS.
541  *  If parameter OS is empty, gives the complete list of resources
542  */ 
543 //=============================================================================
544 void 
545 ResourcesManager_cpp::SelectOnlyResourcesWithOS(std::vector<std::string>& resources, std::string OS)
546 {
547   if (OS != "")
548   {
549     // a computer list is given : take only resources with OS on those computers
550     std::vector<std::string> vec_tmp = resources;
551     resources.clear();
552     std::vector<std::string>::iterator iter = vec_tmp.begin();
553     for (; iter != vec_tmp.end(); iter++)
554     {
555       MapOfParserResourcesType::const_iterator it = _resourcesList.find(*iter);
556       if(it != _resourcesList.end())
557         if ( (*it).second.OS == OS)
558           resources.push_back(*iter);
559     }
560   }
561 }
562
563
564 //=============================================================================
565 /*!
566  *  Gives a sublist of machines on which the component is known.
567  */ 
568 //=============================================================================
569 void 
570 ResourcesManager_cpp::KeepOnlyResourcesWithComponent(std::vector<std::string>& resources, 
571                                                      const std::vector<std::string>& componentList)
572 {
573   std::vector<std::string> kept_resources;
574
575   std::vector<std::string>::iterator iter = resources.begin();
576   for (; iter != resources.end(); iter++)
577   {
578     const std::vector<std::string>& mapOfComponentsOfCurrentHost = _resourcesList[*iter].ComponentsList;
579
580     bool erasedHost = false;
581     if( mapOfComponentsOfCurrentHost.size() > 0 )
582     {
583       for(unsigned int i=0; i<componentList.size(); i++)
584       {
585         std::vector<std::string>::const_iterator itt = find(mapOfComponentsOfCurrentHost.begin(),
586                                                             mapOfComponentsOfCurrentHost.end(),
587                                                             componentList[i]);
588         if (itt == mapOfComponentsOfCurrentHost.end())
589         {
590           erasedHost = true;
591           break;
592         }
593       }
594     }
595     if(!erasedHost)
596       kept_resources.push_back(*iter);
597   }
598   resources=kept_resources;
599 }
600
601 //! thread safe
602 ParserResourcesType ResourcesManager_cpp::GetResourcesDescr(const std::string & name) const
603 {
604   MapOfParserResourcesType::const_iterator it(_resourcesList.find(name));
605   if (it != _resourcesList.end())
606     return (*it).second;
607   else
608   {
609     std::string error("[GetResourcesDescr] Resource does not exist: ");
610     error += name;
611     throw ResourcesException(error);
612   }
613 }
614
615 void ResourcesManager_cpp::AddDefaultResourceInCatalog()
616 {
617   ParserResourcesType resource;
618   resource.Name = DEFAULT_RESOURCE_NAME;
619   // We can't use "localhost" for parameter hostname because the containers are registered in the
620   // naming service with the real hostname, not "localhost"
621   resource.HostName = Kernel_Utils::GetHostname();
622   resource.DataForSort._Name = DEFAULT_RESOURCE_NAME;
623   resource.Protocol = sh;
624   resource.Batch = none;
625 #ifndef WIN32
626   struct stat statbuf;
627   if (getenv("HOME") != NULL && getenv("APPLI") != NULL)
628   {
629     if (stat(getenv("APPLI"), &statbuf) ==0 &&  S_ISREG(statbuf.st_mode))
630     {
631         // if $APPLI is a regular file, we asume it's a salome Launcher file
632         resource.AppliPath = string(getenv("APPLI"));
633     }
634     else
635     {
636         resource.AppliPath = string(getenv("HOME")) + "/" + getenv("APPLI");
637     }
638   }
639   string tmpdir = "/tmp";
640   if (getenv("TMPDIR") != NULL)
641     tmpdir = getenv("TMPDIR");
642   resource.working_directory = tmpdir + "/salome_localres_workdir";
643   if (getenv("USER") != NULL)
644     resource.working_directory += string("_") + getenv("USER");
645 #else
646   if (getenv("USERPROFILE") != NULL && getenv("APPLI") != NULL)
647   {
648     resource.AppliPath = string(getenv("USERPROFILE")) + "\\" + getenv("APPLI");
649   }
650   string tmpdir = "C:\\tmp";
651   if (getenv("TEMP") != NULL)
652     tmpdir = getenv("TEMP");
653   resource.working_directory = tmpdir + "\\salome_localres_workdir";
654   if (getenv("USERNAME") != NULL)
655     resource.working_directory += string("_") + getenv("USERNAME");
656 #endif
657   resource.can_launch_batch_jobs = true;
658   resource.can_run_containers = true;
659   _resourcesList[resource.Name] = resource;
660 }