]> SALOME platform Git repositories - modules/kernel.git/blob - src/Container/SALOME_ContainerManager.cxx
Salome HOME
A patch from Paul RASCLE for: kernel documentation with doxygen, modification on...
[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 "OpUtil.hxx"
23 #include <sys/types.h>
24 #ifndef WNT
25 #include <unistd.h>
26 #endif
27 #include <vector>
28 #include "Utils_CorbaException.hxx"
29 #include "Batch_Date.hxx"
30
31 #ifdef WITH_PACO_PARALLEL
32 #include "PaCO++.h"
33 #endif
34
35 #define TIME_OUT_TO_LAUNCH_CONT 21
36
37 using namespace std;
38
39 vector<Engines::Container_ptr> SALOME_ContainerManager::_batchLaunchedContainers;
40
41 vector<Engines::Container_ptr>::iterator SALOME_ContainerManager::_batchLaunchedContainersIter;
42
43 const char *SALOME_ContainerManager::_ContainerManagerNameInNS = 
44   "/ContainerManager";
45
46 //=============================================================================
47 /*! 
48  *  Constructor
49  *  \param orb
50  *  Define a CORBA single thread policy for the server, which avoid to deal
51  *  with non thread-safe usage like Change_Directory in SALOME naming service
52  */
53 //=============================================================================
54
55 SALOME_ContainerManager::SALOME_ContainerManager(CORBA::ORB_ptr orb, PortableServer::POA_var poa, SALOME_ResourcesManager *rm, SALOME_NamingService *ns)
56 {
57   MESSAGE("constructor");
58   _NS = ns;
59   _ResManager = rm;
60   _id=0;
61
62   PortableServer::POAManager_var pman = poa->the_POAManager();
63   _orb = CORBA::ORB::_duplicate(orb) ;
64   CORBA::PolicyList policies;
65   policies.length(1);
66   PortableServer::ThreadPolicy_var threadPol = 
67     poa->create_thread_policy(PortableServer::SINGLE_THREAD_MODEL);
68   policies[0] = PortableServer::ThreadPolicy::_duplicate(threadPol);
69
70   _poa = poa->create_POA("SThreadPOA",pman,policies);
71   threadPol->destroy();
72   PortableServer::ObjectId_var id = _poa->activate_object(this);
73   CORBA::Object_var obj = _poa->id_to_reference(id);
74   Engines::ContainerManager_var refContMan =
75     Engines::ContainerManager::_narrow(obj);
76
77   _NS->Register(refContMan,_ContainerManagerNameInNS);
78   MESSAGE("constructor end");
79 }
80
81 //=============================================================================
82 /*! 
83  * destructor
84  */
85 //=============================================================================
86
87 SALOME_ContainerManager::~SALOME_ContainerManager()
88 {
89   MESSAGE("destructor");
90 }
91
92 //=============================================================================
93 /*! CORBA method:
94  *  shutdown all the containers, then the ContainerManager servant
95  */
96 //=============================================================================
97
98 void SALOME_ContainerManager::Shutdown()
99 {
100   MESSAGE("Shutdown");
101   ShutdownContainers();
102   _NS->Destroy_Name(_ContainerManagerNameInNS);
103   PortableServer::ObjectId_var oid = _poa->servant_to_id(this);
104   _poa->deactivate_object(oid);
105   _remove_ref();
106 }
107
108 //=============================================================================
109 /*! CORBA method:
110  *  shutdown the ContainerManager servant and kill the ContainerManager process
111  */
112 //=============================================================================
113 void SALOME_ContainerManager::ShutdownWithExit()
114 {
115   MESSAGE("ShutdownWithExit");
116   PortableServer::ObjectId_var oid = _default_POA()->servant_to_id(this);
117   _default_POA()->deactivate_object(oid);
118   _remove_ref();
119   
120   exit( EXIT_SUCCESS );
121 }
122
123 //=============================================================================
124 /*! CORBA Method:
125  *  Loop on all the containers listed in naming service, ask shutdown on each
126  */
127 //=============================================================================
128
129 void SALOME_ContainerManager::ShutdownContainers()
130 {
131   MESSAGE("ShutdownContainers");
132   bool isOK;
133   isOK = _NS->Change_Directory("/Containers");
134   if( isOK ){
135     vector<string> vec = _NS->list_directory_recurs();
136     list<string> lstCont;
137     for(vector<string>::iterator iter = vec.begin();iter!=vec.end();iter++){
138       SCRUTE((*iter));
139       CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
140       Engines::Container_var cont=Engines::Container::_narrow(obj);
141       if(!CORBA::is_nil(cont)){
142         lstCont.push_back((*iter));
143       }
144     }
145     MESSAGE("Container list: ");
146     for(list<string>::iterator iter=lstCont.begin();iter!=lstCont.end();iter++){
147       SCRUTE((*iter));
148     }
149     for(list<string>::iterator iter=lstCont.begin();iter!=lstCont.end();iter++){
150       SCRUTE((*iter));
151       CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
152       Engines::Container_var cont=Engines::Container::_narrow(obj);
153       if(!CORBA::is_nil(cont)){
154         MESSAGE("ShutdownContainers: " << (*iter));
155         cont->Shutdown();
156       }
157       else MESSAGE("ShutdownContainers: no container ref for " << (*iter));
158     }
159   }
160 }
161
162 //=============================================================================
163 /*! CORBA Method:
164  *  Returns the PID of the container manager
165  */
166 //=============================================================================
167 CORBA::Long SALOME_ContainerManager::getPID()
168 {
169   return (CORBA::Long)getpid();
170 }
171
172 //=============================================================================
173 /*! CORBA Method:
174  *  Find a suitable Container in a list of machines, or start one
175  *  \param params            Machine Parameters required for the container
176  *  \param possibleComputers list of machines usable for find or start
177  */
178 //=============================================================================
179
180 Engines::Container_ptr
181 SALOME_ContainerManager::
182 FindOrStartContainer(const Engines::MachineParameters& params,
183                      const Engines::MachineList& possibleComputers)
184 {
185   Engines::Container_ptr ret = FindContainer(params,possibleComputers);
186   if(!CORBA::is_nil(ret))
187     return ret;
188   MESSAGE("Container doesn't exist try to launch it ...");
189
190   return StartContainer(params,possibleComputers,Engines::P_FIRST);
191
192 }
193
194 //=============================================================================
195 /*! CORBA Method:
196  *  Start a suitable Container in a list of machines
197  *  \param params            Machine Parameters required for the container
198  *  \param possibleComputers list of machines usable for start
199  */
200 //=============================================================================
201
202 Engines::Container_ptr
203 SALOME_ContainerManager::
204 StartContainer(const Engines::MachineParameters& params,
205                const Engines::MachineList& possibleComputers,
206                Engines::ResPolicy policy)
207 {
208 #ifdef WITH_PACO_PARALLEL
209   std::string parallelLib(params.parallelLib);
210   if (parallelLib != "")
211     return FindOrStartParallelContainer(params, possibleComputers);
212 #endif
213   long id;
214   string containerNameInNS;
215   char idc[3*sizeof(long)];
216   Engines::Container_ptr ret = Engines::Container::_nil();
217
218   MESSAGE("SALOME_ContainerManager::StartContainer " <<
219           possibleComputers.length());
220
221   string theMachine;
222   try{
223     switch(policy){
224     case Engines::P_FIRST:
225       theMachine=_ResManager->FindFirst(possibleComputers);
226       break;
227     case Engines::P_CYCL:
228       theMachine=_ResManager->FindNext(possibleComputers);
229       break;
230     case Engines::P_BEST:
231       theMachine=_ResManager->FindBest(possibleComputers);
232       break;
233     }
234   }
235   catch( const SALOME_Exception &ex ){
236     MESSAGE(ex.what());
237     return Engines::Container::_nil();
238   }
239
240   MESSAGE("try to launch it on " << theMachine);
241
242   // Get Id for container: a parallel container registers in Naming Service
243   // on the machine where is process 0. ContainerManager does'nt know the name
244   // of this machine before the launch of the parallel container. So to get
245   // the IOR of the parallel container in Naming Service, ContainerManager
246   // gives a unique Id. The parallel container registers his name under
247   // /ContainerManager/Id directory in NamingService
248
249   id = GetIdForContainer();
250
251   string command;
252   if(theMachine==""){
253     MESSAGE("SALOME_ContainerManager::StartContainer : " <<
254             "no possible computer");
255     return Engines::Container::_nil();
256   }
257   else if(theMachine==GetHostname())
258     command=_ResManager->BuildCommandToLaunchLocalContainer(params,id);
259   else
260     command = _ResManager->BuildCommandToLaunchRemoteContainer(theMachine,params,id);
261
262   _ResManager->RmTmpFile();
263   int status=system(command.c_str());
264   if (status == -1){
265     MESSAGE("SALOME_LifeCycleCORBA::StartOrFindContainer rsh failed " <<
266             "(system command status -1)");
267     return Engines::Container::_nil();
268   }
269   else if (status == 217){
270     MESSAGE("SALOME_LifeCycleCORBA::StartOrFindContainer rsh failed " <<
271             "(system command status 217)");
272     return Engines::Container::_nil();
273   }
274   else{
275     int count=TIME_OUT_TO_LAUNCH_CONT;
276     MESSAGE("count = "<<count);
277     while ( CORBA::is_nil(ret) && count ){
278 #ifndef WNT
279       sleep( 1 ) ;
280 #else
281       Sleep(1000);
282 #endif
283       count-- ;
284       if ( count != 10 )
285         MESSAGE( count << ". Waiting for container on " << theMachine);
286
287       if(params.isMPI){
288         containerNameInNS = "/ContainerManager/id";
289         sprintf(idc,"%ld",id);
290         containerNameInNS += idc;
291       }
292       else
293         containerNameInNS = _NS->BuildContainerNameForNS(params,theMachine.c_str());
294
295       SCRUTE(containerNameInNS);
296       CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
297       ret=Engines::Container::_narrow(obj);
298     }
299     
300     if ( CORBA::is_nil(ret) )
301       MESSAGE("SALOME_LifeCycleCORBA::StartOrFindContainer rsh failed");
302
303     return ret;
304   }
305 }
306
307 //=============================================================================
308 /*! CORBA Method:
309  *  Start a suitable Container in a list of machines
310  *  \param params            Machine Parameters required for the container
311  *  \param possibleComputers list of machines usable for start
312  */
313 //=============================================================================
314
315 Engines::Container_ptr
316 SALOME_ContainerManager::
317 StartContainer(const Engines::MachineParameters& params,
318                Engines::ResPolicy policy,
319                const Engines::CompoList& componentList)
320 {
321   Engines::MachineList_var possibleComputers = _ResManager->GetFittingResources(params,componentList);
322   return StartContainer(params,possibleComputers,policy);
323 }
324
325 #ifdef WITH_PACO_PARALLEL
326 //=============================================================================
327 /*! CORBA Method:
328  *  Find or Start a suitable PaCO++ Parallel Container in a list of machines.
329  *  \param params            Machine Parameters required for the container
330  *  \param possibleComputers list of machines usable for find or start
331  *
332  *  \return CORBA container reference.
333  */
334 //=============================================================================
335 Engines::Container_ptr
336 SALOME_ContainerManager::
337 FindOrStartParallelContainer(const Engines::MachineParameters& params_const,
338                              const Engines::MachineList& possibleComputers)
339 {
340   CORBA::Object_var obj;
341   Engines::Container_ptr ret = Engines::Container::_nil();
342   Engines::MachineParameters params(params_const);
343
344   // Step 1 : Try to find a suitable container
345   // Currently not as good as could be since
346   // we have to verified the number of nodes of the container
347   // if a user tell that.
348   ret = FindContainer(params, possibleComputers);
349
350   if(CORBA::is_nil(ret)) {
351     // Step 2 : Starting a new parallel container
352     INFOS("[FindOrStartParallelContainer] Starting a parallel container");
353     
354     // Step 2.1 : Choose a computer
355     string theMachine = _ResManager->FindFirst(possibleComputers);
356     if(theMachine == "") {
357       INFOS("[FindOrStartParallelContainer] !!!!!!!!!!!!!!!!!!!!!!!!!!");
358       INFOS("[FindOrStartParallelContainer] No possible computer found");
359       INFOS("[FindOrStartParallelContainer] !!!!!!!!!!!!!!!!!!!!!!!!!!");
360     }
361     else {
362       INFOS("[FindOrStartParallelContainer] on machine : " << theMachine);
363       string command;
364       if(theMachine == GetHostname()) {
365         // Step 3 : starting parallel container proxy
366         params.hostname = CORBA::string_dup(theMachine.c_str());
367         Engines::MachineParameters params_proxy(params);
368         command = _ResManager->BuildCommandToLaunchLocalParallelContainer("SALOME_ParallelContainerProxy", params_proxy, "xterm");
369         // LaunchParallelContainer uses this value to know if it launches the proxy or the nodes
370         params_proxy.nb_component_nodes = 0;
371         obj = LaunchParallelContainer(command, params_proxy, _NS->ContainerName(params));
372         ret = Engines::Container::_narrow(obj);
373
374         // Step 4 : starting parallel container nodes
375         command = _ResManager->BuildCommandToLaunchLocalParallelContainer("SALOME_ParallelContainerNode", params, "xterm");
376         string name = _NS->ContainerName(params) + "Node";
377         LaunchParallelContainer(command, params, name);
378
379         // Step 5 : connecting nodes and the proxy to actually create a parallel container
380         try {
381         for (int i = 0; i < params.nb_component_nodes; i++) {
382
383         char buffer [5];
384 #ifndef WNT
385           snprintf(buffer,5,"%d",i);
386 #else
387           _snprintf(buffer,5,"%d",i);
388 #endif
389         string name_cont = name + string(buffer);
390
391         string theNodeMachine(CORBA::string_dup(params.hostname));
392         string containerNameInNS = _NS->BuildContainerNameForNS(name_cont.c_str(),theNodeMachine.c_str());
393         int count = TIME_OUT_TO_LAUNCH_CONT;
394         obj = _NS->Resolve(containerNameInNS.c_str());
395         while (CORBA::is_nil(obj) && count) {
396           INFOS("[FindOrStartParallelContainer] CONNECTION FAILED !!!!!!!!!!!!!!!!!!!!!!!!");
397 #ifndef WNT
398           sleep(1) ;
399 #else
400           Sleep(1000);
401 #endif
402           count-- ;
403           obj = _NS->Resolve(containerNameInNS.c_str());
404         }
405
406         PaCO::InterfaceParallel_var node = PaCO::InterfaceParallel::_narrow(obj);
407         MESSAGE("[FindOrStartParallelContainer] Deploying node : " << name);
408         node->deploy(i);
409         }
410         }
411         catch(CORBA::SystemException& e)
412         {
413           INFOS("Caught CORBA::SystemException. : " << e);
414         }
415         catch(PortableServer::POA::ServantAlreadyActive&)
416         {
417           INFOS("Caught CORBA::ServantAlreadyActiveException");
418         }
419         catch(CORBA::Exception&)
420         {
421           INFOS("Caught CORBA::Exception.");
422         }
423         catch(std::exception& exc)
424         {
425           INFOS("Caught std::exception - "<<exc.what()); 
426         }
427         catch(...)
428         {
429           INFOS("Caught unknown exception.");
430         }
431         INFOS("[FindOrStartParallelContainer] node " << name << " deployed");
432       }
433
434       else {
435         INFOS("[FindOrStartParallelContainer] Currently parallel containers are launched only on the local host");
436       }
437     }
438   }
439   return ret;
440 }
441 #else
442 //=============================================================================
443 /*! CORBA Method:
444  *  Find or Start a suitable PaCO++ Parallel Container in a list of machines.
445  *  \param params            Machine Parameters required for the container
446  *  \param possibleComputers list of machines usable for find or start
447  *
448  *  \return CORBA container reference.
449  */
450 //=============================================================================
451 Engines::Container_ptr
452 SALOME_ContainerManager::
453 FindOrStartParallelContainer(const Engines::MachineParameters& params,
454                              const Engines::MachineList& possibleComputers)
455 {
456   Engines::Container_ptr ret = Engines::Container::_nil();
457   INFOS("[FindOrStartParallelContainer] is disabled !");
458   INFOS("[FindOrStartParallelContainer] recompile SALOME Kernel to enable parallel extension");
459   return ret;
460 }
461 #endif
462
463 //=============================================================================
464 /*! CORBA Method:
465  *  Give a suitable Container in a list of machines
466  *  \param params            Machine Parameters required for the container
467  *  \param possibleComputers list of machines usable for start
468  */
469 //=============================================================================
470
471 Engines::Container_ptr
472 SALOME_ContainerManager::
473 GiveContainer(const Engines::MachineParameters& params,
474                Engines::ResPolicy policy,
475                const Engines::CompoList& componentList)
476 {
477   char *valenv=getenv("SALOME_BATCH");
478   if(valenv)
479     if (strcmp(valenv,"1")==0)
480       {
481         if(_batchLaunchedContainers.empty())
482           fillBatchLaunchedContainers();
483         return *(_batchLaunchedContainersIter++);
484       }
485   return StartContainer(params,policy,componentList);
486 }
487
488 //=============================================================================
489 /*! 
490  * 
491  */
492 //=============================================================================
493
494 Engines::Container_ptr
495 SALOME_ContainerManager::
496 FindContainer(const Engines::MachineParameters& params,
497               const char *theMachine)
498 {
499   string containerNameInNS(_NS->BuildContainerNameForNS(params,theMachine));
500   CORBA::Object_var obj = _NS->Resolve(containerNameInNS.c_str());
501   if( !CORBA::is_nil(obj) )
502     return Engines::Container::_narrow(obj);
503   else
504     return Engines::Container::_nil();
505 }
506
507 //=============================================================================
508 /*! 
509  * 
510  */
511 //=============================================================================
512
513 Engines::Container_ptr
514 SALOME_ContainerManager::
515 FindContainer(const Engines::MachineParameters& params,
516               const Engines::MachineList& possibleComputers)
517 {
518   MESSAGE("FindContainer "<<possibleComputers.length());
519   for(unsigned int i=0;i<possibleComputers.length();i++)
520     {
521       MESSAGE("FindContainer possible " << possibleComputers[i]);
522       Engines::Container_ptr cont = FindContainer(params,possibleComputers[i]);
523       if( !CORBA::is_nil(cont) )
524         return cont;
525     }
526   MESSAGE("FindContainer: not found");
527   return Engines::Container::_nil();
528 }
529
530 //=============================================================================
531 /*! This method launches the parallel container.
532  *  It will may be placed on the ressources manager.
533  *
534  * \param command to launch
535  * \param container's parameters
536  * \param name of the container
537  *
538  * \return CORBA container reference
539  */
540 //=============================================================================
541 CORBA::Object_ptr 
542 SALOME_ContainerManager::LaunchParallelContainer(const std::string& command, 
543                                                  const Engines::MachineParameters& params,
544                                                  const std::string& name)
545 {
546   CORBA::Object_ptr obj = CORBA::Object::_nil();
547   string containerNameInNS;
548
549   if (params.nb_component_nodes == 0) {
550     INFOS("[LaunchParallelContainer] launching the proxy of the parallel container");
551     int status = system(command.c_str());
552     if (status == -1) {
553       INFOS("[LaunchParallelContainer] failed : system command status -1");
554     }
555     else if (status == 217) {
556       INFOS("[LaunchParallelContainer] failed : system command status 217");
557     }
558
559     int count = TIME_OUT_TO_LAUNCH_CONT;
560     string theMachine(CORBA::string_dup(params.hostname));
561     containerNameInNS = _NS->BuildContainerNameForNS((char*) name.c_str(),theMachine.c_str());
562
563     INFOS("[LaunchContainer]  Waiting for Parallel Container proxy on " << theMachine);
564     while (CORBA::is_nil(obj) && count) {
565 #ifndef WNT
566       sleep(1) ;
567 #else
568       Sleep(1000);
569 #endif
570       count-- ;
571       obj = _NS->Resolve(containerNameInNS.c_str());
572     }
573   }
574   else {
575     INFOS("[LaunchParallelContainer] launching the nodes of the parallel container");
576     int status = system(command.c_str());
577     if (status == -1) {
578       INFOS("[LaunchParallelContainer] failed : system command status -1");
579     }
580     else if (status == 217) {
581       INFOS("[LaunchParallelContainer] failed : system command status 217");
582     }
583     // We are waiting all the nodes
584     for (int i = 0; i < params.nb_component_nodes; i++) {
585       obj = CORBA::Object::_nil();
586       int count = TIME_OUT_TO_LAUNCH_CONT;
587
588       // Name of the node
589       char buffer [5];
590 #ifndef WNT
591       snprintf(buffer,5,"%d",i);
592 #else
593       _snprintf(buffer,5,"%d",i);
594 #endif
595
596       string name_cont = name + string(buffer);
597
598       // I don't like this...
599       string theMachine(CORBA::string_dup(params.hostname));
600       containerNameInNS = _NS->BuildContainerNameForNS((char*) name_cont.c_str(),theMachine.c_str());
601       cerr << "[LaunchContainer]  Waiting for Parllel Container node " << containerNameInNS << " on " << theMachine << endl;
602       while (CORBA::is_nil(obj) && count) {
603 #ifndef WNT
604         sleep(1) ;
605 #else
606         Sleep(1000);
607 #endif
608         count-- ;
609         obj = _NS->Resolve(containerNameInNS.c_str());
610       }
611     }
612   }
613
614   if ( CORBA::is_nil(obj) ) {
615     INFOS("[LaunchParallelContainer] failed");
616   }
617   return obj;
618 }
619
620 //=============================================================================
621 /*! 
622  * Get Id for container: a parallel container registers in Naming Service
623  * on the machine where is process 0. ContainerManager does'nt know the name
624  * of this machine before the launch of the parallel container. So to get
625  * the IOR of the parallel container in Naming Service, ContainerManager
626  * gives a unique Id. The parallel container registers his name under
627  * /ContainerManager/Id directory in NamingService
628  */
629 //=============================================================================
630
631
632 long SALOME_ContainerManager::GetIdForContainer(void)
633 {
634   _id++;
635   return _id;
636 }
637
638 void SALOME_ContainerManager::fillBatchLaunchedContainers()
639 {
640   _batchLaunchedContainers.clear();
641   _NS->Change_Directory("/Containers");
642   vector<string> vec = _NS->list_directory_recurs();
643   for(vector<string>::iterator iter = vec.begin();iter!=vec.end();iter++){
644     CORBA::Object_var obj=_NS->Resolve((*iter).c_str());
645     Engines::Container_ptr cont=Engines::Container::_narrow(obj);
646     if(!CORBA::is_nil(cont)){
647       _batchLaunchedContainers.push_back(cont);
648     }
649   }
650   _batchLaunchedContainersIter=_batchLaunchedContainers.begin();
651 }