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