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