Version: 9.15.0
SalomeContainerTools.cxx
Go to the documentation of this file.
1 // Copyright (C) 2006-2025 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"
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"
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 
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 
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 
231 {
232  return std::string(_params.container_name);
233 }
234 
236 {
237  return _params.resource_params.nb_proc_per_node;
238 }
239 
240 void SalomeContainerTools::setContainerName(const std::string& name)
241 {
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 
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 
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 
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());
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  {
425  std::ostringstream oss; oss << "SalomeContainer::start : Unable to launch container " << myparams.container_name << " in Salome : CORBA Comm failure detected";
426  throw Exception( oss.str() );
427  }
428  }
429  catch(CORBA::Exception&)
430  {
431  std::ostringstream oss; oss << "SalomeContainer::start : Unable to launch container " << myparams.container_name << " in Salome : Unexpected CORBA failure detected";
432  throw Exception( oss.str() );
433  }
434  }
435 
436  if(CORBA::is_nil(trueCont))
437  {
438  std::ostringstream oss; oss << "SalomeContainer::start : Unable to launch container " << myparams.container_name << " in Salome. Check your CatalogResources.xml file";
439  throw Exception( oss.str() );
440  }
441 
442  // TODO : thread safety!
443  schelp->setContainer(askingNode,trueCont);
444 
445  CORBA::String_var containerName(trueCont->name()),hostName(trueCont->getHostName());
446  //std::cerr << "SalomeContainer launched : " << containerName << " " << hostName << " " << trueCont->getPID() << std::endl;
447  DEBUG_YACSTRACE("SalomeContainer launched : NS entry : " << containerName << " PID : " << trueCont->getPID() );
448 }
449 
450 CORBA::Object_ptr SalomeContainerToolsBase::LoadComponent(SalomeContainerHelper *launchModeType, Container *cont, Task *askingNode)
451 {
452  DEBUG_YACSTRACE("SalomeContainer::loadComponent ");
453  const ComponentInstance *inst(askingNode?askingNode->getComponent():0);
454  {
455  YACS::BASES::AutoLocker<Container> alck(cont);//To be sure
456  if(!cont->isAlreadyStarted(askingNode))
457  cont->start(askingNode);
458  }
459  if(!inst)
460  throw Exception("SalomeContainerToolsBase::LoadComponent : no instance of component in the task requesting for a load of its component !");
461  CORBA::Object_ptr objComponent=CORBA::Object::_nil();
462  {
463  YACS::BASES::AutoLocker<Container> alck(cont);//To be sure
464  std::string compoName(inst->getCompoName());
465  Engines::Container_var container(launchModeType->getContainer(askingNode));
466 
467  char *reason;
468  bool isLoadable(container->load_component_Library(compoName.c_str(), reason));
469  if(isLoadable)
470  objComponent=CreateComponentInstance(cont,container,inst);
471  }
472  return objComponent;
473 }
474 
475 CORBA::Object_ptr SalomeContainerToolsBase::CreateComponentInstance(Container *cont, Engines::Container_ptr contPtr, const ComponentInstance *inst)
476 {
477  if(!inst)
478  throw Exception("SalomeContainerToolsBase::CreateComponentInstance : no instance of component in the task requesting for a load of its component !");
479  char *reason(0);
480  std::string compoName(inst->getCompoName());
481  CORBA::Object_ptr objComponent=CORBA::Object::_nil();
482  Proc* p(cont->getProc());
483  // prepare component instance properties
484  Engines::FieldsDict_var env(new Engines::FieldsDict);
485  std::map<std::string, std::string> properties(inst->getProperties());
486  if(p)
487  {
488  std::map<std::string,std::string> procMap=p->getProperties();
489  properties.insert(procMap.begin(),procMap.end());
490  }
491 
492  std::map<std::string, std::string>::const_iterator itm;
493  env->length(properties.size());
494  int item=0;
495  for(itm = properties.begin(); itm != properties.end(); ++itm, item++)
496  {
497  DEBUG_YACSTRACE("envname="<<itm->first<<" envvalue="<< itm->second);
498  env[item].key= CORBA::string_dup(itm->first.c_str());
499  env[item].value <<= itm->second.c_str();
500  }
501 
502  objComponent=contPtr->create_component_instance_env(compoName.c_str(), env, reason);
503  if(CORBA::is_nil(objComponent))
504  {
505  std::string text="Error while trying to create a new component: component '"+ compoName;
506  text=text+"' is not installed or it's a wrong name";
507  text += '\n';
508  text += reason;
509  CORBA::string_free(reason);
510  throw Exception(text);
511  }
512  return objComponent;
513 }
514 
515 std::string SalomeContainerToolsBase::GetPlacementId(const SalomeContainerHelper *launchModeType, const Container *cont, const Task *askingNode)
516 {
517  if(cont->isAlreadyStarted(askingNode))
518  {
519  Engines::Container_var container(launchModeType->getContainer(askingNode));
520  const char *what="/";
521  CORBA::String_var corbaStr(container->name());
522  std::string ret(corbaStr);
523 
524  //Salome FOREVER ...
525  std::string::size_type i=ret.find_first_of(what,0);
526  i=ret.find_first_of(what, i==std::string::npos ? i:i+1);
527  if(i!=std::string::npos)
528  return ret.substr(i+1);
529  return ret;
530  }
531  else
532  return "Not placed yet !!!";
533 }
534 
535 std::string SalomeContainerToolsBase::GetFullPlacementId(const SalomeContainerHelper *launchModeType, const Container *cont, const Task *askingNode)
536 {
537  if(cont->isAlreadyStarted(askingNode))
538  {
539  Engines::Container_var container(launchModeType->getContainer(askingNode));
540  try
541  {
542  CORBA::String_var corbaStr(container->name());
543  std::string ret(corbaStr);
544  return ret;
545  }
546  catch(...)
547  {
548  return "Unknown_placement";
549  }
550  }
551  else
552  return "Not_placed_yet";
553 }
554 
555 Engines::ContainerParameters SalomeContainerToolsDecorator::getParameters() const
556 {
557  Engines::ContainerParameters ret(_decorated->getParameters());
558  std::string st(ret.resource_params.hostname);
559  if(!st.empty())
560  return ret;
561  int nbProcPerNode(this->_nb_cores_per_worker);
562  std::size_t iPos(_vh->locateTask(_node)),nPos(_vh->size());
563  if(_vh->size()!=_pg->getNumberOfWorkers(nbProcPerNode))
564  throw YACS::Exception("SalomeContainerToolsDecorator::getParameters : Internal error !");
565  std::string zeMachine(_pg->deduceMachineFrom(iPos,nbProcPerNode));
566  ret.resource_params.hostname=CORBA::string_dup(zeMachine.c_str());
567  return ret;
568 }
#define DEBUG_YACSTRACE(msg)
Definition: YacsTrace.hxx:53
void init_orb(CORBA::ORB_ptr orb=0) override
CORBA::Object_ptr Resolve(const char *Path) override
Base class for all component instances.
const std::string & getCompoName() const
virtual void start(const Task *askingNode)=0
virtual std::string getDiscreminantStrOfThis(const Task *askingNode) const
Definition: Container.cxx:45
virtual bool isAlreadyStarted(const Task *askingNode) const =0
virtual std::string getName() const
Definition: Container.hxx:81
std::map< std::string, std::string > getProperties()
Definition: Node.cxx:509
int getNumberOfWorkers(int nbCoresPerWorker) const
Definition: PlayGround.cxx:579
std::string deduceMachineFrom(int workerId, int nbProcPerNode) const
Definition: PlayGround.cxx:570
Base class for all schema objects.
Definition: Proc.hxx:44
std::map< std::string, std::string > getProperties() const
CORBA::ORB_ptr getOrb() const
virtual Engines::Container_var getContainer(const Task *askingNode) const =0
virtual std::string getDftLaunchMode() const =0
virtual void setContainer(const Task *askingNode, Engines::Container_var cont)=0
static std::string GetPlacementId(const SalomeContainerHelper *launchModeType, const Container *cont, const Task *askingNode)
virtual Engines::ContainerParameters getParameters() const =0
virtual std::string getHostName() const =0
static void Start(const std::vector< std::string > &compoNames, SalomeContainerHelper *schelp, SalomeContainerToolsBase &sct, int &shutdownLevel, const Container *cont, const Task *askingNode)
static CORBA::Object_ptr CreateComponentInstance(Container *cont, Engines::Container_ptr contPtr, const ComponentInstance *inst)
static CORBA::Object_ptr LoadComponent(SalomeContainerHelper *launchModeType, Container *cont, Task *askingNode)
static std::string GetFullPlacementId(const SalomeContainerHelper *launchModeType, const Container *cont, const Task *askingNode)
virtual void addToComponentList(const std::string &name)=0
virtual std::string getNotNullContainerName(const Container *contPtr, const Task *askingNode, bool &isEmpty) const =0
static void SetContainerNameOf(Engines::ContainerParameters &params, const std::string &name)
Engines::ContainerParameters getParameters() const override
std::map< std::string, std::string > getResourceProperties(const std::string &name) const override
std::string getHostName() const override
std::map< std::string, std::string > _propertyMap
std::string getProperty(const std::string &name) const override
Engines::ContainerParameters _params
std::string getNotNullContainerName(const Container *contPtr, const Task *askingNode, bool &isEmpty) const override
std::string getContainerName() const override
void addToComponentList(const std::string &name) override
void setProperty(const std::string &name, const std::string &value) override
void addToResourceList(const std::string &name) override
void setContainerName(const std::string &name) override
std::size_t locateTask(const Task *node) const
virtual ComponentInstance * getComponent()=0
Proc * p
Definition: driver.cxx:216
YACSRUNTIMESALOME_EXPORT RuntimeSALOME * getSALOMERuntime()
CORBA::ORB_ptr orb
Definition: yacsSrv.cxx:39