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