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