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