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