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