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