Salome HOME
Merge branch 'V7_main'
[modules/kernel.git] / src / Container / SALOME_ContainerManager.cxx
1 // Copyright (C) 2007-2014  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 "SALOME_ContainerManager.hxx"
24 #include "SALOME_NamingService.hxx"
25 #include "SALOME_ModuleCatalog.hh"
26 #include "Basics_Utils.hxx"
27 #include "Basics_DirUtils.hxx"
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <signal.h>
31 #ifndef WIN32
32 #include <unistd.h>
33 #endif
34 #include <vector>
35 #include "Utils_CorbaException.hxx"
36 #include <sstream>
37 #include <string>
38
39 #include <SALOMEconfig.h>
40 #include CORBA_CLIENT_HEADER(SALOME_Session)
41
42 #ifdef WIN32
43 #include <process.h>
44 #define getpid _getpid
45 #endif
46
47 #ifdef WITH_PACO_PARALLEL
48 #include "PaCOPP.hxx"
49 #endif
50
51 #define TIME_OUT_TO_LAUNCH_CONT 60
52
53 const char *SALOME_ContainerManager::_ContainerManagerNameInNS = 
54   "/ContainerManager";
55
56 omni_mutex SALOME_ContainerManager::_numInstanceMutex;
57
58
59 //=============================================================================
60 /*! 
61  *  Constructor
62  *  \param orb
63  *  Define a CORBA single thread policy for the server, which avoid to deal
64  *  with non thread-safe usage like Change_Directory in SALOME naming service
65  */
66 //=============================================================================
67
68 SALOME_ContainerManager::SALOME_ContainerManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa, SALOME_ResourcesManager *rm, SALOME_NamingService *ns):_nbprocUsed(1)
69 {
70   MESSAGE("constructor");
71   _NS = ns;
72   _ResManager = rm;
73
74   PortableServer::POAManager_var pman = poa->the_POAManager();
75   _orb = CORBA::ORB::_duplicate(orb) ;
76   CORBA::PolicyList policies;
77   policies.length(1);
78   PortableServer::ThreadPolicy_var threadPol = 
79     poa->create_thread_policy(PortableServer::SINGLE_THREAD_MODEL);
80   policies[0] = PortableServer::ThreadPolicy::_duplicate(threadPol);
81
82   _poa = poa->create_POA("SThreadPOA",pman,policies);
83   threadPol->destroy();
84   PortableServer::ObjectId_var id = _poa->activate_object(this);
85   CORBA::Object_var obj = _poa->id_to_reference(id);
86   Engines::ContainerManager_var refContMan =
87     Engines::ContainerManager::_narrow(obj);
88
89   _NS->Register(refContMan,_ContainerManagerNameInNS);
90   _isAppliSalomeDefined = (getenv("APPLI") != 0);
91
92 #ifdef HAVE_MPI2
93 #ifdef WITHOPENMPI
94   _pid_mpiServer = -1;
95   // the urifile name depends on pid of the process
96   std::stringstream urifile;
97   urifile << getenv("HOME") << "/.urifile_" << getpid();
98   setenv("OMPI_URI_FILE",urifile.str().c_str(),1);
99   if( getenv("OMPI_URI_FILE") != NULL ){
100     // get the pid of all ompi-server
101     std::set<pid_t> thepids1 = getpidofprogram("ompi-server");
102     // launch a new ompi-server
103     std::string command;
104     command = "ompi-server -r ";
105     command += getenv("OMPI_URI_FILE");
106     int status=system(command.c_str());
107     if(status!=0)
108       throw SALOME_Exception("Error when launching ompi-server");
109     // get the pid of all ompi-server
110     std::set<pid_t> thepids2 = getpidofprogram("ompi-server");
111     // my ompi-server is the new one
112     std::set<pid_t>::const_iterator it;
113     for(it=thepids2.begin();it!=thepids2.end();it++)
114       if(thepids1.find(*it) == thepids1.end())
115         _pid_mpiServer = *it;
116     if(_pid_mpiServer < 0)
117       throw SALOME_Exception("Error when getting ompi-server id");
118   }
119 #elif defined(WITHMPICH)
120   _pid_mpiServer = -1;
121   // get the pid of all hydra_nameserver
122   std::set<pid_t> thepids1 = getpidofprogram("hydra_nameserver");
123   // launch a new hydra_nameserver
124   std::string command;
125   command = "hydra_nameserver &";
126   system(command.c_str());
127   // get the pid of all hydra_nameserver
128   std::set<pid_t> thepids2 = getpidofprogram("hydra_nameserver");
129   // my hydra_nameserver is the new one
130   std::set<pid_t>::const_iterator it;
131   for(it=thepids2.begin();it!=thepids2.end();it++)
132     if(thepids1.find(*it) == thepids1.end())
133       _pid_mpiServer = *it;
134 #endif
135 #endif
136
137   MESSAGE("constructor end");
138 }
139
140 //=============================================================================
141 /*! 
142  * destructor
143  */
144 //=============================================================================
145
146 SALOME_ContainerManager::~SALOME_ContainerManager()
147 {
148   MESSAGE("destructor");
149 #ifdef HAVE_MPI2
150 #ifdef WITHOPENMPI
151   if( getenv("OMPI_URI_FILE") != NULL ){
152     // kill my ompi-server
153     if( kill(_pid_mpiServer,SIGTERM) != 0 )
154       throw SALOME_Exception("Error when killing ompi-server");
155     // delete my urifile
156     int status=system("rm -f ${OMPI_URI_FILE}");
157     if(status!=0)
158       throw SALOME_Exception("Error when removing urifile");
159   }
160 #elif defined(WITHMPICH)
161   // kill my hydra_nameserver
162   if(_pid_mpiServer > -1)
163     if( kill(_pid_mpiServer,SIGTERM) != 0 )
164       throw SALOME_Exception("Error when killing hydra_nameserver");
165 #endif
166 #endif
167 }
168
169 //=============================================================================
170 //! shutdown all the containers, then the ContainerManager servant
171 /*! CORBA method:
172  */
173 //=============================================================================
174
175 void SALOME_ContainerManager::Shutdown()
176 {
177   MESSAGE("Shutdown");
178   ShutdownContainers();
179   _NS->Destroy_Name(_ContainerManagerNameInNS);
180   PortableServer::ObjectId_var oid = _poa->servant_to_id(this);
181   _poa->deactivate_object(oid);
182 }
183
184 //=============================================================================
185 //! Loop on all the containers listed in naming service, ask shutdown on each
186 /*! CORBA Method:
187  */
188 //=============================================================================
189
190 void SALOME_ContainerManager::ShutdownContainers()
191 {
192   MESSAGE("ShutdownContainers");
193
194   SALOME::Session_var session = SALOME::Session::_nil();
195   CORBA::Long pid = 0;
196   CORBA::Object_var objS = _NS->Resolve("/Kernel/Session");
197   if (!CORBA::is_nil(objS))
198   {
199     session = SALOME::Session::_narrow(objS);
200     if (!CORBA::is_nil(session))
201       pid = session->getPID();
202   }
203
204   bool isOK;
205   isOK = _NS->Change_Directory("/Containers");
206   if( isOK ){
207     std::vector<std::string> vec = _NS->list_directory_recurs();
208     std::list<std::string> lstCont;
209     for(std::vector<std::string>::iterator iter = vec.begin();iter!=vec.end();iter++)
210       {
211         SCRUTE((*iter));
212         CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
213         try
214           {
215             Engines::Container_var cont=Engines::Container::_narrow(obj);
216             if(!CORBA::is_nil(cont) && pid != cont->getPID())
217               lstCont.push_back((*iter));
218           }
219         catch(const CORBA::Exception& e)
220           {
221             // ignore this entry and continue
222           }
223       }
224     MESSAGE("Container list: ");
225     for(std::list<std::string>::iterator iter=lstCont.begin();iter!=lstCont.end();iter++){
226       SCRUTE((*iter));
227     }
228     for(std::list<std::string>::iterator iter=lstCont.begin();iter!=lstCont.end();iter++)
229     {
230       try
231       {
232         SCRUTE((*iter));
233         CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
234         Engines::Container_var cont=Engines::Container::_narrow(obj);
235         if(!CORBA::is_nil(cont))
236         {
237           MESSAGE("ShutdownContainers: " << (*iter));
238           cont->Shutdown();
239         }
240         else 
241           MESSAGE("ShutdownContainers: no container ref for " << (*iter));
242       }
243       catch(CORBA::SystemException& e)
244       {
245         INFOS("CORBA::SystemException ignored : " << e);
246       }
247       catch(CORBA::Exception&)
248       {
249         INFOS("CORBA::Exception ignored.");
250       }
251       catch(...)
252       {
253         INFOS("Unknown exception ignored.");
254       }
255     }
256   }
257 }
258
259 //=============================================================================
260 //! Give a suitable Container given constraints
261 /*! CORBA Method:
262  *  \param params Container Parameters required for the container
263  *  \return the container or nil
264  */
265 //=============================================================================
266 Engines::Container_ptr
267 SALOME_ContainerManager::GiveContainer(const Engines::ContainerParameters& params)
268 {
269   std::string machFile;
270   Engines::Container_ptr ret = Engines::Container::_nil();
271
272   // Step 0: Default mode is start
273   Engines::ContainerParameters local_params(params);
274   if (std::string(local_params.mode.in()) == "")
275     local_params.mode = CORBA::string_dup("start");
276   std::string mode = local_params.mode.in();
277   MESSAGE("[GiveContainer] starting with mode: " << mode);
278
279   // Step 1: Find Container for find and findorstart mode
280   if (mode == "find" || mode == "findorstart")
281   {
282     ret = FindContainer(params, params.resource_params.resList);
283     if(!CORBA::is_nil(ret))
284       return ret;
285     else
286     {
287       if (mode == "find")
288       {
289         MESSAGE("[GiveContainer] no container found");
290         return ret;
291       }
292       else
293       {
294         mode = "start";
295       }
296     }
297   }
298
299   // Step 2: Get all possibleResources from the parameters
300   // Consider only resources that can run containers
301   local_params.resource_params.can_run_containers = true;
302   Engines::ResourceList_var possibleResources = _ResManager->GetFittingResources(local_params.resource_params);
303   MESSAGE("[GiveContainer] - length of possible resources " << possibleResources->length());
304   std::vector<std::string> local_resources;
305
306   // Step 3: if mode is "get" keep only machines with existing containers 
307   if(mode == "get")
308   {
309     for(unsigned int i=0; i < possibleResources->length(); i++)
310     {
311       Engines::Container_ptr cont = FindContainer(params, possibleResources[i].in());
312       try
313       {
314         if(!cont->_non_existent())
315           local_resources.push_back(std::string(possibleResources[i]));
316       }
317       catch(CORBA::Exception&) {}
318     }
319
320     // if local_resources is empty, we cannot give a container
321     if (local_resources.size() == 0)
322     {
323       MESSAGE("[GiveContainer] cannot find a container for mode get");
324       return ret;
325     }
326   }
327   else
328     for(unsigned int i=0; i < possibleResources->length(); i++)
329       local_resources.push_back(std::string(possibleResources[i]));
330
331   // Step 4: select the resource where to get/start the container
332   bool resource_available = true;
333   std::string resource_selected;
334   std::vector<std::string> resources = local_resources;
335   while (resource_available)
336   {
337     if (resources.size() == 0)
338       resource_available = false;
339     else
340     {
341       try
342       {
343         resource_selected = _ResManager->GetImpl()->Find(params.resource_params.policy.in(), resources);
344         // Remove resource_selected from vector
345         std::vector<std::string>::iterator it;
346         for (it=resources.begin() ; it < resources.end(); it++ )
347           if (*it == resource_selected)
348           {
349             resources.erase(it);
350             break;
351           }
352       }
353       catch(const SALOME_Exception &ex)
354       {
355         MESSAGE("[GiveContainer] Exception in ResourceManager find !: " << ex.what());
356         return ret;
357       }
358       MESSAGE("[GiveContainer] Resource selected is: " << resource_selected);
359
360       // Step 5: Create container name
361       Engines::ResourceDefinition_var resource_definition = _ResManager->GetResourceDefinition(resource_selected.c_str());
362       std::string hostname(resource_definition->hostname.in());
363       std::string containerNameInNS;
364       if(params.isMPI){
365         int nbproc;
366         if ( params.nb_proc <= 0 )
367           nbproc = 1;
368         else
369           nbproc = params.nb_proc;
370         try
371         {
372           if( getenv("LIBBATCH_NODEFILE") != NULL )
373             machFile = machinesFile(nbproc);
374         }
375         catch(const SALOME_Exception & ex)
376         {
377           std::string err_msg = ex.what();
378           err_msg += params.container_name;
379           INFOS(err_msg.c_str());
380           return ret;
381         }
382         // A mpi parallel container register on zero node in NS
383         containerNameInNS = _NS->BuildContainerNameForNS(params, GetMPIZeroNode(hostname,machFile).c_str());
384       }
385       else
386         containerNameInNS = _NS->BuildContainerNameForNS(params, hostname.c_str());
387       MESSAGE("[GiveContainer] Container name in the naming service: " << containerNameInNS);
388
389       // Step 6: check if the name exists in naming service
390       //if params.mode == "getorstart" or "get" use the existing container
391       //if params.mode == "start" shutdown the existing container before launching a new one with that name
392       CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
393       if (!CORBA::is_nil(obj))
394       {
395         try
396         {
397           Engines::Container_var cont=Engines::Container::_narrow(obj);
398           if(!cont->_non_existent())
399           {
400             if(std::string(params.mode.in())=="getorstart" || std::string(params.mode.in())=="get"){
401               return cont._retn(); /* the container exists and params.mode is getorstart or get use it*/
402             }
403             else
404             {
405               INFOS("[GiveContainer] A container is already registered with the name: " << containerNameInNS << ", shutdown the existing container");
406               cont->Shutdown(); // shutdown the registered container if it exists
407             }
408           }
409         }
410         catch(CORBA::Exception&)
411         {
412           INFOS("[GiveContainer] CORBA::Exception ignored when trying to get the container - we start a new one");
413         }
414       }
415       Engines::Container_var cont = LaunchContainer(params, resource_selected, hostname, machFile, containerNameInNS);
416       if (!CORBA::is_nil(cont))
417       {
418         INFOS("[GiveContainer] container " << containerNameInNS << " launched");
419         return cont._retn();
420       }
421       else
422       {
423         INFOS("[GiveContainer] Failed to launch container on resource " << resource_selected);
424       }
425     }
426   }
427
428   // We were not able to launch the container
429   INFOS("[GiveContainer] Cannot launch the container on the following selected resources:")
430   std::vector<std::string>::iterator it;
431   for (it=local_resources.begin() ; it < local_resources.end(); it++ )
432     INFOS("[GiveContainer] " << *it)
433   return ret;
434 }
435
436 Engines::Container_ptr
437 SALOME_ContainerManager::LaunchContainer(const Engines::ContainerParameters& params,
438                                          const std::string & resource_selected,
439                                          const std::string & hostname,
440                                          const std::string & machFile,
441                                          const std::string & containerNameInNS)
442 {
443
444   // Step 1: type of container: PaCO, Exe, Mpi or Classic
445   // Mpi already tested in step 5, specific code on BuildCommandToLaunch Local/Remote Container methods
446   // TODO -> separates Mpi from Classic/Exe
447   // Classic or Exe ?
448   std::string container_exe = "SALOME_Container"; // Classic container
449   Engines::ContainerParameters local_params(params);
450   Engines::Container_ptr ret = Engines::Container::_nil();
451   int found=0;
452   try
453   {
454     CORBA::String_var container_exe_tmp;
455     CORBA::Object_var obj = _NS->Resolve("/Kernel/ModulCatalog");
456     SALOME_ModuleCatalog::ModuleCatalog_var Catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj) ;
457     if (CORBA::is_nil (Catalog))
458     {
459       INFOS("[GiveContainer] Module Catalog is not found -> cannot launch a container");
460       return ret;
461     }
462     // Loop through component list
463     for(unsigned int i=0; i < local_params.resource_params.componentList.length(); i++)
464     {
465       const char* compoi = local_params.resource_params.componentList[i];
466       SALOME_ModuleCatalog::Acomponent_var compoInfo = Catalog->GetComponent(compoi);
467       if (CORBA::is_nil (compoInfo))
468       {
469         continue;
470       }
471       SALOME_ModuleCatalog::ImplType impl=compoInfo->implementation_type();
472       container_exe_tmp=compoInfo->implementation_name();
473       if(impl==SALOME_ModuleCatalog::CEXE)
474       {
475         if(found)
476         {
477           INFOS("ContainerManager Error: you can't have 2 CEXE component in the same container" );
478           return Engines::Container::_nil();
479         }
480         MESSAGE("[GiveContainer] Exe container found !: " << container_exe_tmp);
481         container_exe = container_exe_tmp.in();
482         found=1;
483       }
484     }
485   }
486   catch (ServiceUnreachable&)
487   {
488     INFOS("Caught exception: Naming Service Unreachable");
489     return ret;
490   }
491   catch (...)
492   {
493     INFOS("Caught unknown exception.");
494     return ret;
495   }
496
497   // Step 2: test resource
498   // Only if an application directory is set
499   if(hostname != Kernel_Utils::GetHostname() && _isAppliSalomeDefined)
500   {
501     // Preparing remote command
502     std::string command = "";
503     const ParserResourcesType& resInfo = _ResManager->GetImpl()->GetResourcesDescr(resource_selected);
504     command = getCommandToRunRemoteProcess(resInfo.Protocol, resInfo.HostName, resInfo.UserName);
505     if (resInfo.AppliPath != "")
506       command += resInfo.AppliPath;
507     else
508     {
509       ASSERT(getenv("APPLI"));
510       command += getenv("APPLI");
511     }
512     command += "/runRemote.sh ";
513     ASSERT(getenv("NSHOST")); 
514     command += getenv("NSHOST"); // hostname of CORBA name server
515     command += " ";
516     ASSERT(getenv("NSPORT"));
517     command += getenv("NSPORT"); // port of CORBA name server
518     command += " \"ls /tmp >/dev/null 2>&1\"";
519
520     // Launch remote command
521     int status = system(command.c_str());
522     if (status != 0)
523     {
524       // Error on resource - cannot launch commands
525       INFOS("[LaunchContainer] Cannot launch commands on machine " << hostname);
526       INFOS("[LaunchContainer] Command was " << command);
527 #ifndef WIN32
528       INFOS("[LaunchContainer] Command status is " << WEXITSTATUS(status));
529 #endif
530       return Engines::Container::_nil();
531     }
532   }
533
534   // Step 3: start a new container
535   // Check if a PaCO container
536   // PaCO++
537   if (std::string(local_params.parallelLib.in()) != "")
538   {
539     ret = StartPaCOPPContainer(params, resource_selected);
540     return ret;
541   }
542   // Other type of containers...
543   MESSAGE("[GiveContainer] Try to launch a new container on " << resource_selected);
544   std::string command;
545   // if a parallel container is launched in batch job, command is: "mpirun -np nbproc -machinefile nodesfile SALOME_MPIContainer"
546   if( getenv("LIBBATCH_NODEFILE") != NULL && params.isMPI )
547     command = BuildCommandToLaunchLocalContainer(params, machFile, container_exe);
548   // if a container is launched on localhost, command is "SALOME_Container" or "mpirun -np nbproc SALOME_MPIContainer"
549   else if(hostname == Kernel_Utils::GetHostname())
550     command = BuildCommandToLaunchLocalContainer(params, machFile, container_exe);
551   // if a container is launched in remote mode, command is "ssh resource_selected SALOME_Container" or "ssh resource_selected mpirun -np nbproc SALOME_MPIContainer"
552   else
553     command = BuildCommandToLaunchRemoteContainer(resource_selected, params, container_exe);
554
555   //redirect stdout and stderr in a file
556 #ifdef WIN32
557   std::string logFilename=getenv("TEMP");
558   logFilename += "\\";
559   std::string user = getenv( "USERNAME" );
560 #else
561   std::string user = getenv( "USER" );
562   std::string logFilename="/tmp";
563   char* val = getenv("SALOME_TMP_DIR");
564   if(val)
565   {
566     struct stat file_info;
567     stat(val, &file_info);
568     bool is_dir = S_ISDIR(file_info.st_mode);
569     if (is_dir)logFilename=val;
570     else std::cerr << "SALOME_TMP_DIR environment variable is not a directory use /tmp instead" << std::endl;
571   }
572   logFilename += "/";
573 #endif
574   logFilename += _NS->ContainerName(params)+"_"+ resource_selected +"_"+user;
575   std::ostringstream tmp;
576   tmp << "_" << getpid();
577   logFilename += tmp.str();
578   logFilename += ".log" ;
579   command += " > " + logFilename + " 2>&1";
580 #ifdef WIN32
581   command = "%PYTHONBIN% -c \"import win32pm ; win32pm.spawnpid(r'" + command + "', '')\"";
582 #else
583   command += " &";
584 #endif
585
586   // launch container with a system call
587   int status=system(command.c_str());
588
589   if (status == -1){
590     INFOS("[LaunchContainer] command failed (system command status -1): " << command);
591     RmTmpFile(_TmpFileName); // command file can be removed here
592     _TmpFileName="";
593     return Engines::Container::_nil();
594   }
595   else if (status == 217){
596     INFOS("[LaunchContainer] command failed (system command status 217): " << command);
597     RmTmpFile(_TmpFileName); // command file can be removed here
598     _TmpFileName="";
599     return Engines::Container::_nil();
600   }
601   else
602   {
603     // Step 4: Wait for the container
604     int count = TIME_OUT_TO_LAUNCH_CONT;
605     if (getenv("TIMEOUT_TO_LAUNCH_CONTAINER") != 0)
606     {
607       std::string new_count_str = getenv("TIMEOUT_TO_LAUNCH_CONTAINER");
608       int new_count;
609       std::istringstream ss(new_count_str);
610       if (!(ss >> new_count))
611       {
612         INFOS("[LaunchContainer] TIMEOUT_TO_LAUNCH_CONTAINER should be an int");
613       }
614       else
615         count = new_count;
616     }
617     INFOS("[GiveContainer] waiting " << count << " second steps container " << containerNameInNS);
618     while (CORBA::is_nil(ret) && count)
619     {
620 #ifndef WIN32
621       sleep( 1 ) ;
622 #else
623       Sleep(1000);
624 #endif
625       count--;
626       MESSAGE("[GiveContainer] step " << count << " Waiting for container on " << resource_selected);
627       CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
628       ret=Engines::Container::_narrow(obj);
629     }
630     if (CORBA::is_nil(ret))
631     {
632       INFOS("[GiveContainer] was not able to launch container " << containerNameInNS);
633     }
634     else
635     {
636       // Setting log file name
637       logFilename=":"+logFilename;
638       logFilename="@"+Kernel_Utils::GetHostname()+logFilename;
639       logFilename=user+logFilename;
640       ret->logfilename(logFilename.c_str());
641       RmTmpFile(_TmpFileName); // command file can be removed here
642       _TmpFileName="";
643     }
644   }
645   return ret;
646 }
647
648 //=============================================================================
649 //! Find a container given constraints (params) on a list of machines (possibleComputers)
650 /*!
651  *
652  */
653 //=============================================================================
654
655 Engines::Container_ptr
656 SALOME_ContainerManager::FindContainer(const Engines::ContainerParameters& params,
657                                        const Engines::ResourceList& possibleResources)
658 {
659   MESSAGE("[FindContainer] FindContainer on " << possibleResources.length() << " resources");
660   for(unsigned int i=0; i < possibleResources.length();i++)
661     {
662       Engines::Container_ptr cont = FindContainer(params, possibleResources[i].in());
663       if(!CORBA::is_nil(cont))
664         return cont;
665     }
666   MESSAGE("[FindContainer] no container found");
667   return Engines::Container::_nil();
668 }
669
670 //=============================================================================
671 //! Find a container given constraints (params) on a machine (theMachine)
672 /*!
673  *
674  */
675 //=============================================================================
676
677 Engines::Container_ptr
678 SALOME_ContainerManager::FindContainer(const Engines::ContainerParameters& params,
679                                        const std::string& resource)
680 {
681   Engines::ResourceDefinition_var resource_definition = _ResManager->GetResourceDefinition(resource.c_str());
682   std::string hostname(resource_definition->hostname.in());
683   std::string containerNameInNS(_NS->BuildContainerNameForNS(params, hostname.c_str()));
684   MESSAGE("[FindContainer] Try to find a container  " << containerNameInNS << " on resource " << resource);
685   CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
686   try
687   {
688     if(obj->_non_existent())
689       return Engines::Container::_nil();
690     else
691       return Engines::Container::_narrow(obj);
692   }
693   catch(const CORBA::Exception& e)
694   {
695     return Engines::Container::_nil();
696   }
697 }
698
699
700 bool isPythonContainer(const char* ContainerName);
701
702 //=============================================================================
703 /*!
704  *  This is no longer valid (C++ container are also python containers)
705  */ 
706 //=============================================================================
707 bool isPythonContainer(const char* ContainerName)
708 {
709   return false; // VSR 02/08/2013: Python containers are no more supported
710   bool ret = false;
711   int len = strlen(ContainerName);
712
713   if (len >= 2)
714     if (strcmp(ContainerName + len - 2, "Py") == 0)
715       ret = true;
716
717   return ret;
718 }
719
720 //=============================================================================
721 /*!
722  *  Builds the script to be launched
723  *
724  *  If SALOME Application not defined ($APPLI),
725  *  see BuildTempFileToLaunchRemoteContainer()
726  *
727  *  Else rely on distant configuration. Command is under the form (example):
728  *  ssh user@machine distantPath/runRemote.sh hostNS portNS WORKINGDIR workingdir \
729  *                   SALOME_Container containerName &"
730
731  *  - where user is ommited if not specified in CatalogResources,
732  *  - where distant path is always relative to user@machine $HOME, and
733  *    equal to $APPLI if not specified in CatalogResources,
734  *  - where hostNS is the hostname of CORBA naming server (set by scripts to
735  *    use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
736  *  - where portNS is the port used by CORBA naming server (set by scripts to
737  *    use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
738  *  - where workingdir is the requested working directory for the container.
739  *    If WORKINGDIR (and workingdir) is not present the working dir will be $HOME
740  */ 
741 //=============================================================================
742
743 std::string
744 SALOME_ContainerManager::BuildCommandToLaunchRemoteContainer
745 (const std::string& resource_name,
746  const Engines::ContainerParameters& params, const std::string& container_exe)
747 {
748
749   std::string command;
750   if (!_isAppliSalomeDefined)
751     command = BuildTempFileToLaunchRemoteContainer(resource_name, params);
752   else
753   {
754     int nbproc;
755     Engines::ResourceDefinition_var resource_definition = _ResManager->GetResourceDefinition(resource_name.c_str());
756     std::string hostname(resource_definition->hostname.in());
757     const ParserResourcesType& resInfo = _ResManager->GetImpl()->GetResourcesDescr(resource_name);
758
759     if (params.isMPI)
760     {
761       if ( params.nb_proc <= 0 )
762         nbproc = 1;
763       else
764         nbproc = params.nb_proc;
765     }
766
767     // "ssh -l user machine distantPath/runRemote.sh hostNS portNS WORKINGDIR workingdir \
768     //  SALOME_Container containerName &"
769     command = getCommandToRunRemoteProcess(resInfo.Protocol, resInfo.HostName, resInfo.UserName);
770
771     if (resInfo.AppliPath != "")
772       command += resInfo.AppliPath; // path relative to user@machine $HOME
773     else
774     {
775       ASSERT(getenv("APPLI"));
776       command += getenv("APPLI"); // path relative to user@machine $HOME
777     }
778
779     command += "/runRemote.sh ";
780
781     ASSERT(getenv("NSHOST")); 
782     command += getenv("NSHOST"); // hostname of CORBA name server
783
784     command += " ";
785     ASSERT(getenv("NSPORT"));
786     command += getenv("NSPORT"); // port of CORBA name server
787
788     std::string wdir = params.workingdir.in();
789     if(wdir != "")
790     {
791       command += " WORKINGDIR ";
792       command += " '";
793       if(wdir == "$TEMPDIR")
794         wdir="\\$TEMPDIR";
795       command += wdir; // requested working directory
796       command += "'"; 
797     }
798
799     if(params.isMPI)
800     {
801       command += " mpirun -np ";
802       std::ostringstream o;
803       o << nbproc << " ";
804       command += o.str();
805 #ifdef WITHLAM
806       command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
807 #elif defined(WITHOPENMPI)
808       if( getenv("OMPI_URI_FILE") == NULL )
809         command += "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace";
810       else{
811         command += "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace -ompi-server file:";
812         command += getenv("OMPI_URI_FILE");
813       }
814 #elif defined(WITHMPICH)
815       command += "-nameserver " + Kernel_Utils::GetHostname();
816 #endif        
817       command += " SALOME_MPIContainer ";
818     }
819     else
820       command += " " +container_exe+ " ";
821
822     command += _NS->ContainerName(params);
823     command += " -";
824     AddOmninamesParams(command);
825
826     MESSAGE("command =" << command);
827   }
828
829   return command;
830 }
831
832 //=============================================================================
833 /*!
834  *  builds the command to be launched.
835  */ 
836 //=============================================================================
837 std::string
838 SALOME_ContainerManager::BuildCommandToLaunchLocalContainer
839 (const Engines::ContainerParameters& params, const std::string& machinesFile, const std::string& container_exe)
840 {
841   _TmpFileName = BuildTemporaryFileName();
842   std::string command;
843   int nbproc = 0;
844
845   std::ostringstream o;
846
847   if (params.isMPI)
848     {
849       o << "mpirun -np ";
850
851       if ( params.nb_proc <= 0 )
852         nbproc = 1;
853       else
854         nbproc = params.nb_proc;
855
856       o << nbproc << " ";
857
858       if( getenv("LIBBATCH_NODEFILE") != NULL )
859         o << "-machinefile " << machinesFile << " ";
860
861 #ifdef WITHLAM
862       o << "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
863 #elif defined(WITHOPENMPI)
864       if( getenv("OMPI_URI_FILE") == NULL )
865         o << "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace";
866       else
867         {
868           o << "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace -ompi-server file:";
869           o << getenv("OMPI_URI_FILE");
870         }
871 #elif defined(WITHMPICH)
872       o << "-nameserver " + Kernel_Utils::GetHostname();
873 #endif
874
875       if (isPythonContainer(params.container_name))
876         o << " pyMPI SALOME_ContainerPy.py ";
877       else
878         o << " SALOME_MPIContainer ";
879     }
880
881   else
882     {
883       std::string wdir=params.workingdir.in();
884       if(wdir != "")
885         {
886           // a working directory is requested
887           if(wdir == "$TEMPDIR")
888             {
889               // a new temporary directory is requested
890               std::string dir = Kernel_Utils::GetTmpDir();
891 #ifdef WIN32
892               o << "cd /d " << dir << std::endl;
893 #else
894               o << "cd " << dir << ";";
895 #endif
896
897             }
898           else
899             {
900               // a permanent directory is requested use it or create it
901 #ifdef WIN32
902               o << "mkdir " + wdir << std::endl;
903               o << "cd /D " + wdir << std::endl;
904 #else
905               o << "mkdir -p " << wdir << " && cd " << wdir + ";";
906 #endif
907             }
908         }
909
910       if (isPythonContainer(params.container_name))
911         o << "SALOME_ContainerPy.py ";
912       else
913         o << container_exe + " ";
914
915     }
916
917   o << _NS->ContainerName(params);
918   o << " -";
919   AddOmninamesParams(o);
920
921   std::ofstream command_file( _TmpFileName.c_str() );
922   command_file << o.str();
923   command_file.close();
924
925 #ifndef WIN32
926   chmod(_TmpFileName.c_str(), 0x1ED);
927 #endif
928   command = _TmpFileName;
929
930   MESSAGE("Command is file ... " << command);
931   MESSAGE("Command is ... " << o.str());
932   return command;
933 }
934
935
936 //=============================================================================
937 /*!
938  *  removes the generated temporary file in case of a remote launch.
939  */ 
940 //=============================================================================
941
942 void SALOME_ContainerManager::RmTmpFile(std::string& tmpFileName)
943 {
944   int lenght = tmpFileName.size();
945   if ( lenght  > 0)
946     {
947 #ifdef WIN32
948       std::string command = "del /F ";
949 #else
950       std::string command = "rm ";      
951 #endif
952       if ( lenght > 4 )
953         command += tmpFileName.substr(0, lenght - 3 );
954       else
955         command += tmpFileName;
956       command += '*';
957       system(command.c_str());
958       //if dir is empty - remove it
959       std::string tmp_dir = Kernel_Utils::GetDirByPath( tmpFileName );
960       if ( Kernel_Utils::IsEmptyDir( tmp_dir ) )
961         {
962 #ifdef WIN32
963           command = "del /F " + tmp_dir;
964 #else
965           command = "rmdir " + tmp_dir;
966 #endif
967           system(command.c_str());
968         }
969     }
970 }
971
972 //=============================================================================
973 /*!
974  *   add to command all options relative to naming service.
975  */ 
976 //=============================================================================
977
978 void SALOME_ContainerManager::AddOmninamesParams(std::string& command) const
979 {
980   CORBA::String_var iorstr = _NS->getIORaddr();
981   command += "ORBInitRef NameService=";
982   command += iorstr;
983 }
984
985 //=============================================================================
986 /*!
987  *  add to command all options relative to naming service.
988  */ 
989 //=============================================================================
990
991 void SALOME_ContainerManager::AddOmninamesParams(std::ofstream& fileStream) const
992 {
993   CORBA::String_var iorstr = _NS->getIORaddr();
994   fileStream << "ORBInitRef NameService=";
995   fileStream << iorstr;
996 }
997
998 //=============================================================================
999 /*!
1000  *  add to command all options relative to naming service.
1001  */ 
1002 //=============================================================================
1003
1004 void SALOME_ContainerManager::AddOmninamesParams(std::ostringstream& oss) const
1005 {
1006   CORBA::String_var iorstr = _NS->getIORaddr();
1007   oss << "ORBInitRef NameService=";
1008   oss << iorstr;
1009 }
1010
1011 //=============================================================================
1012 /*!
1013  *  generate a file name in /tmp directory
1014  */ 
1015 //=============================================================================
1016
1017 std::string SALOME_ContainerManager::BuildTemporaryFileName() const
1018 {
1019   //build more complex file name to support multiple salome session
1020   std::string aFileName = Kernel_Utils::GetTmpFileName();
1021 #ifndef WIN32
1022   aFileName += ".sh";
1023 #else
1024   aFileName += ".bat";
1025 #endif
1026   return aFileName;
1027 }
1028
1029 //=============================================================================
1030 /*!
1031  *  Builds in a temporary file the script to be launched.
1032  *  
1033  *  Used if SALOME Application ($APPLI) is not defined.
1034  *  The command is build with data from CatalogResources, in which every path
1035  *  used on remote computer must be defined.
1036  */ 
1037 //=============================================================================
1038
1039 std::string
1040 SALOME_ContainerManager::BuildTempFileToLaunchRemoteContainer
1041 (const std::string& resource_name,
1042  const Engines::ContainerParameters& params) throw(SALOME_Exception)
1043 {
1044   int status;
1045
1046   _TmpFileName = BuildTemporaryFileName();
1047   std::ofstream tempOutputFile;
1048   tempOutputFile.open(_TmpFileName.c_str(), std::ofstream::out );
1049   const ParserResourcesType& resInfo = _ResManager->GetImpl()->GetResourcesDescr(resource_name);
1050   tempOutputFile << "#! /bin/sh" << std::endl;
1051
1052   // --- set env vars
1053
1054   tempOutputFile << "export SALOME_trace=local" << std::endl; // mkr : 27.11.2006 : PAL13967 - Distributed supervision graphs - Problem with "SALOME_trace"
1055   //tempOutputFile << "source " << resInfo.PreReqFilePath << endl;
1056
1057   // ! env vars
1058
1059   if (params.isMPI)
1060     {
1061       tempOutputFile << "mpirun -np ";
1062       int nbproc;
1063
1064       if ( params.nb_proc <= 0 )
1065         nbproc = 1;
1066       else
1067         nbproc = params.nb_proc;
1068
1069       std::ostringstream o;
1070
1071       tempOutputFile << nbproc << " ";
1072 #ifdef WITHLAM
1073       tempOutputFile << "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
1074 #elif defined(WITHOPENMPI)
1075       if( getenv("OMPI_URI_FILE") == NULL )
1076         tempOutputFile << "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace";
1077       else{
1078         tempOutputFile << "-x PATH -x LD_LIBRARY_PATH -x OMNIORB_CONFIG -x SALOME_trace -ompi-server file:";
1079         tempOutputFile << getenv("OMPI_URI_FILE");
1080       }
1081 #elif defined(WITHMPICH)
1082       tempOutputFile << "-nameserver " + Kernel_Utils::GetHostname();
1083 #endif
1084     }
1085
1086   tempOutputFile << getenv("KERNEL_ROOT_DIR") << "/bin/salome/";
1087
1088   if (params.isMPI)
1089     {
1090       if (isPythonContainer(params.container_name))
1091         tempOutputFile << " pyMPI SALOME_ContainerPy.py ";
1092       else
1093         tempOutputFile << " SALOME_MPIContainer ";
1094     }
1095
1096   else
1097     {
1098       if (isPythonContainer(params.container_name))
1099         tempOutputFile << "SALOME_ContainerPy.py ";
1100       else
1101         tempOutputFile << "SALOME_Container ";
1102     }
1103
1104   tempOutputFile << _NS->ContainerName(params) << " -";
1105   AddOmninamesParams(tempOutputFile);
1106   tempOutputFile << " &" << std::endl;
1107   tempOutputFile.flush();
1108   tempOutputFile.close();
1109 #ifndef WIN32
1110   chmod(_TmpFileName.c_str(), 0x1ED);
1111 #endif
1112
1113   // --- Build command
1114
1115   std::string command;
1116
1117   if (resInfo.Protocol == rsh)
1118     {
1119       command = "rsh ";
1120       std::string commandRcp = "rcp ";
1121       commandRcp += _TmpFileName;
1122       commandRcp += " ";
1123       commandRcp += resInfo.HostName;
1124       commandRcp += ":";
1125       commandRcp += _TmpFileName;
1126       status = system(commandRcp.c_str());
1127     }
1128
1129   else if (resInfo.Protocol == ssh)
1130     {
1131       command = "ssh ";
1132       std::string commandRcp = "scp ";
1133       commandRcp += _TmpFileName;
1134       commandRcp += " ";
1135       commandRcp += resInfo.HostName;
1136       commandRcp += ":";
1137       commandRcp += _TmpFileName;
1138       status = system(commandRcp.c_str());
1139     }
1140
1141   else if (resInfo.Protocol == srun)
1142     {
1143       command = "srun -n 1 -N 1 --share --nodelist=";
1144       std::string commandRcp = "rcp ";
1145       commandRcp += _TmpFileName;
1146       commandRcp += " ";
1147       commandRcp += resInfo.HostName;
1148       commandRcp += ":";
1149       commandRcp += _TmpFileName;
1150       status = system(commandRcp.c_str());
1151     }
1152   else
1153     throw SALOME_Exception("Unknown protocol");
1154
1155   if(status)
1156     throw SALOME_Exception("Error of connection on remote host");    
1157
1158   command += resInfo.HostName;
1159   _CommandForRemAccess = command;
1160   command += " ";
1161   command += _TmpFileName;
1162
1163   SCRUTE(command);
1164
1165   return command;
1166
1167 }
1168
1169 std::string SALOME_ContainerManager::GetMPIZeroNode(const std::string machine, const std::string machinesFile)
1170 {
1171   int status;
1172   std::string zeronode;
1173   std::string command;
1174   std::string tmpFile = BuildTemporaryFileName();
1175
1176   if( getenv("LIBBATCH_NODEFILE") == NULL )
1177     {
1178       if (_isAppliSalomeDefined)
1179         {
1180           const ParserResourcesType& resInfo = _ResManager->GetImpl()->GetResourcesDescr(machine);
1181
1182           if (resInfo.Protocol == rsh)
1183             command = "rsh ";
1184           else if (resInfo.Protocol == ssh)
1185             command = "ssh ";
1186           else if (resInfo.Protocol == srun)
1187             command = "srun -n 1 -N 1 --share --nodelist=";
1188           else
1189             throw SALOME_Exception("Unknown protocol");
1190
1191           if (resInfo.UserName != "")
1192             {
1193               command += "-l ";
1194               command += resInfo.UserName;
1195               command += " ";
1196             }
1197
1198           command += resInfo.HostName;
1199           command += " ";
1200
1201           if (resInfo.AppliPath != "")
1202             command += resInfo.AppliPath; // path relative to user@machine $HOME
1203           else
1204             {
1205               ASSERT(getenv("APPLI"));
1206               command += getenv("APPLI"); // path relative to user@machine $HOME
1207             }
1208
1209           command += "/runRemote.sh ";
1210
1211           ASSERT(getenv("NSHOST")); 
1212           command += getenv("NSHOST"); // hostname of CORBA name server
1213
1214           command += " ";
1215           ASSERT(getenv("NSPORT"));
1216           command += getenv("NSPORT"); // port of CORBA name server
1217
1218           command += " mpirun -np 1 hostname -s > " + tmpFile;
1219         }
1220       else
1221         command = "mpirun -np 1 hostname -s > " + tmpFile;
1222     }
1223   else
1224     command = "mpirun -np 1 -machinefile " + machinesFile + " hostname -s > " + tmpFile;
1225
1226   status = system(command.c_str());
1227   if( status == 0 ){
1228     std::ifstream fp(tmpFile.c_str(),std::ios::in);
1229     while(fp >> zeronode);
1230   }
1231
1232   RmTmpFile(tmpFile);
1233
1234   return zeronode;
1235 }
1236
1237 std::string SALOME_ContainerManager::machinesFile(const int nbproc)
1238 {
1239   std::string tmp;
1240   std::string nodesFile = getenv("LIBBATCH_NODEFILE");
1241   std::string machinesFile = Kernel_Utils::GetTmpFileName();
1242   std::ifstream fpi(nodesFile.c_str(),std::ios::in);
1243   std::ofstream fpo(machinesFile.c_str(),std::ios::out);
1244
1245   _numInstanceMutex.lock();
1246
1247   for(int i=0;i<_nbprocUsed;i++)
1248     fpi >> tmp;
1249
1250   for(int i=0;i<nbproc;i++)
1251     if( fpi >> tmp )
1252       fpo << tmp << std::endl;
1253     else
1254       throw SALOME_Exception("You need more processors than batch session have allocated for you! Unable to launch the mpi container: ");
1255
1256   _nbprocUsed += nbproc;
1257   fpi.close();
1258   fpo.close();
1259
1260   _numInstanceMutex.unlock();
1261
1262   return machinesFile;
1263
1264 }
1265
1266 std::set<pid_t> SALOME_ContainerManager::getpidofprogram(const std::string program)
1267 {
1268   std::set<pid_t> thepids;
1269   std::string tmpFile = Kernel_Utils::GetTmpFileName();
1270   std::string cmd;
1271   std::string thepid;
1272   cmd = "pidof " + program + " > " + tmpFile;
1273   system(cmd.c_str());
1274   std::ifstream fpi(tmpFile.c_str(),std::ios::in);
1275   while(fpi >> thepid){
1276     thepids.insert(atoi(thepid.c_str()));
1277   }
1278   return thepids;
1279 }
1280
1281 std::string SALOME_ContainerManager::getCommandToRunRemoteProcess(AccessProtocolType protocol,
1282                                                                   const std::string & hostname,
1283                                                                   const std::string & username)
1284 {
1285   std::ostringstream command;
1286   switch (protocol)
1287   {
1288   case rsh:
1289     command << "rsh ";
1290     if (username != "")
1291     {
1292       command << "-l " << username << " ";
1293     }
1294     command << hostname << " ";
1295     break;
1296   case ssh:
1297     command << "ssh ";
1298     if (username != "")
1299     {
1300       command << "-l " << username << " ";
1301     }
1302     command << hostname << " ";
1303     break;
1304   case srun:
1305     // no need to redefine the user with srun, the job user is taken by default
1306     // (note: for srun, user id can be specified with " --uid=<user>")
1307     command << "srun -n 1 -N 1 --share --nodelist=" << hostname << " ";
1308     break;
1309   case pbsdsh:
1310     command << "pbsdsh -o -h " << hostname << " ";
1311     break;
1312   case blaunch:
1313     command << "blaunch -no-shell " << hostname << " ";
1314     break;
1315   default:
1316     throw SALOME_Exception("Unknown protocol");
1317   }
1318
1319   return command.str();
1320 }
1321
1322 bool 
1323 SALOME_ContainerManager::checkPaCOParameters(Engines::ContainerParameters & params, std::string resource_selected)
1324 {
1325   bool result = true;
1326  
1327   // Step 1 : check ContainerParameters
1328   // Check container_name, has to be defined
1329   if (std::string(params.container_name.in()) == "")
1330   {
1331     INFOS("[checkPaCOParameters] You must define a container_name to launch a PaCO++ container");
1332     result = false;
1333   }
1334   // Check parallelLib
1335   std::string parallelLib = params.parallelLib.in();
1336   if (parallelLib != "Mpi" && parallelLib != "Dummy")
1337   {
1338     INFOS("[checkPaCOParameters] parallelLib is not correctly defined");
1339     INFOS("[checkPaCOParameters] you can chosse between: Mpi and Dummy");
1340     INFOS("[checkPaCOParameters] you entered: " << parallelLib);
1341     result = false;
1342   }
1343   // Check nb_proc
1344   if (params.nb_proc <= 0)
1345   {
1346     INFOS("[checkPaCOParameters] You must define a nb_proc > 0");
1347     result = false;
1348   }
1349
1350   // Step 2 : check resource_selected
1351   Engines::ResourceDefinition_var resource_definition = _ResManager->GetResourceDefinition(resource_selected.c_str());
1352   std::string protocol = resource_definition->protocol.in();
1353   std::string username = resource_definition->username.in();
1354   std::string applipath = resource_definition->applipath.in();
1355
1356   if (protocol == "" || username == "" || applipath == "")
1357   {
1358     INFOS("[checkPaCOParameters] resource selected is not well defined");
1359     INFOS("[checkPaCOParameters] resource name: " << resource_definition->name.in());
1360     INFOS("[checkPaCOParameters] resource hostname: " << resource_definition->hostname.in());
1361     INFOS("[checkPaCOParameters] resource protocol: " << protocol);
1362     INFOS("[checkPaCOParameters] resource username: " << username);
1363     INFOS("[checkPaCOParameters] resource applipath: " << applipath);
1364     result = false;
1365   }
1366
1367   return result;
1368 }
1369 #ifdef WITH_PACO_PARALLEL
1370
1371 //=============================================================================
1372 /*! CORBA Method:
1373  *  Start a suitable PaCO++ Parallel Container in a list of machines.
1374  *  \param params           Container Parameters required for the container
1375  *  \return CORBA container reference.
1376  */
1377 //=============================================================================
1378 Engines::Container_ptr
1379 SALOME_ContainerManager::StartPaCOPPContainer(const Engines::ContainerParameters& params_const,
1380                                               std::string resource_selected)
1381 {
1382   CORBA::Object_var obj;
1383   PaCO::InterfaceManager_var container_proxy;
1384   Engines::Container_ptr ret = Engines::Container::_nil();
1385   Engines::ContainerParameters params(params_const);
1386   params.resource_params.name = CORBA::string_dup(resource_selected.c_str());
1387
1388   // Step 0 : Check parameters
1389   if (!checkPaCOParameters(params, resource_selected))
1390   {
1391     INFOS("[StartPaCOPPContainer] check parameters failed ! see logs...");
1392     return ret;
1393   }
1394
1395   // Step 1 : Starting a new parallel container !
1396   INFOS("[StartPaCOPPContainer] Starting a PaCO++ parallel container");
1397   INFOS("[StartPaCOPPContainer] on resource : " << resource_selected);
1398
1399   // Step 2 : Get a MachineFile for the parallel container
1400   std::string machine_file_name = _ResManager->getMachineFile(resource_selected, 
1401                                                               params.nb_proc,
1402                                                               params.parallelLib.in());
1403
1404   if (machine_file_name == "")
1405   {
1406     INFOS("[StartPaCOPPContainer] Machine file generation failed");
1407     return ret;
1408   }
1409
1410   // Step 3 : starting parallel container proxy
1411   std::string command_proxy("");
1412   std::string proxy_machine;
1413   try 
1414   {
1415     command_proxy = BuildCommandToLaunchPaCOProxyContainer(params, machine_file_name, proxy_machine);
1416   }
1417   catch(const SALOME_Exception & ex)
1418   {
1419     INFOS("[StartPaCOPPContainer] Exception in BuildCommandToLaunchPaCOContainer");
1420     INFOS(ex.what());
1421     return ret;
1422   }
1423   obj = LaunchPaCOProxyContainer(command_proxy, params, proxy_machine);
1424   if (CORBA::is_nil(obj))
1425   {
1426     INFOS("[StartPaCOPPContainer] LaunchPaCOContainer for proxy returns NIL !");
1427     return ret;
1428   }
1429   container_proxy = PaCO::InterfaceManager::_narrow(obj);
1430   MESSAGE("[StartPaCOPPContainer] PaCO container proxy is launched");
1431
1432   // Step 4 : starting parallel container nodes
1433   std::string command_nodes("");
1434   SALOME_ContainerManager::actual_launch_machine_t nodes_machines;
1435   try 
1436   {
1437     command_nodes = BuildCommandToLaunchPaCONodeContainer(params, machine_file_name, nodes_machines, proxy_machine);
1438   }
1439   catch(const SALOME_Exception & ex)
1440   {
1441     INFOS("[StarPaCOPPContainer] Exception in BuildCommandToLaunchPaCONodeContainer");
1442     INFOS(ex.what());
1443     return ret;
1444   }
1445
1446   std::string container_generic_node_name = std::string(params.container_name.in()) + std::string("Node");
1447   bool result = LaunchPaCONodeContainer(command_nodes, params, container_generic_node_name, nodes_machines);
1448   if (!result)
1449   {
1450     INFOS("[StarPaCOPPContainer] LaunchPaCONodeContainer failed !");
1451     // Il faut tuer le proxy
1452     try 
1453     {
1454       Engines::Container_var proxy = Engines::Container::_narrow(container_proxy);
1455       proxy->Shutdown();
1456     }
1457     catch (...)
1458     {
1459       INFOS("[StarPaCOPPContainer] Exception catched from proxy Shutdown...");
1460     }
1461     return ret;
1462   }
1463
1464   // Step 4 : connecting nodes and the proxy to actually create a parallel container
1465   for (int i = 0; i < params.nb_proc; i++) 
1466   {
1467     std::ostringstream tmp;
1468     tmp << i;
1469     std::string proc_number = tmp.str();
1470     std::string container_node_name = container_generic_node_name + proc_number;
1471
1472     std::string theNodeMachine(nodes_machines[i]);
1473     std::string containerNameInNS = _NS->BuildContainerNameForNS(container_node_name.c_str(), theNodeMachine.c_str());
1474     obj = _NS->Resolve(containerNameInNS.c_str());
1475     if (CORBA::is_nil(obj)) 
1476     {
1477       INFOS("[StarPaCOPPContainer] CONNECTION FAILED From Naming Service !");
1478       INFOS("[StarPaCOPPContainer] Container name is " << containerNameInNS);
1479       return ret;
1480     }
1481     try
1482     {
1483       MESSAGE("[StarPaCOPPContainer] Deploying node : " << container_node_name);
1484       PaCO::InterfaceParallel_var node = PaCO::InterfaceParallel::_narrow(obj);
1485       node->deploy();
1486       MESSAGE("[StarPaCOPPContainer] node " << container_node_name << " is deployed");
1487     }
1488     catch(CORBA::SystemException& e)
1489     {
1490       INFOS("[StarPaCOPPContainer] Exception in deploying node : " << containerNameInNS);
1491       INFOS("CORBA::SystemException : " << e);
1492       return ret;
1493     }
1494     catch(CORBA::Exception& e)
1495     {
1496       INFOS("[StarPaCOPPContainer] Exception in deploying node : " << containerNameInNS);
1497       INFOS("CORBA::Exception" << e);
1498       return ret;
1499     }
1500     catch(...)
1501     {
1502       INFOS("[StarPaCOPPContainer] Exception in deploying node : " << containerNameInNS);
1503       INFOS("Unknown exception !");
1504       return ret;
1505     }
1506   }
1507
1508   // Step 5 : starting parallel container
1509   try 
1510   {
1511     MESSAGE ("[StarPaCOPPContainer] Starting parallel object");
1512     container_proxy->start();
1513     MESSAGE ("[StarPaCOPPContainer] Parallel object is started");
1514     ret = Engines::Container::_narrow(container_proxy);
1515   }
1516   catch(CORBA::SystemException& e)
1517   {
1518     INFOS("Caught CORBA::SystemException. : " << e);
1519   }
1520   catch(PortableServer::POA::ServantAlreadyActive&)
1521   {
1522     INFOS("Caught CORBA::ServantAlreadyActiveException");
1523   }
1524   catch(CORBA::Exception&)
1525   {
1526     INFOS("Caught CORBA::Exception.");
1527   }
1528   catch(std::exception& exc)
1529   {
1530     INFOS("Caught std::exception - "<<exc.what()); 
1531   }
1532   catch(...)
1533   {
1534     INFOS("Caught unknown exception.");
1535   }
1536   return ret;
1537 }
1538
1539 std::string 
1540 SALOME_ContainerManager::BuildCommandToLaunchPaCOProxyContainer(const Engines::ContainerParameters& params,
1541                                                                 std::string machine_file_name,
1542                                                                 std::string & proxy_hostname)
1543 {
1544   // In the proxy case, we always launch a Dummy Proxy
1545   std::string exe_name = "SALOME_ParallelContainerProxyDummy";
1546   std::string container_name = params.container_name.in();
1547
1548   // Convert nb_proc in string
1549   std::ostringstream tmp_string;
1550   tmp_string << params.nb_proc;
1551   std::string nb_proc_str = tmp_string.str();
1552
1553   // Get resource definition
1554   Engines::ResourceDefinition_var resource_definition = 
1555     _ResManager->GetResourceDefinition(params.resource_params.name);
1556
1557   // Choose hostname
1558   std::string hostname;
1559   std::ifstream machine_file(machine_file_name.c_str());
1560   std::getline(machine_file, hostname, ' ');
1561   size_t found = hostname.find('\n');
1562   if (found!=std::string::npos)
1563     hostname.erase(found, 1); // Remove \n
1564   proxy_hostname = hostname;
1565   MESSAGE("[BuildCommandToLaunchPaCOProxyContainer] machine file name extracted is " << hostname);
1566
1567   // Remote execution
1568   bool remote_execution = false;
1569   if (hostname != std::string(Kernel_Utils::GetHostname()))
1570   {
1571     MESSAGE("[BuildCommandToLaunchPaCOProxyContainer] remote machine case detected !");
1572     remote_execution = true;
1573   }
1574   
1575   // Log environnement
1576   std::string log_type("");
1577   char * get_val = getenv("PARALLEL_LOG");
1578   if (get_val)
1579     log_type = get_val;
1580
1581   // Generating the command
1582   std::string command_begin("");
1583   std::string command_end("");
1584   std::ostringstream command;
1585
1586   LogConfiguration(log_type, "proxy", container_name, hostname, command_begin, command_end);
1587   command << command_begin;
1588
1589   // Adding connection command
1590   // We can only have a remote execution with
1591   // a SALOME application
1592   if (remote_execution)
1593   {
1594     ASSERT(getenv("NSHOST")); 
1595     ASSERT(getenv("NSPORT"));
1596
1597     command << resource_definition->protocol.in();
1598     command << " -l ";
1599     command << resource_definition->username.in();
1600     command << " " << hostname;
1601     command << " " << resource_definition->applipath.in();
1602     command << "/runRemote.sh ";
1603     command << getenv("NSHOST") << " "; // hostname of CORBA name server
1604     command << getenv("NSPORT") << " "; // port of CORBA name server
1605   }
1606
1607   command << exe_name;
1608   command << " " << container_name;
1609   command << " Dummy";
1610   command << " " << hostname;
1611   command << " " << nb_proc_str;
1612   command << " -";
1613   AddOmninamesParams(command);
1614
1615   // Final command
1616   command << command_end;
1617   MESSAGE("[BuildCommandToLaunchPaCOProxyContainer] Command is: " << command.str());
1618
1619   return command.str();
1620 }
1621
1622 std::string 
1623 SALOME_ContainerManager::BuildCommandToLaunchPaCONodeContainer(const Engines::ContainerParameters& params,
1624                                                                const std::string & machine_file_name,
1625                                                                SALOME_ContainerManager::actual_launch_machine_t & vect_machine,
1626                                                                const std::string & proxy_hostname)
1627 {
1628   // Name of exe
1629   std::string exe_name = "SALOME_ParallelContainerNode";
1630   exe_name += params.parallelLib.in();
1631   std::string container_name = params.container_name.in();
1632
1633   // Convert nb_proc in string
1634   std::ostringstream nb_proc_stream;
1635   nb_proc_stream << params.nb_proc;
1636
1637   // Get resource definition
1638   Engines::ResourceDefinition_var resource_definition = 
1639     _ResManager->GetResourceDefinition(params.resource_params.name);
1640   
1641   // Log environnement
1642   std::string log_type("");
1643   char * get_val = getenv("PARALLEL_LOG");
1644   if (get_val)
1645     log_type = get_val;
1646
1647   // Now the command is different according to paralleLib
1648   std::ostringstream command_nodes;
1649   std::ifstream machine_file(machine_file_name.c_str());
1650   if (std::string(params.parallelLib.in()) == "Dummy")
1651   {
1652     for (int i= 0; i < params.nb_proc; i++)
1653     {
1654       // Choose hostname
1655       std::string hostname;
1656       std::getline(machine_file, hostname);
1657       MESSAGE("[BuildCommandToLaunchPaCONodeContainer] machine file name extracted is " << hostname);
1658
1659       // Remote execution
1660       bool remote_execution = false;
1661       if (hostname != std::string(Kernel_Utils::GetHostname()))
1662       {
1663         MESSAGE("[BuildCommandToLaunchPaCONodeContainer] remote machine case detected !");
1664         remote_execution = true;
1665       }
1666
1667       // For each node we have a new command
1668       // Generating the command
1669       std::ostringstream command_node_stream;
1670       std::string command_node_begin("");
1671       std::string command_node_end("");
1672       std::ostringstream node_number;
1673       node_number << i;
1674       std::string container_node_name = container_name + node_number.str();
1675       LogConfiguration(log_type, "node", container_node_name, hostname, command_node_begin, command_node_end);
1676
1677       // Adding connection command
1678       // We can only have a remote execution with
1679       // a SALOME application
1680       if (remote_execution)
1681       {
1682         ASSERT(getenv("NSHOST")); 
1683         ASSERT(getenv("NSPORT"));
1684
1685         command_node_stream << resource_definition->protocol.in();
1686         command_node_stream << " -l ";
1687         command_node_stream << resource_definition->username.in();
1688         command_node_stream << " " << hostname;
1689         command_node_stream << " " << resource_definition->applipath.in();
1690         command_node_stream << "/runRemote.sh ";
1691         command_node_stream << getenv("NSHOST") << " "; // hostname of CORBA name server
1692         command_node_stream << getenv("NSPORT") << " "; // port of CORBA name server
1693       }
1694
1695       command_node_stream << exe_name;
1696       command_node_stream << " " << container_name;
1697       command_node_stream << " " << params.parallelLib.in();
1698       command_node_stream << " " << proxy_hostname;
1699       command_node_stream << " " << node_number.str();
1700       command_node_stream << " -";
1701       AddOmninamesParams(command_node_stream);
1702
1703       command_nodes << command_node_begin << command_node_stream.str() << command_node_end;
1704       vect_machine.push_back(hostname);
1705     }
1706   }
1707
1708   else if (std::string(params.parallelLib.in()) == "Mpi")
1709   {
1710     // Choose hostname
1711     std::string hostname;
1712     std::getline(machine_file, hostname, ' ');
1713     MESSAGE("[BuildCommandToLaunchPaCONodeContainer] machine file name extracted is " << hostname);
1714
1715     // Remote execution
1716     bool remote_execution = false;
1717     if (hostname != std::string(Kernel_Utils::GetHostname()))
1718     {
1719       MESSAGE("[BuildCommandToLaunchPaCONodeContainer] remote machine case detected !");
1720       remote_execution = true;
1721     }
1722
1723     // In case of Mpi and Remote, we copy machine_file in the applipath
1724     // scp mpi_machine_file user@machine:Path
1725     std::ostringstream command_remote_stream;
1726     std::string::size_type last = machine_file_name.find_last_of("/");
1727     if (last == std::string::npos)
1728       last = -1;
1729
1730     std::string protocol = resource_definition->protocol.in();
1731     if (protocol == "rsh")
1732       command_remote_stream << "rcp ";
1733     else 
1734       command_remote_stream << "scp ";
1735     command_remote_stream << machine_file_name << " ";
1736     command_remote_stream << resource_definition->username.in() << "@";
1737     command_remote_stream << hostname << ":" << resource_definition->applipath.in();
1738     command_remote_stream <<  "/" << machine_file_name.substr(last+1);
1739
1740     int status = system(command_remote_stream.str().c_str());
1741     if (status == -1)
1742     {
1743       INFOS("copy of the MPI machine file failed ! - sorry !");
1744       return "";
1745     }
1746
1747     // Generating the command
1748     std::string command_begin("");
1749     std::string command_end("");
1750
1751     LogConfiguration(log_type, "nodes", container_name, hostname, command_begin, command_end);
1752     command_nodes << command_begin;
1753
1754     // Adding connection command
1755     // We can only have a remote execution with
1756     // a SALOME application
1757     if (remote_execution)
1758     {
1759       ASSERT(getenv("NSHOST")); 
1760       ASSERT(getenv("NSPORT"));
1761
1762       command_nodes << resource_definition->protocol.in();
1763       command_nodes << " -l ";
1764       command_nodes << resource_definition->username.in();
1765       command_nodes << " " << hostname;
1766       command_nodes << " " << resource_definition->applipath.in();
1767       command_nodes << "/runRemote.sh ";
1768       command_nodes << getenv("NSHOST") << " "; // hostname of CORBA name server
1769       command_nodes << getenv("NSPORT") << " "; // port of CORBA name server
1770     }
1771
1772     if (std::string(resource_definition->mpiImpl.in()) == "lam")
1773     {
1774       command_nodes << "mpiexec -ssi boot ";
1775       command_nodes << "-machinefile "  << machine_file_name << " "; 
1776       command_nodes <<  "-n " << params.nb_proc;
1777     }
1778     else
1779     {
1780       command_nodes << "mpirun -np " << params.nb_proc;
1781     }
1782     command_nodes << " " << exe_name;
1783     command_nodes << " " << container_name;
1784     command_nodes << " " << params.parallelLib.in();
1785     command_nodes << " " << proxy_hostname;
1786     command_nodes << " -";
1787     AddOmninamesParams(command_nodes);
1788
1789     // We don't put hostname, because nodes are registered in the resource of the proxy
1790     for (int i= 0; i < params.nb_proc; i++)
1791       vect_machine.push_back(proxy_hostname); 
1792
1793     command_nodes << command_end;
1794   }
1795   return command_nodes.str();
1796 }
1797
1798 void
1799 SALOME_ContainerManager::LogConfiguration(const std::string & log_type,
1800                                           const std::string & exe_type,
1801                                           const std::string & container_name,
1802                                           const std::string & hostname,
1803                                           std::string & begin, 
1804                                           std::string & end)
1805 {
1806   if(log_type == "xterm")
1807   {
1808     begin = "xterm -e \"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; export PATH=$PATH;";
1809     end   = "\"&";
1810   }
1811   else if(log_type == "xterm_debug")
1812   {
1813     begin = "xterm -e \"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; export PATH=$PATH;";
1814     end   = "; cat \" &";
1815   }
1816   else
1817   {
1818     // default into a file...
1819     std::string logFilename = "/tmp/" + container_name + "_" + hostname + "_" + exe_type + "_";
1820     logFilename += std::string(getenv("USER")) + ".log";
1821     end = " > " + logFilename + " 2>&1 & ";
1822   }
1823 }
1824
1825 CORBA::Object_ptr 
1826 SALOME_ContainerManager::LaunchPaCOProxyContainer(const std::string& command, 
1827                                                   const Engines::ContainerParameters& params,
1828                                                   const std::string & hostname)
1829 {
1830   PaCO::InterfaceManager_ptr container_proxy = PaCO::InterfaceManager::_nil();
1831
1832   MESSAGE("[LaunchPaCOProxyContainer] Launch command");
1833   int status = system(command.c_str());
1834   if (status == -1) {
1835     INFOS("[LaunchPaCOProxyContainer] failed : system command status -1");
1836     return container_proxy;
1837   }
1838   else if (status == 217) {
1839     INFOS("[LaunchPaCOProxyContainer] failed : system command status 217");
1840     return container_proxy;
1841   }
1842
1843   int count = TIME_OUT_TO_LAUNCH_CONT;
1844   CORBA::Object_var obj = CORBA::Object::_nil();
1845   std::string containerNameInNS = _NS->BuildContainerNameForNS(params.container_name.in(), 
1846                                                                hostname.c_str());
1847   MESSAGE("[LaunchParallelContainer]  Waiting for Parallel Container proxy : " << containerNameInNS);
1848
1849   while (CORBA::is_nil(obj) && count) 
1850   {
1851     sleep(1);
1852     count--;
1853     obj = _NS->Resolve(containerNameInNS.c_str());
1854   }
1855
1856   try 
1857   {
1858     container_proxy = PaCO::InterfaceManager::_narrow(obj);
1859   }
1860   catch(CORBA::SystemException& e)
1861   {
1862     INFOS("[StarPaCOPPContainer] Exception in _narrow after LaunchParallelContainer for proxy !");
1863     INFOS("CORBA::SystemException : " << e);
1864     return container_proxy;
1865   }
1866   catch(CORBA::Exception& e)
1867   {
1868     INFOS("[StarPaCOPPContainer] Exception in _narrow after LaunchParallelContainer for proxy !");
1869     INFOS("CORBA::Exception" << e);
1870     return container_proxy;
1871   }
1872   catch(...)
1873   {
1874     INFOS("[StarPaCOPPContainer] Exception in _narrow after LaunchParallelContainer for proxy !");
1875     INFOS("Unknown exception !");
1876     return container_proxy;
1877   }
1878   if (CORBA::is_nil(container_proxy))
1879   {
1880     INFOS("[StarPaCOPPContainer] PaCO::InterfaceManager::_narrow returns NIL !");
1881     return container_proxy;
1882   }
1883   return obj._retn();
1884 }
1885
1886 //=============================================================================
1887 /*! This method launches the parallel container.
1888  *  It will may be placed on the ressources manager.
1889  *
1890  * \param command to launch
1891  * \param container's parameters
1892  * \param name of the container
1893  *
1894  * \return CORBA container reference
1895  */
1896 //=============================================================================
1897 bool
1898 SALOME_ContainerManager::LaunchPaCONodeContainer(const std::string& command, 
1899                                                  const Engines::ContainerParameters& params,
1900                                                  const std::string& name,
1901                                                  SALOME_ContainerManager::actual_launch_machine_t & vect_machine)
1902 {
1903   INFOS("[LaunchPaCONodeContainer] Launch command");
1904   int status = system(command.c_str());
1905   if (status == -1) {
1906     INFOS("[LaunchPaCONodeContainer] failed : system command status -1");
1907     return false;
1908   }
1909   else if (status == 217) {
1910     INFOS("[LaunchPaCONodeContainer] failed : system command status 217");
1911     return false;
1912   }
1913
1914   INFOS("[LaunchPaCONodeContainer] Waiting for the nodes of the parallel container");
1915   // We are waiting all the nodes
1916   for (int i = 0; i < params.nb_proc; i++) 
1917   {
1918     CORBA::Object_var obj = CORBA::Object::_nil();
1919     std::string theMachine(vect_machine[i]);
1920     // Name of the node
1921     std::ostringstream tmp;
1922     tmp << i;
1923     std::string proc_number = tmp.str();
1924     std::string container_node_name = name + proc_number;
1925     std::string containerNameInNS = _NS->BuildContainerNameForNS((char*) container_node_name.c_str(), theMachine.c_str());
1926     INFOS("[LaunchPaCONodeContainer]  Waiting for Parallel Container node " << containerNameInNS << " on " << theMachine);
1927     int count = TIME_OUT_TO_LAUNCH_CONT;
1928     while (CORBA::is_nil(obj) && count) {
1929       sleep(1) ;
1930       count-- ;
1931       obj = _NS->Resolve(containerNameInNS.c_str());
1932     }
1933     if (CORBA::is_nil(obj))
1934     {
1935       INFOS("[LaunchPaCONodeContainer] Launch of node failed (or not found) !");
1936       return false;
1937     }
1938   }
1939   return true;
1940 }
1941
1942 #else
1943
1944 Engines::Container_ptr
1945 SALOME_ContainerManager::StartPaCOPPContainer(const Engines::ContainerParameters& params,
1946                                               std::string resource_selected)
1947 {
1948   Engines::Container_ptr ret = Engines::Container::_nil();
1949   INFOS("[StarPaCOPPContainer] is disabled !");
1950   INFOS("[StarPaCOPPContainer] recompile SALOME Kernel to enable PaCO++ parallel extension");
1951   return ret;
1952 }
1953
1954 std::string 
1955 SALOME_ContainerManager::BuildCommandToLaunchPaCOProxyContainer(const Engines::ContainerParameters& params,
1956                                                                 std::string machine_file_name,
1957                                                                 std::string & proxy_hostname)
1958 {
1959   return "";
1960 }
1961
1962 std::string 
1963 SALOME_ContainerManager::BuildCommandToLaunchPaCONodeContainer(const Engines::ContainerParameters& params,
1964                                                                const std::string & machine_file_name,
1965                                                                SALOME_ContainerManager::actual_launch_machine_t & vect_machine, 
1966                                                                const std::string & proxy_hostname) 
1967 {
1968   return "";
1969 }
1970 void 
1971 SALOME_ContainerManager::LogConfiguration(const std::string & log_type,
1972                                           const std::string & exe_type,
1973                                           const std::string & container_name,
1974                                           const std::string & hostname,
1975                                           std::string & begin, 
1976                                           std::string & end)
1977 {
1978 }
1979
1980 CORBA::Object_ptr 
1981 SALOME_ContainerManager::LaunchPaCOProxyContainer(const std::string& command, 
1982                                                   const Engines::ContainerParameters& params,
1983                                                   const std::string& hostname)
1984 {
1985   CORBA::Object_ptr ret = CORBA::Object::_nil();
1986   return ret;
1987 }
1988
1989 bool 
1990 SALOME_ContainerManager::LaunchPaCONodeContainer(const std::string& command, 
1991                         const Engines::ContainerParameters& params,
1992                         const std::string& name,
1993                         SALOME_ContainerManager::actual_launch_machine_t & vect_machine)
1994 {
1995   return false;
1996 }
1997 #endif
1998