Salome HOME
4a2a4427b07bead9abc25ce545badc0668e7822f
[modules/yacs.git] / src / runtime / SalomeContainerTools.cxx
1 // Copyright (C) 2006-2024  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #define _DEVDEBUG_
20 #include "SalomeContainerTools.hxx"
21 #include "SALOME_LifeCycleCORBA.hxx"
22 #include "SALOME_NamingService_Wrapper.hxx"
23 #include "SALOME_ResourcesManager.hxx"
24 #include "SALOME_ContainerManager.hxx"
25
26 #include "Container.hxx"
27 #include "AutoLocker.hxx"
28
29 #include "YacsTrace.hxx"
30 #include "Proc.hxx"
31 #include "ServiceNode.hxx"
32 #include "ComponentInstance.hxx"
33 #include "SalomeContainerHelper.hxx"
34 #include "SalomeHPContainerTools.hxx"
35 #include "RuntimeSALOME.hxx"
36 #include "Exception.hxx"
37
38 #include <sstream>
39
40 #ifdef WIN32
41 #include <process.h>
42 #define getpid _getpid
43 #endif
44
45 using namespace YACS::ENGINE;
46
47 SalomeContainerTools::SalomeContainerTools()
48 {
49   /* Init ContainerParameters */
50   SALOME_LifeCycleCORBA::preSet(_params);
51 }
52
53 SalomeContainerTools::SalomeContainerTools(const SalomeContainerTools& other):_params(other._params),_propertyMap(other._propertyMap)
54 {
55 }
56
57 void SalomeContainerTools::clearProperties()
58 {
59   _propertyMap.clear();
60   _params=Engines::ContainerParameters();
61 }
62
63 std::string SalomeContainerTools::getProperty(const std::string& name) const
64 {
65   std::map<std::string,std::string>::const_iterator it(_propertyMap.find(name));
66   if(it!=_propertyMap.end())
67     return (*it).second;
68   else
69     return std::string();
70 }
71
72 void SalomeContainerTools::setProperty(const std::string& name, const std::string& value)
73 {
74   //DEBUG_YACSTRACE("SalomeContainer::setProperty : " << name << " ; " << value);
75   // Container Part
76   if (name == "container_name")
77     _params.container_name = CORBA::string_dup(value.c_str());
78   else if (name == "workingdir")
79     _params.workingdir = CORBA::string_dup(value.c_str());
80   else if (name == "nb_parallel_procs")
81   {
82     std::istringstream iss(value);
83     if (!(iss >> _params.nb_proc))
84       throw Exception("salomecontainer::setproperty : params.nb_proc value not correct : " + value);
85   }
86   else if (name == "isMPI")
87   {
88     if (value == "true")
89       _params.isMPI = true;
90     else if (value == "false")
91       _params.isMPI = false;
92     else 
93       throw Exception("SalomeContainer::setProperty : params.isMPI value not correct : " + value);
94   }
95   else if (name == "parallelLib")
96     _params.parallelLib = CORBA::string_dup(value.c_str());
97
98   // Resource part
99   else if (name == "name")
100     _params.resource_params.name = CORBA::string_dup(value.c_str());
101   else if (name == "hostname")
102     _params.resource_params.hostname = CORBA::string_dup(value.c_str());
103   else if (name == "OS")
104     _params.resource_params.OS = CORBA::string_dup(value.c_str());
105   else if (name == "nb_resource_procs")
106   {
107     std::istringstream iss(value);
108     if (!(iss >> _params.resource_params.nb_proc))
109       throw Exception("salomecontainer::setproperty : params.resource_params.nb_proc value not correct : " + value);
110   }
111   else if (name == "mem_mb")
112   {
113     std::istringstream iss(value);
114     if (!(iss >> _params.resource_params.mem_mb))
115       throw Exception("salomecontainer::setproperty : params.resource_params.mem_mb value not correct : " + value);
116   }
117   else if (name == "cpu_clock")
118   {
119     std::istringstream iss(value);
120     if (!(iss >> _params.resource_params.cpu_clock))
121       throw Exception("salomecontainer::setproperty : params.resource_params.cpu_clock value not correct : " + value);
122   }
123   else if (name == "nb_node")
124   {
125     std::istringstream iss(value);
126     if (!(iss >> _params.resource_params.nb_node))
127       throw Exception("salomecontainer::setproperty : params.nb_node value not correct : " + value);
128   }
129   else if (name == "nb_proc_per_node")
130   {
131     std::istringstream iss(value);
132     if (!(iss >> _params.resource_params.nb_proc_per_node))
133       throw Exception("salomecontainer::setproperty : params.nb_proc_per_node value not correct : " + value);
134   }
135   else if (name == "policy")
136     _params.resource_params.policy = CORBA::string_dup(value.c_str());
137   else if (name == "component_list")
138   {
139     std::string clean_value(value);
140
141     // Step 1: remove blanks
142     while(clean_value.find(" ") != std::string::npos)
143       clean_value = clean_value.erase(clean_value.find(" "), 1);
144
145     // Step 2: get values
146     while(!clean_value.empty())
147     {
148       std::string result("");
149       std::string::size_type loc = clean_value.find(",", 0);
150       if (loc != std::string::npos)
151       {
152         result = clean_value.substr(0, loc);
153         clean_value = clean_value.erase(0, loc+1);
154       }
155       else
156       {
157         result = clean_value;
158         clean_value.erase();
159       }
160       if (result != "," && result != "")
161       {
162         addToComponentList(result);
163       }
164     }
165
166   }
167   else if (name == "resource_list")
168   {
169     std::string clean_value(value);
170
171     // Step 1: remove blanks
172     while(clean_value.find(" ") != std::string::npos)
173       clean_value = clean_value.erase(clean_value.find(" "), 1);
174
175     // Step 2: get values
176     while(!clean_value.empty())
177     {
178       std::string result("");
179       std::string::size_type loc = clean_value.find(",", 0);
180       if (loc != std::string::npos)
181       {
182         result = clean_value.substr(0, loc);
183         clean_value = clean_value.erase(0, loc+1);
184       }
185       else
186       {
187         result = clean_value;
188         clean_value.erase();
189       }
190       if (result != "," && result != "")
191       {
192         addToResourceList(result);
193       }
194     }
195
196   }
197   _propertyMap[name]=value;
198 }
199
200 void SalomeContainerTools::addToComponentList(const std::string& name)
201 {
202   // Search if name is already in the list
203   for (CORBA::ULong i = 0; i < _params.resource_params.componentList.length(); i++)
204     {
205       std::string component_name = _params.resource_params.componentList[i].in();
206       if (component_name == name)
207         return;
208     }
209   // Add name to list
210   CORBA::ULong lgth = _params.resource_params.componentList.length();
211   _params.resource_params.componentList.length(lgth + 1);
212   _params.resource_params.componentList[lgth] = CORBA::string_dup(name.c_str());
213 }
214
215 void SalomeContainerTools::addToResourceList(const std::string& name)
216 {
217   // Search if name is already in the list
218   for (CORBA::ULong i = 0; i < _params.resource_params.resList.length(); i++)
219     {
220       std::string component_name = _params.resource_params.resList[i].in();
221       if (component_name == name)
222         return;
223     }
224   // Add name to list
225   CORBA::ULong lgth = _params.resource_params.resList.length();
226   _params.resource_params.resList.length(lgth + 1);
227   _params.resource_params.resList[lgth] = CORBA::string_dup(name.c_str());
228 }
229
230 std::string SalomeContainerTools::getContainerName() const
231 {
232   return std::string(_params.container_name);
233 }
234
235 int SalomeContainerTools::getNumberOfCoresPerWorker() const
236 {
237   return _params.resource_params.nb_proc_per_node;
238 }
239
240 void SalomeContainerTools::setContainerName(const std::string& name)
241 {
242   SetContainerNameOf(_params,name);
243 }
244
245 std::string SalomeContainerTools::getNotNullContainerName(const Container *contPtr, const Task *askingNode, bool& isEmpty) const
246 {
247   isEmpty=true;
248   std::string name(_params.container_name);
249   if(!name.empty())
250     {
251       isEmpty=false;
252       return name;
253     }
254   else
255     {
256       //give a almost unique name to the container : Pid_Name_Addr
257       std::ostringstream stream;
258       stream << getpid();
259       stream << "_";
260       stream << contPtr->getName();
261       stream << "_";
262       stream << contPtr->getDiscreminantStrOfThis(askingNode);
263       return stream.str();
264     }
265 }
266
267 std::string SalomeContainerTools::getHostName() const
268 {
269   return std::string(_params.resource_params.hostname);
270 }
271
272 void SalomeContainerToolsBase::SetContainerNameOf(Engines::ContainerParameters& params, const std::string& name)
273 {
274   params.container_name=CORBA::string_dup(name.c_str());
275 }
276
277 std::map<std::string,std::string> SalomeContainerTools::getResourceProperties(const std::string& name) const
278 {
279   std::map<std::string,std::string> properties;
280
281   YACS::ENGINE::RuntimeSALOME* runTime = YACS::ENGINE::getSALOMERuntime();
282   CORBA::ORB_ptr orb = runTime->getOrb();
283   if (!orb) return properties;
284   SALOME_NamingService_Wrapper namingService(orb);
285   SALOME_LifeCycleCORBA lcc(&namingService);
286   CORBA::Object_var obj = namingService.Resolve(SALOME_ResourcesManager::_ResourcesManagerNameInNS);
287   if (CORBA::is_nil(obj))
288     return properties;
289   Engines::ResourcesManager_var resManager = Engines::ResourcesManager::_narrow(obj);
290   if (CORBA::is_nil(resManager))
291     return properties;
292
293   std::ostringstream value;
294   Engines::ResourceDefinition_var resource_definition = resManager->GetResourceDefinition(name.c_str());
295   properties["hostname"]=resource_definition->hostname.in();
296   properties["OS"]=resource_definition->OS.in();
297   value.str(""); value << resource_definition->mem_mb;
298   properties["mem_mb"]=value.str();
299   value.str(""); value << resource_definition->cpu_clock;
300   properties["cpu_clock"]=value.str();
301   value.str(""); value << resource_definition->nb_node;
302   properties["nb_node"]=value.str();
303   value.str(""); value << resource_definition->nb_proc_per_node;
304   properties["nb_proc_per_node"]=value.str();
305   /*
306   properties["component_list"]="";
307   for(CORBA::ULong i=0; i < resource_definition->componentList.length(); i++)
308     {
309       if(i > 0)
310         properties["component_list"]=properties["component_list"]+",";
311       properties["component_list"]=properties["component_list"]+resource_definition->componentList[i].in();
312     }
313     */
314   return properties;
315 }
316
317 /*!
318  * \param [in] compoNames
319  * \param [in,out] shutdownLevel
320  */
321 void SalomeContainerToolsBase::Start(const std::vector<std::string>& compoNames, SalomeContainerHelper *schelp, SalomeContainerToolsBase& sct, int& shutdownLevel, const Container *cont, const Task *askingNode)
322 {
323   CORBA::ORB_ptr orb(getSALOMERuntime()->getOrb());
324   SALOME_NamingService_Wrapper ns;
325   try
326   {
327       ns.init_orb(orb);
328   }
329   catch(SALOME_Exception& e)
330   {
331       throw Exception("SalomeContainer::start : Unable to contact the SALOME Naming Service");
332   }
333   CORBA::Object_var obj(ns.Resolve(SALOME_ContainerManager::_ContainerManagerNameInNS));
334   Engines::ContainerManager_var contManager(Engines::ContainerManager::_narrow(obj));
335
336   bool isEmptyName;
337   std::string str(sct.getNotNullContainerName(cont,askingNode,isEmptyName));
338   DEBUG_YACSTRACE("SalomeContainer::start " << str <<";"<< sct.getHostName() );
339
340   // Finalize parameters with components found in the container
341
342   for(std::vector<std::string>::const_iterator iter=compoNames.begin();iter!=compoNames.end();iter++)
343     sct.addToComponentList(*iter);
344
345   Engines::ContainerParameters myparams(sct.getParameters());
346   {
347     std::string dftLauchMode(schelp->getDftLaunchMode());
348     myparams.mode=CORBA::string_dup(dftLauchMode.c_str());
349   }
350
351   //If a container_name is given try to find an already existing container in naming service
352   //If not found start a new container with the given parameters
353   if (dynamic_cast<SalomeContainerMonoHelper *>(schelp) && !isEmptyName)
354     {
355       myparams.mode=CORBA::string_dup("getorstart");
356     }
357
358   if (isEmptyName)
359     {
360       shutdownLevel=1;
361     }
362   //sct.setContainerName(str);
363   SetContainerNameOf(myparams,str);
364   Engines::Container_var trueCont(Engines::Container::_nil());
365   if(!isEmptyName && shutdownLevel==999)
366     {
367       //Make this only the first time start is called (_shutdownLevel==999)
368       //If the container is named, first try to get an existing container
369       //If there is an existing container use it and set the shutdown level to 3
370       //If there is no existing container, try to launch a new one and set the shutdown level to 2
371       myparams.mode="get";
372       try
373       {
374           DEBUG_YACSTRACE("GiveContainer " << str << " mode " << myparams.mode);
375           trueCont=contManager->GiveContainer(myparams);
376       }
377       catch( const SALOME::SALOME_Exception& ex )
378       {
379           std::string msg="SalomeContainer::start : no existing container : ";
380           msg += '\n';
381           msg += ex.details.text.in();
382           DEBUG_YACSTRACE( msg );
383       }
384       catch(...)
385       {
386       }
387
388       if(!CORBA::is_nil(trueCont))
389         {
390           shutdownLevel=3;
391           DEBUG_YACSTRACE( "container found: " << str << " " << shutdownLevel );
392         }
393       else
394         {
395           shutdownLevel=2;
396           myparams.mode="start";
397           DEBUG_YACSTRACE( "container not found: " << str << " " << shutdownLevel);
398         }
399     }
400
401   int nbTries=0;
402   while(CORBA::is_nil(trueCont))
403   {
404     try
405     {
406           // --- GiveContainer is used in batch mode to retreive launched containers,
407           //     and is equivalent to StartContainer when not in batch.
408           DEBUG_YACSTRACE("GiveContainer " << str << " mode " << myparams.mode);
409           trueCont=contManager->GiveContainer(myparams);
410     }
411     catch( const SALOME::SALOME_Exception& ex )
412     {
413         std::string msg="SalomeContainer::start : Unable to launch container in Salome : ";
414         msg += '\n';
415         msg += ex.details.text.in();
416         throw Exception(msg);
417     }
418     catch(CORBA::COMM_FAILURE&)
419     {
420       //std::cerr << "SalomeContainer::start : CORBA Comm failure detected. Make another try!" << std::endl;
421       DEBUG_YACSTRACE("SalomeContainer::start :" << str << " :CORBA Comm failure detected. Make another try!");
422       nbTries++;
423       if(nbTries > 5)
424         throw Exception("SalomeContainer::start : Unable to launch container in Salome : CORBA Comm failure detected");
425     }
426     catch(CORBA::Exception&)
427     {
428         throw Exception("SalomeContainer::start : Unable to launch container in Salome : Unexpected CORBA failure detected");
429     }
430   }
431
432   if(CORBA::is_nil(trueCont))
433     throw Exception("SalomeContainer::start : Unable to launch container in Salome. Check your CatalogResources.xml file");
434
435   // TODO : thread safety!
436   schelp->setContainer(askingNode,trueCont);
437
438   CORBA::String_var containerName(trueCont->name()),hostName(trueCont->getHostName());
439   //std::cerr << "SalomeContainer launched : " << containerName << " " << hostName << " " << trueCont->getPID() << std::endl;
440   DEBUG_YACSTRACE("SalomeContainer launched : NS entry : " << containerName << " PID : " << trueCont->getPID() );
441 }
442
443 CORBA::Object_ptr SalomeContainerToolsBase::LoadComponent(SalomeContainerHelper *launchModeType, Container *cont, Task *askingNode)
444 {
445   DEBUG_YACSTRACE("SalomeContainer::loadComponent ");
446   const ComponentInstance *inst(askingNode?askingNode->getComponent():0);
447   {
448     YACS::BASES::AutoLocker<Container> alck(cont);//To be sure
449     if(!cont->isAlreadyStarted(askingNode))
450       cont->start(askingNode);
451   }
452   if(!inst)
453     throw Exception("SalomeContainerToolsBase::LoadComponent : no instance of component in the task requesting for a load of its component !");
454   CORBA::Object_ptr objComponent=CORBA::Object::_nil();
455   {
456     YACS::BASES::AutoLocker<Container> alck(cont);//To be sure
457     std::string compoName(inst->getCompoName());
458     Engines::Container_var container(launchModeType->getContainer(askingNode));
459
460     char *reason;
461     bool isLoadable(container->load_component_Library(compoName.c_str(), reason));
462     if(isLoadable)
463       objComponent=CreateComponentInstance(cont,container,inst);
464   }
465   return objComponent;
466 }
467
468 CORBA::Object_ptr SalomeContainerToolsBase::CreateComponentInstance(Container *cont, Engines::Container_ptr contPtr, const ComponentInstance *inst)
469 {
470   if(!inst)
471     throw Exception("SalomeContainerToolsBase::CreateComponentInstance : no instance of component in the task requesting for a load of its component !");
472   char *reason(0);
473   std::string compoName(inst->getCompoName());
474   CORBA::Object_ptr objComponent=CORBA::Object::_nil();
475   Proc* p(cont->getProc());
476   // prepare component instance properties
477   Engines::FieldsDict_var env(new Engines::FieldsDict);
478   std::map<std::string, std::string> properties(inst->getProperties());
479   if(p)
480     {
481       std::map<std::string,std::string> procMap=p->getProperties();
482       properties.insert(procMap.begin(),procMap.end());
483     }
484
485   std::map<std::string, std::string>::const_iterator itm;
486   env->length(properties.size());
487   int item=0;
488   for(itm = properties.begin(); itm != properties.end(); ++itm, item++)
489     {
490       DEBUG_YACSTRACE("envname="<<itm->first<<" envvalue="<< itm->second);
491       env[item].key= CORBA::string_dup(itm->first.c_str());
492       env[item].value <<= itm->second.c_str();
493     }
494
495   objComponent=contPtr->create_component_instance_env(compoName.c_str(), env, reason);
496   if(CORBA::is_nil(objComponent))
497     {
498       std::string text="Error while trying to create a new component: component '"+ compoName;
499       text=text+"' is not installed or it's a wrong name";
500       text += '\n';
501       text += reason;
502       CORBA::string_free(reason);
503       throw Exception(text);
504     }
505   return objComponent;
506 }
507
508 std::string SalomeContainerToolsBase::GetPlacementId(const SalomeContainerHelper *launchModeType, const Container *cont, const Task *askingNode)
509 {
510   if(cont->isAlreadyStarted(askingNode))
511     {
512       Engines::Container_var container(launchModeType->getContainer(askingNode));
513       const char *what="/";
514       CORBA::String_var corbaStr(container->name());
515       std::string ret(corbaStr);
516
517       //Salome FOREVER ...
518       std::string::size_type i=ret.find_first_of(what,0);
519       i=ret.find_first_of(what, i==std::string::npos ? i:i+1);
520       if(i!=std::string::npos)
521         return ret.substr(i+1);
522       return ret;
523     }
524   else
525     return "Not placed yet !!!";
526 }
527
528 std::string SalomeContainerToolsBase::GetFullPlacementId(const SalomeContainerHelper *launchModeType, const Container *cont, const Task *askingNode)
529 {
530   if(cont->isAlreadyStarted(askingNode))
531     {
532       Engines::Container_var container(launchModeType->getContainer(askingNode));
533       try
534       {
535           CORBA::String_var corbaStr(container->name());
536           std::string ret(corbaStr);
537           return ret;
538       }
539       catch(...)
540       {
541           return "Unknown_placement";
542       }
543     }
544   else
545     return "Not_placed_yet";
546 }
547
548 Engines::ContainerParameters SalomeContainerToolsDecorator::getParameters() const
549 {
550   Engines::ContainerParameters ret(_decorated->getParameters());
551   std::string st(ret.resource_params.hostname);
552   if(!st.empty())
553     return ret;
554   int nbProcPerNode(this->_nb_cores_per_worker);
555   std::size_t iPos(_vh->locateTask(_node)),nPos(_vh->size());
556   if(_vh->size()!=_pg->getNumberOfWorkers(nbProcPerNode))
557     throw YACS::Exception("SalomeContainerToolsDecorator::getParameters : Internal error !");
558   std::string zeMachine(_pg->deduceMachineFrom(iPos,nbProcPerNode));
559   ret.resource_params.hostname=CORBA::string_dup(zeMachine.c_str());
560   return ret;
561 }