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