Salome HOME
CCAR: add traces to CALCIUM ports, some debug in ModuleCatalog
[modules/kernel.git] / src / Container / SALOME_ContainerManager.cxx
1 // Copyright (C) 2005  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 // 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either 
7 // version 2.1 of the License.
8 // 
9 // This library is distributed in the hope that it will be useful 
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 // Lesser General Public License for more details.
13 //
14 // You should have received a copy of the GNU Lesser General Public  
15 // License along with this library; if not, write to the Free Software 
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20 #include "SALOME_ContainerManager.hxx"
21 #include "SALOME_NamingService.hxx"
22 #include "SALOME_ModuleCatalog.hh"
23 #include "OpUtil.hxx"
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #ifndef WNT
27 #include <unistd.h>
28 #endif
29 #include <vector>
30 #include "Utils_CorbaException.hxx"
31 #include "Batch_Date.hxx"
32
33 #ifdef WITH_PACO_PARALLEL
34 #include "PaCO++.h"
35 #endif
36
37 #define TIME_OUT_TO_LAUNCH_CONT 21
38
39 using namespace std;
40
41 vector<Engines::Container_ptr> SALOME_ContainerManager::_batchLaunchedContainers;
42
43 vector<Engines::Container_ptr>::iterator SALOME_ContainerManager::_batchLaunchedContainersIter;
44
45 const char *SALOME_ContainerManager::_ContainerManagerNameInNS = 
46   "/ContainerManager";
47
48 //=============================================================================
49 /*! 
50  *  Constructor
51  *  \param orb
52  *  Define a CORBA single thread policy for the server, which avoid to deal
53  *  with non thread-safe usage like Change_Directory in SALOME naming service
54  */
55 //=============================================================================
56
57 SALOME_ContainerManager::SALOME_ContainerManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa, SALOME_ResourcesManager *rm, SALOME_NamingService *ns)
58 {
59   MESSAGE("constructor");
60   _NS = ns;
61   _ResManager = rm;
62   _id=0;
63
64   PortableServer::POAManager_var pman = poa->the_POAManager();
65   _orb = CORBA::ORB::_duplicate(orb) ;
66   CORBA::PolicyList policies;
67   policies.length(1);
68   PortableServer::ThreadPolicy_var threadPol = 
69     poa->create_thread_policy(PortableServer::SINGLE_THREAD_MODEL);
70   policies[0] = PortableServer::ThreadPolicy::_duplicate(threadPol);
71
72   _poa = poa->create_POA("SThreadPOA",pman,policies);
73   threadPol->destroy();
74   PortableServer::ObjectId_var id = _poa->activate_object(this);
75   CORBA::Object_var obj = _poa->id_to_reference(id);
76   Engines::ContainerManager_var refContMan =
77     Engines::ContainerManager::_narrow(obj);
78
79   _NS->Register(refContMan,_ContainerManagerNameInNS);
80   _MpiStarted = false;
81   _isAppliSalomeDefined = (getenv("APPLI") != 0);
82   MESSAGE("constructor end");
83 }
84
85 //=============================================================================
86 /*! 
87  * destructor
88  */
89 //=============================================================================
90
91 SALOME_ContainerManager::~SALOME_ContainerManager()
92 {
93   MESSAGE("destructor");
94 }
95
96 //=============================================================================
97 /*! CORBA method:
98  *  shutdown all the containers, then the ContainerManager servant
99  */
100 //=============================================================================
101
102 void SALOME_ContainerManager::Shutdown()
103 {
104   MESSAGE("Shutdown");
105   ShutdownContainers();
106   _NS->Destroy_Name(_ContainerManagerNameInNS);
107   PortableServer::ObjectId_var oid = _poa->servant_to_id(this);
108   _poa->deactivate_object(oid);
109   //_remove_ref() has already been done at creation
110   //_remove_ref();
111 }
112
113 //=============================================================================
114 /*! CORBA Method:
115  *  Loop on all the containers listed in naming service, ask shutdown on each
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       SCRUTE((*iter));
129       CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
130       Engines::Container_var cont=Engines::Container::_narrow(obj);
131       if(!CORBA::is_nil(cont)){
132         lstCont.push_back((*iter));
133       }
134     }
135     MESSAGE("Container list: ");
136     for(list<string>::iterator iter=lstCont.begin();iter!=lstCont.end();iter++){
137       SCRUTE((*iter));
138     }
139     for(list<string>::iterator iter=lstCont.begin();iter!=lstCont.end();iter++){
140       SCRUTE((*iter));
141       CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
142       Engines::Container_var cont=Engines::Container::_narrow(obj);
143       if(!CORBA::is_nil(cont))
144         {
145           MESSAGE("ShutdownContainers: " << (*iter));
146           try
147             {
148               cont->Shutdown();
149             }
150           catch(CORBA::SystemException& e)
151             {
152               INFOS("CORBA::SystemException ignored : " << e);
153             }
154           catch(CORBA::Exception&)
155             {
156               INFOS("CORBA::Exception ignored.");
157             }
158           catch(...)
159             {
160               INFOS("Unknown exception ignored.");
161             }
162         }
163       else 
164         MESSAGE("ShutdownContainers: no container ref for " << (*iter));
165     }
166   }
167 }
168
169 //=============================================================================
170 /*! CORBA Method:
171  *  Find a suitable Container in a list of machines, or start one
172  *  \param params            Machine Parameters required for the container
173  *  \param possibleComputers list of machines usable for find or start
174  */
175 //=============================================================================
176
177 Engines::Container_ptr
178 SALOME_ContainerManager::
179 FindOrStartContainer(const Engines::MachineParameters& params,
180                      const Engines::MachineList& possibleComputers)
181 {
182   Engines::Container_ptr ret = FindContainer(params,possibleComputers);
183   if(!CORBA::is_nil(ret))
184     return ret;
185   MESSAGE("Container doesn't exist try to launch it ...");
186
187   return StartContainer(params,possibleComputers,Engines::P_FIRST);
188
189 }
190
191 //=============================================================================
192 /*! CORBA Method:
193  *  Start a suitable Container in a list of machines
194  *  \param params            Machine Parameters required for the container
195  *  \param possibleComputers list of machines usable for start
196  */
197 //=============================================================================
198
199 Engines::Container_ptr
200 SALOME_ContainerManager::
201 StartContainer(const Engines::MachineParameters& params,
202                const Engines::MachineList& possibleComputers,
203                Engines::ResPolicy policy,const std::string& container_exe)
204 {
205 #ifdef WITH_PACO_PARALLEL
206   std::string parallelLib(params.parallelLib);
207   if (parallelLib != "")
208     return FindOrStartParallelContainer(params, possibleComputers);
209 #endif
210   long id;
211   string containerNameInNS;
212   char idc[3*sizeof(long)];
213   Engines::Container_ptr ret = Engines::Container::_nil();
214
215   MESSAGE("SALOME_ContainerManager::StartContainer " <<
216           possibleComputers.length());
217
218   vector<string> lm;
219   for(int i=0;i<possibleComputers.length();i++)
220     lm.push_back(string(possibleComputers[i]));
221
222   string theMachine;
223   try{
224     switch(policy){
225     case Engines::P_FIRST:
226       theMachine=_ResManager->GetImpl()->FindFirst(lm);
227       break;
228     case Engines::P_CYCL:
229       theMachine=_ResManager->GetImpl()->FindNext(lm);
230       break;
231     case Engines::P_BEST:
232       theMachine=_ResManager->GetImpl()->FindBest(lm);
233       break;
234     }
235   }
236   catch( const SALOME_Exception &ex ){
237     MESSAGE(ex.what());
238     return Engines::Container::_nil();
239   }
240
241   //If the machine name is localhost use the real name
242   if(theMachine == "localhost")
243     theMachine=GetHostname();
244
245   MESSAGE("try to launch it on " << theMachine);
246
247   // Get Id for container: a parallel container registers in Naming Service
248   // on the machine where is process 0. ContainerManager does'nt know the name
249   // of this machine before the launch of the parallel container. So to get
250   // the IOR of the parallel container in Naming Service, ContainerManager
251   // gives a unique Id. The parallel container registers his name under
252   // /ContainerManager/Id directory in NamingService
253
254   id = GetIdForContainer();
255
256   string command;
257   if(theMachine==""){
258     MESSAGE("SALOME_ContainerManager::StartContainer : " <<
259             "no possible computer");
260     return Engines::Container::_nil();
261   }
262   else if(theMachine==GetHostname())
263     command = BuildCommandToLaunchLocalContainer(params,id,container_exe);
264   else
265     command = BuildCommandToLaunchRemoteContainer(theMachine,params,id,container_exe);
266
267   RmTmpFile();
268
269   //check if an entry exists in Naming service
270   if(params.isMPI)
271     {
272       containerNameInNS = "/ContainerManager/id";
273       sprintf(idc,"%ld",id);
274       containerNameInNS += idc;
275     }
276   else
277     containerNameInNS = _NS->BuildContainerNameForNS(params,theMachine.c_str());
278
279   SCRUTE(containerNameInNS);
280   CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
281   if ( !CORBA::is_nil(obj) )
282     {
283       // unregister the registered container if it exists
284       _NS->Destroy_Name(containerNameInNS.c_str());
285       // unregister component instances ???
286       //Engines::Container_var cont=Engines::Container::_narrow(obj);
287     }
288
289   //redirect stdout and stderr in a file
290   string logFilename="/tmp/"+_NS->ContainerName(params)+"_"+ theMachine +"_"+getenv( "USER" )+".log" ;
291   command += " > " + logFilename + " 2>&1 &";
292
293   // launch container with a system call
294   int status=system(command.c_str());
295   if (status == -1){
296     MESSAGE("SALOME_LifeCycleCORBA::StartOrFindContainer rsh failed " <<
297             "(system command status -1)");
298     return Engines::Container::_nil();
299   }
300   else if (status == 217){
301     MESSAGE("SALOME_LifeCycleCORBA::StartOrFindContainer rsh failed " <<
302             "(system command status 217)");
303     return Engines::Container::_nil();
304   }
305   else{
306     int count=TIME_OUT_TO_LAUNCH_CONT;
307     MESSAGE("count = "<<count);
308     while ( CORBA::is_nil(ret) && count ){
309 #ifndef WNT
310       sleep( 1 ) ;
311 #else
312       Sleep(1000);
313 #endif
314       count-- ;
315       if ( count != 10 )
316         MESSAGE( count << ". Waiting for container on " << theMachine);
317
318       CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
319       ret=Engines::Container::_narrow(obj);
320     }
321     
322     if ( CORBA::is_nil(ret) )
323       {
324         MESSAGE("SALOME_LifeCycleCORBA::StartOrFindContainer rsh failed");
325       }
326     else
327       {
328         logFilename=":"+logFilename;
329         logFilename="@"+GetHostname()+logFilename;
330         logFilename=getenv( "USER" )+logFilename;
331         ret->logfilename(logFilename.c_str());
332       }
333
334     return ret;
335   }
336 }
337
338 //=============================================================================
339 /*! CORBA Method:
340  *  Start a suitable Container in a list of machines
341  *  \param params            Machine Parameters required for the container
342  *  \param possibleComputers list of machines usable for start
343  */
344 //=============================================================================
345
346 Engines::Container_ptr
347 SALOME_ContainerManager::
348 StartContainer(const Engines::MachineParameters& params,
349                Engines::ResPolicy policy,
350                const Engines::CompoList& componentList)
351 {
352   Engines::MachineList_var possibleComputers = _ResManager->GetFittingResources(params,componentList);
353
354   // Look into ModulCatalog if a specific container must be launched
355   CORBA::String_var container_exe;
356   int found=0;
357   try
358     {
359       CORBA::Object_var obj = _NS->Resolve("/Kernel/ModulCatalog");
360       SALOME_ModuleCatalog::ModuleCatalog_var Catalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj) ;
361       if (CORBA::is_nil (Catalog))
362         return Engines::Container::_nil();
363       // Loop through component list
364       for(int i=0;i<componentList.length();i++)
365         {
366           const char* compoi = componentList[i];
367           SALOME_ModuleCatalog::Acomponent_var compoInfo = Catalog->GetComponent(compoi);
368           if (CORBA::is_nil (compoInfo))
369             {
370               INFOS("ContainerManager Error: Component not found in the catalog" );
371               INFOS( compoi );
372               return Engines::Container::_nil();
373             }
374           SALOME_ModuleCatalog::ImplType impl=compoInfo->implementation_type();
375           container_exe=compoInfo->implementation_name();
376           if(impl==SALOME_ModuleCatalog::CEXE)
377             {
378               if(found)
379                 {
380                   INFOS("ContainerManager Error: you can't have 2 CEXE component in the same container" );
381                   return Engines::Container::_nil();
382                 }
383               found=1;
384             }
385         }
386     }
387   catch (ServiceUnreachable&)
388     {
389       INFOS("Caught exception: Naming Service Unreachable");
390       return Engines::Container::_nil();
391     }
392   catch (...)
393     {
394       INFOS("Caught unknown exception.");
395       return Engines::Container::_nil();
396     }
397
398   if(found)
399     return StartContainer(params,possibleComputers,policy,container_exe.in());
400   else
401     return StartContainer(params,possibleComputers,policy);
402 }
403
404 #ifdef WITH_PACO_PARALLEL
405 //=============================================================================
406 /*! CORBA Method:
407  *  Find or Start a suitable PaCO++ Parallel Container in a list of machines.
408  *  \param params            Machine Parameters required for the container
409  *  \param possibleComputers list of machines usable for find or start
410  *
411  *  \return CORBA container reference.
412  */
413 //=============================================================================
414 Engines::Container_ptr
415 SALOME_ContainerManager::
416 FindOrStartParallelContainer(const Engines::MachineParameters& params_const,
417                              const Engines::MachineList& possibleComputers)
418 {
419   CORBA::Object_var obj;
420   PaCO::InterfaceManager_var proxy;
421   Engines::Container_ptr ret = Engines::Container::_nil();
422   Engines::MachineParameters params(params_const);
423
424   // Step 1 : Try to find a suitable container
425   // Currently not as good as could be since
426   // we have to verified the number of nodes of the container
427   // if a user tell that.
428   ret = FindContainer(params, possibleComputers);
429
430   if(CORBA::is_nil(ret)) {
431     // Step 2 : Starting a new parallel container
432     INFOS("[FindOrStartParallelContainer] Starting a parallel container");
433
434     // Step 2.1 : Choose a computer
435     string theMachine = _ResManager->FindFirst(possibleComputers);
436     if(theMachine == "") {
437       INFOS("[FindOrStartParallelContainer] !!!!!!!!!!!!!!!!!!!!!!!!!!");
438       INFOS("[FindOrStartParallelContainer] No possible computer found");
439       INFOS("[FindOrStartParallelContainer] !!!!!!!!!!!!!!!!!!!!!!!!!!");
440     }
441     else {
442       INFOS("[FindOrStartParallelContainer] on machine : " << theMachine);
443       string command;
444       if(theMachine == GetHostname()) {
445         // Step 3 : starting parallel container proxy
446         params.hostname = CORBA::string_dup(theMachine.c_str());
447         Engines::MachineParameters params_proxy(params);
448         try {
449           command = BuildCommandToLaunchLocalParallelContainer("SALOME_ParallelContainerProxy", params_proxy, "xterm");
450         }
451         catch(const SALOME_Exception & ex){
452           MESSAGE(ex.what());
453           return Engines::Container::_nil();
454         }
455         // LaunchParallelContainer uses this value to know if it launches the proxy or the nodes
456         params_proxy.nb_component_nodes = 0;
457         obj = LaunchParallelContainer(command, params_proxy, _NS->ContainerName(params));
458         ret = Engines::Container::_narrow(obj);
459         proxy = PaCO::InterfaceManager::_narrow(obj);
460
461         // Step 4 : starting parallel container nodes
462         command = BuildCommandToLaunchLocalParallelContainer("SALOME_ParallelContainerNode", params, "xterm");
463         string name = _NS->ContainerName(params) + "Node";
464         LaunchParallelContainer(command, params, name);
465         // Step 5 : connecting nodes and the proxy to actually create a parallel container
466         try {
467           for (int i = 0; i < params.nb_component_nodes; i++) {
468
469             char buffer [5];
470 #ifndef WNT
471             snprintf(buffer,5,"%d",i);
472 #else
473             _snprintf(buffer,5,"%d",i);
474 #endif
475             string name_cont = name + string(buffer);
476
477             string theNodeMachine(CORBA::string_dup(params.hostname));
478             string containerNameInNS = _NS->BuildContainerNameForNS(name_cont.c_str(),theNodeMachine.c_str());
479             int count = TIME_OUT_TO_LAUNCH_CONT;
480             obj = _NS->Resolve(containerNameInNS.c_str());
481             while (CORBA::is_nil(obj) && count) {
482               INFOS("[FindOrStartParallelContainer] CONNECTION FAILED !!!!!!!!!!!!!!!!!!!!!!!!");
483 #ifndef WNT
484               sleep(1) ;
485 #else
486               Sleep(1000);
487 #endif
488               count-- ;
489               obj = _NS->Resolve(containerNameInNS.c_str());
490             }
491
492             PaCO::InterfaceParallel_var node = PaCO::InterfaceParallel::_narrow(obj);
493             MESSAGE("[FindOrStartParallelContainer] Deploying node : " << name);
494             node->deploy();
495           }
496           proxy->start();
497         }
498         catch(CORBA::SystemException& e)
499         {
500           INFOS("Caught CORBA::SystemException. : " << e);
501         }
502         catch(PortableServer::POA::ServantAlreadyActive&)
503         {
504           INFOS("Caught CORBA::ServantAlreadyActiveException");
505         }
506         catch(CORBA::Exception&)
507         {
508           INFOS("Caught CORBA::Exception.");
509         }
510         catch(std::exception& exc)
511         {
512           INFOS("Caught std::exception - "<<exc.what()); 
513         }
514         catch(...)
515         {
516           INFOS("Caught unknown exception.");
517         }
518         INFOS("[FindOrStartParallelContainer] node " << name << " deployed");
519       }
520       else {
521         INFOS("[FindOrStartParallelContainer] Currently parallel containers are launched only on the local host");
522       }
523     }
524 }
525 return ret;
526 }
527 #else
528 //=============================================================================
529 /*! CORBA Method:
530  *  Find or Start a suitable PaCO++ Parallel Container in a list of machines.
531  *  \param params            Machine Parameters required for the container
532  *  \param possibleComputers list of machines usable for find or start
533  *
534  *  \return CORBA container reference.
535  */
536 //=============================================================================
537 Engines::Container_ptr
538 SALOME_ContainerManager::
539 FindOrStartParallelContainer(const Engines::MachineParameters& params,
540                              const Engines::MachineList& possibleComputers)
541 {
542   Engines::Container_ptr ret = Engines::Container::_nil();
543   INFOS("[FindOrStartParallelContainer] is disabled !");
544   INFOS("[FindOrStartParallelContainer] recompile SALOME Kernel to enable parallel extension");
545   return ret;
546 }
547 #endif
548
549 //=============================================================================
550 /*! CORBA Method:
551  *  Give a suitable Container in a list of machines
552  *  \param params            Machine Parameters required for the container
553  *  \param possibleComputers list of machines usable for start
554  */
555 //=============================================================================
556
557 Engines::Container_ptr
558 SALOME_ContainerManager::
559 GiveContainer(const Engines::MachineParameters& params,
560                Engines::ResPolicy policy,
561                const Engines::CompoList& componentList)
562 {
563   char *valenv=getenv("SALOME_BATCH");
564   if(valenv)
565     if (strcmp(valenv,"1")==0)
566       {
567         if(_batchLaunchedContainers.empty())
568           fillBatchLaunchedContainers();
569
570         if (_batchLaunchedContainersIter == _batchLaunchedContainers.end())
571           _batchLaunchedContainersIter = _batchLaunchedContainers.begin();
572
573         Engines::Container_ptr rtn = Engines::Container::_duplicate(*_batchLaunchedContainersIter);
574         _batchLaunchedContainersIter++;
575         return rtn;
576       }
577   return StartContainer(params,policy,componentList);
578 }
579
580 //=============================================================================
581 /*! 
582  * 
583  */
584 //=============================================================================
585
586 Engines::Container_ptr
587 SALOME_ContainerManager::
588 FindContainer(const Engines::MachineParameters& params,
589               const char *theMachine)
590 {
591   string containerNameInNS(_NS->BuildContainerNameForNS(params,theMachine));
592   CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
593   if( !CORBA::is_nil(obj) )
594     return Engines::Container::_narrow(obj);
595   else
596     return Engines::Container::_nil();
597 }
598
599 //=============================================================================
600 /*! 
601  * 
602  */
603 //=============================================================================
604
605 Engines::Container_ptr
606 SALOME_ContainerManager::
607 FindContainer(const Engines::MachineParameters& params,
608               const Engines::MachineList& possibleComputers)
609 {
610   MESSAGE("FindContainer "<<possibleComputers.length());
611   for(unsigned int i=0;i<possibleComputers.length();i++)
612     {
613       MESSAGE("FindContainer possible " << possibleComputers[i]);
614       Engines::Container_ptr cont = FindContainer(params,possibleComputers[i]);
615       if( !CORBA::is_nil(cont) )
616         return cont;
617     }
618   MESSAGE("FindContainer: not found");
619   return Engines::Container::_nil();
620 }
621
622 //=============================================================================
623 /*! This method launches the parallel container.
624  *  It will may be placed on the ressources manager.
625  *
626  * \param command to launch
627  * \param container's parameters
628  * \param name of the container
629  *
630  * \return CORBA container reference
631  */
632 //=============================================================================
633 CORBA::Object_ptr 
634 SALOME_ContainerManager::LaunchParallelContainer(const std::string& command, 
635                                                  const Engines::MachineParameters& params,
636                                                  const std::string& name)
637 {
638   CORBA::Object_ptr obj = CORBA::Object::_nil();
639   string containerNameInNS;
640   MESSAGE("[LaunchParallelContainer] : command to launch...");
641   MESSAGE(command);
642   if (params.nb_component_nodes == 0) {
643     INFOS("[LaunchParallelContainer] launching the proxy of the parallel container");
644     int status = system(command.c_str());
645     if (status == -1) {
646       INFOS("[LaunchParallelContainer] failed : system command status -1");
647     }
648     else if (status == 217) {
649       INFOS("[LaunchParallelContainer] failed : system command status 217");
650     }
651
652     int count = TIME_OUT_TO_LAUNCH_CONT;
653     string theMachine(CORBA::string_dup(params.hostname));
654     containerNameInNS = _NS->BuildContainerNameForNS((char*) name.c_str(),theMachine.c_str());
655
656     INFOS("[LaunchParallelContainer]  Waiting for Parallel Container proxy on " << theMachine);
657     while (CORBA::is_nil(obj) && count) {
658 #ifndef WNT
659       sleep(1) ;
660 #else
661       Sleep(1000);
662 #endif
663       count-- ;
664       obj = _NS->Resolve(containerNameInNS.c_str());
665     }
666   }
667   else {
668     INFOS("[LaunchParallelContainer] launching the nodes of the parallel container");
669     int status = system(command.c_str());
670     if (status == -1) {
671       INFOS("[LaunchParallelContainer] failed : system command status -1");
672     }
673     else if (status == 217) {
674       INFOS("[LaunchParallelContainer] failed : system command status 217");
675     }
676     // We are waiting all the nodes
677     for (int i = 0; i < params.nb_component_nodes; i++) {
678       obj = CORBA::Object::_nil();
679       int count = TIME_OUT_TO_LAUNCH_CONT;
680
681       // Name of the node
682       char buffer [5];
683 #ifndef WNT
684       snprintf(buffer,5,"%d",i);
685 #else
686       _snprintf(buffer,5,"%d",i);
687 #endif
688
689       string name_cont = name + string(buffer);
690
691       // I don't like this...
692       string theMachine(CORBA::string_dup(params.hostname));
693       containerNameInNS = _NS->BuildContainerNameForNS((char*) name_cont.c_str(),theMachine.c_str());
694       cerr << "[LaunchContainer]  Waiting for Parllel Container node " << containerNameInNS << " on " << theMachine << endl;
695       while (CORBA::is_nil(obj) && count) {
696 #ifndef WNT
697         sleep(1) ;
698 #else
699         Sleep(1000);
700 #endif
701         count-- ;
702         obj = _NS->Resolve(containerNameInNS.c_str());
703       }
704     }
705   }
706
707   if ( CORBA::is_nil(obj) ) {
708     INFOS("[LaunchParallelContainer] failed");
709   }
710   return obj;
711 }
712
713 //=============================================================================
714 /*! 
715  * Get Id for container: a parallel container registers in Naming Service
716  * on the machine where is process 0. ContainerManager does'nt know the name
717  * of this machine before the launch of the parallel container. So to get
718  * the IOR of the parallel container in Naming Service, ContainerManager
719  * gives a unique Id. The parallel container registers his name under
720  * /ContainerManager/Id directory in NamingService
721  */
722 //=============================================================================
723
724
725 long SALOME_ContainerManager::GetIdForContainer(void)
726 {
727   _id++;
728   return _id;
729 }
730
731 void SALOME_ContainerManager::fillBatchLaunchedContainers()
732 {
733   _batchLaunchedContainers.clear();
734   _NS->Change_Directory("/Containers");
735   vector<string> vec = _NS->list_directory_recurs();
736   for(vector<string>::iterator iter = vec.begin();iter!=vec.end();iter++){
737     CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
738     Engines::Container_ptr cont=Engines::Container::_narrow(obj);
739     if(!CORBA::is_nil(cont)){
740       _batchLaunchedContainers.push_back(cont);
741     }
742   }
743   _batchLaunchedContainersIter=_batchLaunchedContainers.begin();
744 }
745
746 //=============================================================================
747 /*!
748  *  This is no longer valid (C++ container are also python containers)
749  */ 
750 //=============================================================================
751
752 bool isPythonContainer(const char* ContainerName)
753 {
754   bool ret = false;
755   int len = strlen(ContainerName);
756
757   if (len >= 2)
758     if (strcmp(ContainerName + len - 2, "Py") == 0)
759       ret = true;
760
761   return ret;
762 }
763
764 //=============================================================================
765 /*!
766  *  Builds the script to be launched
767  *
768  *  If SALOME Application not defined ($APPLI),
769  *  see BuildTempFileToLaunchRemoteContainer()
770  *
771  *  Else rely on distant configuration. Command is under the form (example):
772  *  ssh user@machine distantPath/runRemote.sh hostNS portNS WORKINGDIR workingdir \
773  *                   SALOME_Container containerName &"
774
775  *  - where user is ommited if not specified in CatalogResources,
776  *  - where distant path is always relative to user@machine $HOME, and
777  *    equal to $APPLI if not specified in CatalogResources,
778  *  - where hostNS is the hostname of CORBA naming server (set by scripts to
779  *    use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
780  *  - where portNS is the port used by CORBA naming server (set by scripts to
781  *    use to launch SALOME and servers in $APPLI: runAppli.sh, runRemote.sh)
782  *  - where workingdir is the requested working directory for the container.
783  *    If WORKINGDIR (and workingdir) is not present the working dir will be $HOME
784  */ 
785 //=============================================================================
786
787 string
788 SALOME_ContainerManager::BuildCommandToLaunchRemoteContainer
789 (const string& machine,
790  const Engines::MachineParameters& params, const long id,const std::string& container_exe)
791 {
792   string command;
793   int nbproc;
794   char idc[3*sizeof(long)];
795           
796   if ( ! _isAppliSalomeDefined )
797     command = BuildTempFileToLaunchRemoteContainer(machine, params);
798
799   else
800     {
801       const ParserResourcesType& resInfo = _ResManager->GetImpl()->GetResourcesList(machine);
802
803       if (params.isMPI)
804         {
805           if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
806             nbproc = 1;
807           else if ( params.nb_node == 0 )
808             nbproc = params.nb_proc_per_node;
809           else if ( params.nb_proc_per_node == 0 )
810             nbproc = params.nb_node;
811           else
812             nbproc = params.nb_node * params.nb_proc_per_node;
813         }
814
815       // "ssh user@machine distantPath/runRemote.sh hostNS portNS WORKINGDIR workingdir \
816       //  SALOME_Container containerName &"
817
818       if (resInfo.Protocol == rsh)
819         command = "rsh ";
820       else if (resInfo.Protocol == ssh)
821         command = "ssh ";
822       else
823         throw SALOME_Exception("Unknown protocol");
824
825       if (resInfo.UserName != "")
826         {
827           command += resInfo.UserName;
828           command += "@";
829         }
830
831       command += machine;
832       command += " ";
833
834       if (resInfo.AppliPath != "")
835         command += resInfo.AppliPath; // path relative to user@machine $HOME
836       else
837         {
838           ASSERT(getenv("APPLI"));
839           command += getenv("APPLI"); // path relative to user@machine $HOME
840         }
841
842       command += "/runRemote.sh ";
843
844       ASSERT(getenv("NSHOST")); 
845       command += getenv("NSHOST"); // hostname of CORBA name server
846
847       command += " ";
848       ASSERT(getenv("NSPORT"));
849       command += getenv("NSPORT"); // port of CORBA name server
850
851       std::string wdir=params.workingdir.in();
852       if(wdir != "")
853         {
854           command += " WORKINGDIR ";
855           command += " '";
856           if(wdir == "$TEMPDIR")
857             wdir="\\$TEMPDIR";
858           command += wdir; // requested working directory
859           command += "'"; 
860         }
861
862       if(params.isMPI)
863         {
864           command += " mpirun -np ";
865           std::ostringstream o;
866           o << nbproc << " ";
867           command += o.str();
868 #ifdef WITHLAM
869           command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
870 #endif  
871           command += " SALOME_MPIContainer ";
872         }
873       else
874         command += " " +container_exe+ " ";
875
876       command += _NS->ContainerName(params);
877       command += " -id ";
878       sprintf(idc,"%ld",id);
879       command += idc;
880       command += " -";
881       AddOmninamesParams(command);
882
883       MESSAGE("command =" << command);
884     }
885
886   return command;
887 }
888
889 //=============================================================================
890 /*!
891  *  builds the command to be launched.
892  */ 
893 //=============================================================================
894
895 string
896 SALOME_ContainerManager::BuildCommandToLaunchLocalContainer
897 (const Engines::MachineParameters& params, const long id,const std::string& container_exe)
898 {
899   _TmpFileName = "";
900   string command;
901   int nbproc = 0;
902   char idc[3*sizeof(long)];
903
904   if (params.isMPI)
905     {
906       command = "mpirun -np ";
907
908       if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
909         nbproc = 1;
910       else if ( params.nb_node == 0 )
911         nbproc = params.nb_proc_per_node;
912       else if ( params.nb_proc_per_node == 0 )
913         nbproc = params.nb_node;
914       else
915         nbproc = params.nb_node * params.nb_proc_per_node;
916
917       std::ostringstream o;
918
919       o << nbproc << " ";
920
921       command += o.str();
922 #ifdef WITHLAM
923       command += "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
924 #endif
925
926       if (isPythonContainer(params.container_name))
927         command += "pyMPI SALOME_ContainerPy.py ";
928       else
929         command += "SALOME_MPIContainer ";
930     }
931
932   else
933     {
934       command="";
935       std::string wdir=params.workingdir.in();
936       if(wdir != "")
937         {
938           // a working directory is requested
939           if(wdir == "$TEMPDIR")
940             {
941               // a new temporary directory is requested
942               char dir[]="/tmp/salomeXXXXXX";
943               char* mdir=mkdtemp(dir);
944               if(mdir==NULL)
945                 std::cerr << "Problem in mkdtemp " << dir << " " << mdir << std::endl;
946               else
947                 command="cd "+std::string(dir)+";";
948             }
949           else
950             {
951               // a permanent directory is requested use it or create it
952               command="mkdir -p " + wdir + " && cd " + wdir + ";";
953             }
954         }
955       if (isPythonContainer(params.container_name))
956         command += "SALOME_ContainerPy.py ";
957       else
958         command += container_exe + " ";
959     }
960
961   command += _NS->ContainerName(params);
962   command += " -id ";
963   sprintf(idc,"%ld",id);
964   command += idc;
965   command += " -";
966   AddOmninamesParams(command);
967
968   MESSAGE("Command is ... " << command);
969   return command;
970 }
971
972
973 //=============================================================================
974 /*!
975  *  removes the generated temporary file in case of a remote launch.
976  */ 
977 //=============================================================================
978
979 void SALOME_ContainerManager::RmTmpFile()
980 {
981   if (_TmpFileName != "")
982     {
983 #ifndef WNT
984       string command = "rm ";
985 #else
986       string command = "del /F ";
987 #endif
988       command += _TmpFileName;
989       char *temp = strdup(command.c_str());
990       int lgthTemp = strlen(temp);
991       temp[lgthTemp - 3] = '*';
992       temp[lgthTemp - 2] = '\0';
993       system(temp);
994       free(temp);
995     }
996 }
997
998 //=============================================================================
999 /*!
1000  *   add to command all options relative to naming service.
1001  */ 
1002 //=============================================================================
1003
1004 void SALOME_ContainerManager::AddOmninamesParams(string& command) const
1005   {
1006     CORBA::String_var iorstr = _NS->getIORaddr();
1007     command += "ORBInitRef NameService=";
1008     command += iorstr;
1009   }
1010
1011
1012 //=============================================================================
1013 /*!
1014  *  add to command all options relative to naming service.
1015  */ 
1016 //=============================================================================
1017
1018 void SALOME_ContainerManager::AddOmninamesParams(ofstream& fileStream) const
1019   {
1020     CORBA::String_var iorstr = _NS->getIORaddr();
1021     fileStream << "ORBInitRef NameService=";
1022     fileStream << iorstr;
1023   }
1024
1025 //=============================================================================
1026 /*!
1027  *  generate a file name in /tmp directory
1028  */ 
1029 //=============================================================================
1030
1031 string SALOME_ContainerManager::BuildTemporaryFileName() const
1032   {
1033     //build more complex file name to support multiple salome session
1034     char *temp = new char[19];
1035     strcpy(temp, "/tmp/command");
1036     strcat(temp, "XXXXXX");
1037 #ifndef WNT
1038
1039     mkstemp(temp);
1040 #else
1041
1042     char aPID[80];
1043     itoa(getpid(), aPID, 10);
1044     strcat(temp, aPID);
1045 #endif
1046
1047     string command(temp);
1048     delete [] temp;
1049     command += ".sh";
1050     return command;
1051   }
1052
1053
1054 //=============================================================================
1055 /*!
1056  *  Builds in a temporary file the script to be launched.
1057  *  
1058  *  Used if SALOME Application ($APPLI) is not defined.
1059  *  The command is build with data from CatalogResources, in which every path
1060  *  used on remote computer must be defined.
1061  */ 
1062 //=============================================================================
1063
1064 string
1065 SALOME_ContainerManager::BuildTempFileToLaunchRemoteContainer
1066 (const string& machine,
1067  const Engines::MachineParameters& params) throw(SALOME_Exception)
1068 {
1069   int status;
1070
1071   _TmpFileName = BuildTemporaryFileName();
1072   ofstream tempOutputFile;
1073   tempOutputFile.open(_TmpFileName.c_str(), ofstream::out );
1074   const ParserResourcesType& resInfo = _ResManager->GetImpl()->GetResourcesList(machine);
1075   tempOutputFile << "#! /bin/sh" << endl;
1076
1077   // --- set env vars
1078
1079   tempOutputFile << "export SALOME_trace=local" << endl; // mkr : 27.11.2006 : PAL13967 - Distributed supervision graphs - Problem with "SALOME_trace"
1080   //tempOutputFile << "source " << resInfo.PreReqFilePath << endl;
1081
1082   // ! env vars
1083
1084   if (params.isMPI)
1085     {
1086       tempOutputFile << "mpirun -np ";
1087       int nbproc;
1088
1089       if ( (params.nb_node <= 0) && (params.nb_proc_per_node <= 0) )
1090         nbproc = 1;
1091       else if ( params.nb_node == 0 )
1092         nbproc = params.nb_proc_per_node;
1093       else if ( params.nb_proc_per_node == 0 )
1094         nbproc = params.nb_node;
1095       else
1096         nbproc = params.nb_node * params.nb_proc_per_node;
1097
1098       std::ostringstream o;
1099
1100       tempOutputFile << nbproc << " ";
1101 #ifdef WITHLAM
1102       tempOutputFile << "-x PATH,LD_LIBRARY_PATH,OMNIORB_CONFIG,SALOME_trace ";
1103 #endif
1104     }
1105
1106   tempOutputFile << getenv("KERNEL_ROOT_DIR") << "/bin/salome/";
1107
1108   if (params.isMPI)
1109     {
1110       if (isPythonContainer(params.container_name))
1111         tempOutputFile << "pyMPI SALOME_ContainerPy.py ";
1112       else
1113         tempOutputFile << "SALOME_MPIContainer ";
1114     }
1115
1116   else
1117     {
1118       if (isPythonContainer(params.container_name))
1119         tempOutputFile << "SALOME_ContainerPy.py ";
1120       else
1121         tempOutputFile << "SALOME_Container ";
1122     }
1123
1124   tempOutputFile << _NS->ContainerName(params) << " -";
1125   AddOmninamesParams(tempOutputFile);
1126   tempOutputFile << " &" << endl;
1127   tempOutputFile.flush();
1128   tempOutputFile.close();
1129   chmod(_TmpFileName.c_str(), 0x1ED);
1130
1131   // --- Build command
1132
1133   string command;
1134
1135   if (resInfo.Protocol == rsh)
1136     {
1137       command = "rsh ";
1138       string commandRcp = "rcp ";
1139       commandRcp += _TmpFileName;
1140       commandRcp += " ";
1141       commandRcp += machine;
1142       commandRcp += ":";
1143       commandRcp += _TmpFileName;
1144       status = system(commandRcp.c_str());
1145     }
1146
1147   else if (resInfo.Protocol == ssh)
1148     {
1149       command = "ssh ";
1150       string commandRcp = "scp ";
1151       commandRcp += _TmpFileName;
1152       commandRcp += " ";
1153       commandRcp += machine;
1154       commandRcp += ":";
1155       commandRcp += _TmpFileName;
1156       status = system(commandRcp.c_str());
1157     }
1158   else
1159     throw SALOME_Exception("Unknown protocol");
1160
1161   if(status)
1162     throw SALOME_Exception("Error of connection on remote host");    
1163
1164   command += machine;
1165   _CommandForRemAccess = command;
1166   command += " ";
1167   command += _TmpFileName;
1168
1169   SCRUTE(command);
1170
1171   return command;
1172
1173 }
1174
1175 //=============================================================================
1176 /*! Creates a command line that the container manager uses to launch
1177  * a parallel container.
1178  */ 
1179 //=============================================================================
1180 string 
1181 SALOME_ContainerManager::BuildCommandToLaunchLocalParallelContainer(const std::string& exe_name,
1182                                                                     const Engines::MachineParameters& params,
1183                                                                     const std::string& log)
1184 {
1185   // This method knows the differences between the proxy and the nodes.
1186   // nb_component_nodes is not used in the same way if it is a proxy or 
1187   // a node.
1188
1189   string command;
1190   string parallelLib(CORBA::string_dup(params.parallelLib));
1191   string hostname(CORBA::string_dup(params.hostname));
1192   int par = exe_name.find("Proxy");
1193   int nbproc = params.nb_component_nodes;
1194   char buffer [33];
1195   sprintf(buffer,"%d",nbproc);
1196
1197   Engines::MachineParameters_var rtn = new Engines::MachineParameters();
1198   rtn->container_name = params.container_name;
1199   rtn->hostname = params.hostname;
1200   rtn->OS = params.OS;
1201   rtn->mem_mb = params.mem_mb;
1202   rtn->cpu_clock = params.cpu_clock;
1203   rtn->nb_proc_per_node = params.nb_proc_per_node;
1204   rtn->nb_node = params.nb_node;
1205   rtn->isMPI = params.isMPI;
1206
1207   string real_exe_name  = exe_name + parallelLib;
1208
1209   if (parallelLib == "Dummy")
1210   {
1211     //command = "gdb --args ";
1212     //command = "valgrind --tool=memcheck --log-file=val_log ";
1213     //command += real_exe_name;
1214
1215     command = real_exe_name;
1216
1217     command += " " + _NS->ContainerName(rtn);
1218     command += " " + parallelLib;
1219     command += " " + hostname;
1220     command += " -";
1221     AddOmninamesParams(command);
1222   }
1223
1224   else if (parallelLib == "Mpi")
1225   {
1226     // Step 1 : check if MPI is started
1227     if (_MpiStarted == false)
1228     {
1229       startMPI();
1230     }
1231
1232     if (par < 0)
1233     {
1234       // Nodes case
1235
1236       command = "mpiexec -np " + string(buffer) + " ";
1237 //      command += "gdb --args ";
1238       command += real_exe_name;
1239       command += " " + _NS->ContainerName(rtn);
1240       command += " " + parallelLib;
1241       command += " " + hostname;
1242       command += " -";
1243       AddOmninamesParams(command);
1244     }
1245     else                                          
1246     {
1247       // Proxy case
1248       command = "mpiexec -np 1 ";
1249       command += real_exe_name;
1250       command += " " + _NS->ContainerName(rtn);
1251       command += " " + string(buffer);
1252       command += " " + parallelLib;
1253       command += " " + hostname;
1254       command += " -";
1255       AddOmninamesParams(command);
1256     }
1257   }
1258   else
1259   {
1260     std::string message("Unknown parallelLib" + parallelLib);
1261     throw SALOME_Exception(message.c_str());
1262   }
1263
1264   // log choice
1265   if (log == "default")
1266   {
1267     command += " > /tmp/";
1268     command += _NS->ContainerName(rtn);
1269     command += "_";
1270     command += GetHostname();
1271     command += "_";
1272     command += getenv( "USER" ) ;
1273     command += ".log 2>&1 &" ;
1274   }
1275   if (log == "xterm")
1276   {
1277     command = "/usr/X11R6/bin/xterm -e \"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; export PATH=$PATH;  " 
1278               + command + " \" &";
1279 //            + command + "; echo $LD_LIBRARY_PATH; cat \" &";
1280   }
1281   return command;
1282
1283 /*  if (log == "xterm")
1284   {
1285     command = "/usr/X11R6/bin/xterm -e \"export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; export PATH=$PATH; echo $LD_LIBRARY_PATH; echo $PATH; " + command + "; cat \" &";
1286   }
1287 */
1288 /*  command = "cd ; rm " + fichier_commande + "; touch " + \
1289              fichier_commande + "; echo \" export LD_LIBRARY_PATH=$LD_LIBRARY_PATH; " + \
1290              command + " >& /tmp/ribes_" + fichier_commande + " & \" > " + fichier_commande + ";";
1291   command += "ssh cn01 sh " + fichier_commande + " &";
1292   cerr << "La commande : " << command << endl;
1293 */
1294 }
1295
1296 void SALOME_ContainerManager::startMPI()
1297 {
1298   cerr << "----------------------------------------------" << endl;
1299   cerr << "----------------------------------------------" << endl;
1300   cerr << "----------------------------------------------" << endl;
1301   cerr << "-Only Lam on Localhost is currently supported-" << endl;
1302   cerr << "----------------------------------------------" << endl;
1303   cerr << "----------------------------------------------" << endl;
1304   cerr << "----------------------------------------------" << endl;
1305
1306   int status = system("lamboot");
1307   if (status == -1)
1308   {
1309     INFOS("lamboot failed : system command status -1");
1310   }
1311   else if (status == 217)
1312   {
1313     INFOS("lamboot failed : system command status 217");
1314   }
1315   else
1316   {
1317     _MpiStarted = true;
1318   }
1319 }
1320