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