Salome HOME
[EDF30062] : Forward of current directory mecanism
[modules/kernel.git] / src / KERNEL_PY / __init__.py
index 0f7bee48c518b70738e7c6cfcfee834e8800ede9..6d7d73211f837fd94006e9254f551918d94eb4b7 100644 (file)
@@ -1,5 +1,5 @@
 #  -*- coding: iso-8859-1 -*-
-# Copyright (C) 2007-2021  CEA/DEN, EDF R&D, OPEN CASCADE
+# Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
 #
 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -136,7 +136,7 @@ if not flags:
         # dl module can be unavailable
         import dl
         flags = dl.RTLD_NOW | dl.RTLD_GLOBAL
-    except:
+    except Exception:
         pass
     pass
 if not flags:
@@ -144,7 +144,7 @@ if not flags:
         # DLFCN module can be unavailable
         import DLFCN
         flags = DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL
-    except:
+    except Exception:
         pass
     pass
 if not flags:
@@ -152,7 +152,7 @@ if not flags:
         # ctypes module can be unavailable
         import ctypes
         flags = ctypes.RTLD_GLOBAL
-    except:
+    except Exception:
         pass
     pass
 
@@ -161,55 +161,62 @@ if not flags:
 #    sys.setdlopenflags(flags)
 #    pass
 
-orb, lcc, naming_service, cm, sg, esm, dsm, modulcat = None,None,None,None,None,None,None,None
+orb, lcc, naming_service, cm, sg, esm, dsm, logm, modulcat, rm = None,None,None,None,None,None,None,None,None,None
 myStudy, myStudyName = None,None
 
 salome_initial=True
 
-__EMB_SERVANT_ENV_VAR_NAME = "SALOME_EMB_SERVANT"
-
 def standalone():
-    import os
-    os.environ[__EMB_SERVANT_ENV_VAR_NAME] = "1"
+    pass
+
+def withServers():
     import KernelBasis
-    KernelBasis.setSSLMode(True)
+    KernelBasis.setSSLMode(False)
 
-def salome_init(path=None, embedded=False):
-    import os
+def salome_init(path=None, embedded=False, iorfakensfile=None, forced=False):
+    """
+    Initialize SALOME client process (that can also be server).
+    3 modes of initialization exists:
+    - SSL mode (see salome_init_without_session)
+    - SSL mode attached in the context of python execution inside SALOME_Container_No_NS_Serv server (typically YACS)
+    - Classical mode (see salome_init_with_session)
+    :param iorfakensfile: filename inside which IOR of fake NS will be written
+    :param forced: tell if the multi-initialization protection mecanism of salome_init must be skiped of not
+                   (typically in the context where a path to a study is given whereas a previous initialisation without it was done)
+    """
+    if not forced:
+        if lcc is not None:# multi-initialization protection mecanism is based on lcc global var
+            return
+    PATH_TO_STUDY_FILE_TO_INITIATE = "PATH_TO_STUDY_FILE_TO_INITIATE"
     import KernelBasis
-    if __EMB_SERVANT_ENV_VAR_NAME in os.environ:
-        KernelBasis.setSSLMode(True)
-    #
     if KernelBasis.getSSLMode():
         if KernelBasis.getIOROfEmbeddedNS() == "":
-            salome_init_without_session()
+            import os
+            # make runSalome.py -t study.hdf toto.py
+            if path is None and PATH_TO_STUDY_FILE_TO_INITIATE in os.environ:
+                path = os.environ[PATH_TO_STUDY_FILE_TO_INITIATE]
+            salome_init_without_session(path, embedded, iorfakensfile)
         else:
-            salome_init_without_session_attached()
+            salome_init_without_session_attached(path, embedded)
     else:
         salome_init_with_session(path, embedded)
 
-class StandAloneLifecyle:
-    def __init__(self, containerManager, resourcesManager):
-        self._cm = containerManager
-        self._rm = resourcesManager
-
-    def FindOrLoadComponent(self,contName,moduleName):
-        global orb
-        import importlib
-        builder_name = moduleName + "_SalomeSessionless"
-        moduleObj = importlib.import_module(builder_name)
-        result, orb = moduleObj.buildInstance(orb)
-        return result
-        #raise RuntimeError("Undealed situation cont = {} module = {}".format(contName,moduleName))
-
-    def getContainerManager(self):
-      return self._cm
-
-    def getResourcesManager(self):
-      return self._rm
-
-def salome_init_without_session_common():
-    global lcc,naming_service,myStudy,orb,modulcat,sg
+def salome_init_without_session_common(path=None, embedded=False):
+    from ORBConfigFile import writeORBConfigFileSSL
+    OMNIORB_USER_PATH = "OMNIORB_USER_PATH"
+    def RemoveOmniorbConfigFile():
+        import os
+        if "OMNIORB_CONFIG" in os.environ:
+            fileToRemove = os.environ["OMNIORB_CONFIG"]
+            if os.path.exists(fileToRemove):
+                os.unlink(fileToRemove)
+
+    if OMNIORB_USER_PATH in os.environ:
+        import atexit
+        writeORBConfigFileSSL(os.environ[OMNIORB_USER_PATH],kwargs={"with_pid":True})
+        atexit.register(RemoveOmniorbConfigFile)
+
+    global lcc,naming_service,myStudy,myStudyName,orb,modulcat,sg
     import KernelBasis
     KernelBasis.setSSLMode(True)
     import KernelDS
@@ -224,18 +231,30 @@ def salome_init_without_session_common():
     poa = orb.resolve_initial_references("RootPOA")
     poaManager = poa._get_the_POAManager()
     poaManager.activate()
-    sg = SalomeOutsideGUI()
-    salome_study_init_without_session()
+    #
+    sg = salome_iapp_init(embedded)
+    salome_study_init_without_session(path)
     #
     from NamingService import NamingService
     naming_service = NamingService()
+    myStudyName = myStudy.Name
 
-def salome_init_without_session():
-    salome_init_without_session_common()
-    global lcc,cm,dsm,esm
+def salome_init_without_session(path=None, embedded=False, iorfakensfile=None):
+    """
+    Force creation of all servants needed by SALOME session in the current process.
+    A Fake NamingService is created storing reference of all servants in the current process.
+    """
+    salome_init_without_session_common(path,embedded)
+    global lcc,cm,dsm,esm,rm,logm
     import KernelLauncher
     cm = KernelLauncher.myContainerManager()
-    lcc = StandAloneLifecyle(cm, KernelLauncher.myResourcesManager())
+    type(cm).SetOverrideEnvForContainersSimple = ContainerManagerSetOverrideEnvForContainersSimple
+    rm = KernelLauncher.myResourcesManager()
+    from LifeCycleCORBA import LifeCycleCORBASSL
+    lcc = LifeCycleCORBASSL()
+    # create a FactoryServer Container servant
+    import KernelContainer
+    KernelContainer.myContainer()
     # activate poaManager to accept co-localized CORBA calls.
     from KernelSDS import GetDSMInstance
     import sys
@@ -247,25 +266,60 @@ def salome_init_without_session():
     # esm inherits from SALOME_CPythonHelper singleton already initialized by GetDSMInstance
     # esm inherits also from SALOME_ResourcesManager creation/initialization (concerning SingleThreadPOA POA) when KernelLauncher.GetContainerManager() has been called
     esm = KernelLauncher.GetExternalServer()
+    # idem for logm
+    logm = KernelLauncher.myLogManager()
+    type(logm).NaiveFetch = LogManagerNaiveFetch
+    type(logm).Fetch = LogManagerFetch
+    type(logm).DumpInFile = LogManagerDumpInFile
+    type(logm).LaunchMonitoringDumpFile = LogManagerLaunchMonitoringDumpFile
+    type(logm).FinalFetchBeforeDying = LogManagerFinalFetchBeforeDying
+    type(logm).GetLatestMonitoringDumpFile = LogManagerGetLatestMonitoringDumpFile
+    type(logm).DumpIORInFile = LogManagerDumpIORInFile
+    #
+    import KernelLogger
+    naming_service.Register(KernelLogger.myLogger(),"/Logger")
+    #
+    from NamingService import NamingService
+    if iorfakensfile is not None:
+        with open(iorfakensfile,"w") as iorfakensf:
+            iorfakensf.write(NamingService.IOROfNS())
     
-def salome_init_without_session_attached():
+CM_NAME_IN_NS = "/ContainerManager"
+RM_NAME_IN_NS = "/ResourcesManager"
+DSM_NAME_IN_NS = "/DataServerManager"
+ESM_NAME_IN_NS = "/ExternalServers"
+LOGM_NAME_IN_NS = "/LogManager"
+
+def salome_init_without_session_attached(path=None, embedded=False):
     """
     Configuration SSL inside a python interpretor launched in the SALOME_Container_No_NS_Serv.
-    In this configuration, 
+    In this configuration, a local FakeNamingService is created and remote objects are stored in it.
+    lcc is pointing to the FakeNamingService above.
     """
-    salome_init_without_session_common()
-    global lcc,cm,dsm,esm
+    salome_init_without_session_common(path,embedded)
+    global lcc,cm,dsm,esm,rm,logm
     import CORBA
     orb=CORBA.ORB_init([''])
     import Engines
     import KernelBasis
     nsAbroad = orb.string_to_object( KernelBasis.getIOROfEmbeddedNS() )
     import SALOME
-    cm = orb.string_to_object( nsAbroad.Resolve("/ContainerManager").decode() )
-    rm = orb.string_to_object( nsAbroad.Resolve("/ResourcesManager").decode() )
-    lcc = StandAloneLifecyle(cm,rm)
-    dsm = orb.string_to_object( nsAbroad.Resolve("/DataServerManager").decode() )
-    esm = orb.string_to_object( nsAbroad.Resolve("/ExternalServers").decode() )
+    cm = orb.string_to_object( nsAbroad.Resolve(CM_NAME_IN_NS).decode() )
+    type(cm).SetOverrideEnvForContainersSimple = ContainerManagerSetOverrideEnvForContainersSimple
+    naming_service.Register(cm,CM_NAME_IN_NS)
+    rm = orb.string_to_object( nsAbroad.Resolve(RM_NAME_IN_NS).decode() )
+    naming_service.Register(rm,RM_NAME_IN_NS)
+    #
+    from LifeCycleCORBA import LifeCycleCORBASSL
+    lcc = LifeCycleCORBASSL()
+    dsm = orb.string_to_object( nsAbroad.Resolve(DSM_NAME_IN_NS).decode() )
+    naming_service.Register(dsm,DSM_NAME_IN_NS)
+    #
+    esm = orb.string_to_object( nsAbroad.Resolve(ESM_NAME_IN_NS).decode() )
+    naming_service.Register(esm,ESM_NAME_IN_NS)
+    #
+    logm = orb.string_to_object( nsAbroad.Resolve(LOGM_NAME_IN_NS).decode() )
+    naming_service.Register(logm,LOGM_NAME_IN_NS)
 
 def salome_init_with_session(path=None, embedded=False):
     """
@@ -301,7 +355,7 @@ def salome_init_with_session(path=None, embedded=False):
         import time
         time.sleep(0.2)
         x = inst
-        print("salome.salome_init():", x)
+        print("salome.salome_init_with_session():", x)
         print("""
         ============================================
         May be there is no running SALOME session
@@ -312,18 +366,19 @@ def salome_init_with_session(path=None, embedded=False):
         raise
     
 def salome_close():
-    global salome_initial, myStudy, myStudyName
+    global salome_initial, myStudy, myStudyName, lcc
     try:
         # study can be clear either from GUI or directly with salome.myStudy.Clear()
         myStudy.Clear()
-    except:
+    except Exception:
         pass
     salome_initial=True
     salome_iapp_close()
     salome_study_close()
     myStudy, myStudyName = None, None
+    lcc = None # to salome_init to rebuild all in case of salome_init after salome_close
     import KernelBasis
-    if KernelBasis.getSSLMode():
+    if KernelBasis.getSSLMode() and not KernelBasis.getGUIMode():
         import KernelDS
         KernelDS.KillGlobalSessionInstance()
         import KernelSDS
@@ -359,7 +414,7 @@ def salome_walk_on_containers(ns,root):
         pass
     pass
 
-def salome_shutdown_containers():
+def salome_shutdown_containers_with_session():
     salome_init()
     ns=salome_NS()
     li = [elt for elt in salome_walk_on_containers(ns,[""])]
@@ -367,12 +422,33 @@ def salome_shutdown_containers():
     for cont,(root,cont_name) in li:
         try:
             cont.Shutdown()
-        except:
+        except Exception:
             pass
         ref_in_ns = "/".join(root+[cont_name])
         naming_service.Destroy_Name(ref_in_ns)
     print("Number of containers in NS after clean : {}".format( len( list(salome_walk_on_containers(ns,[""])) )))
 
+def retrieve_containers_in_ns():
+    return [elt for elt in naming_service.repr() if "/Containers/" == elt[:12]]
+
+def get_all_containers():
+    containersEntries = retrieve_containers_in_ns()
+    return [naming_service.Resolve(containerEntry) for containerEntry in containersEntries]
+    
+def salome_shutdown_containers_without_session():
+    for cont in get_all_containers():
+        try:
+            cont.Shutdown()
+        except:
+            pass
+
+def salome_shutdown_containers():
+    import KernelBasis
+    if KernelBasis.getSSLMode():
+        salome_shutdown_containers_without_session()
+    else:
+        salome_shutdown_containers_with_session()
+
 class SessionContextManager:
     def __enter__(self):
         standalone()
@@ -380,5 +456,150 @@ class SessionContextManager:
     def __exit__(self, type, value, traceback):
         salome_close()
 
+def ContainerManagerSetOverrideEnvForContainersSimple(self,env):
+    envEff = [ Engines.KeyValPairString(key=k,val=v) for k,v in env ]
+    return self.SetOverrideEnvForContainers( envEff )
+
+def LogManagerNaiveFetch(self):
+    """
+    Fetch data from server with multiple CORBA invokations.
+    """
+    import SALOME_ContainerHelper
+    return [SALOME_ContainerHelper.ContainerLogInfoClt(elt) for elt in self.listOfContainerLogs()]
+
+def LogManagerFetch(self,clearMemory = False):
+    """
+    Fetch data from server in one shot mode.
+    """
+    from SALOME_ContainerHelper import unserializeLogManager
+    return unserializeLogManager( self.getAllStruct(clearMemory) )
+
+def LogManagerDumpInFile(self,fileName,clearMemory = False):
+    with open(fileName,"wb") as f:
+        f.write( self.getAllStruct( clearMemory ) )
+
+
+class LogManagerLaunchMonitoringFileCtxMgr:
+    def __init__(self, intervalInMs, outFileName):
+        self._interval_in_ms = intervalInMs
+        self._out_filename = outFileName
+        self._monitoring_params = None
+    def __enter__(self):
+        import salome
+        self._monitoring_params = salome.logm.LaunchMonitoringDumpFile(self._interval_in_ms, self._out_filename)
+        return self._monitoring_params
+    def __exit__(self,exctype, exc, tb):
+        import SALOME_PyNode
+        import salome
+        SALOME_PyNode.StopMonitoring( self._monitoring_params )
+        salome.logm.GetLatestMonitoringDumpFile()
+        pass
+
+def LogManagerLaunchMonitoringDumpFile(self, intervalInMs, outFileName):
+    """
+    This method loops indefinitely every intervalInMs milliseconds to dump the singleton 
+    content of perf log stored in salome.logm.
+    This method runs in a dedicated subprocess that can be killed at any time.
+    So subprocess code must deal with.
+
+    See also LogManagerGetLatestMonitoringDumpFile
+    """
+    global orb,logm
+    ior = orb.object_to_string( logm )
+    import os
+    outFileName2 = os.path.abspath( os.path.expanduser(outFileName) )
+    import tempfile
+    import logging
+    import SALOME_PyNode
+    import KernelBasis
+    # outFileNameSave stores the content of outFileName during phase of dumping
+    with tempfile.NamedTemporaryFile(prefix=os.path.basename(outFileName2),dir=os.path.dirname(outFileName2)) as f:
+      outFileNameSave = f.name
+    with tempfile.NamedTemporaryFile(prefix="htopmain_",suffix=".py") as f:
+      tempPyFile = f.name
+    with open(tempPyFile,"w") as f:
+        f.write("""import Engines
+import os
+import shutil
+import CORBA
+import time
+orb=CORBA.ORB_init([''], CORBA.ORB_ID)
+logm = orb.string_to_object("{ior}")
+outFileName = "{outFileName}"
+outFileNameSave = "{outFileNameSave}"
+logm.setFileNamePairOfLogger(outFileName, outFileNameSave )
+import salome
+while(True):
+  if os.path.exists( outFileName ):
+    shutil.copy(outFileName,outFileNameSave)
+    logm.versionB_IsTheLatestValidVersion()
+  salome.LogManagerDumpInFile(logm,outFileName)
+  logm.versionA_IsTheLatestValidVersion()
+  time.sleep( {intervalInMs} / 1000.0 )
+""".format( **locals()))
+    logging.debug( "File for monitoring dump file : {}".format(tempPyFile) )
+    pyFileName = SALOME_PyNode.FileDeleter( tempPyFile )
+    pid = KernelBasis.LaunchMonitoring( tempPyFile )
+    return SALOME_PyNode.MonitoringInfo(pyFileName,intervalInMs,None,pid)
+
+def LogManagerDumpIORInFile(self, iorFileName):
+    global logm
+    with open(iorFileName,"w") as f:
+        f.write( orb.object_to_string( logm ) )
+
+def LogManagerLoadFromFile(fileName):
+    from SALOME_ContainerHelper import unserializeLogManager
+    with open(fileName,"rb") as f:
+        data = f.read()
+    return unserializeLogManager( data )
+
+def LogManagerLoadFromIORFile( iorFile ):
+    global orb
+    def LoadAndWrite(logm,tempFileName):
+        import SALOME_PyNode
+        logm.putStructInFileAtomic( False, tempFileName )
+        tempFileAuto = SALOME_PyNode.FileDeleter( tempFileName )
+        ret = LogManagerLoadFromFile( tempFileAuto.filename )
+        return ret
+    with open(iorFile,"r") as f:
+        ior = f.read()
+    import Engines
+    import tempfile
+    salome_init_without_session()
+    logm = orb.string_to_object( ior )
+    with tempfile.NamedTemporaryFile(dir=os.path.expanduser("~")) as f:
+        tempFileName = f.name
+    return LoadAndWrite( logm, tempFileName )
+
+def LogManagerFinalFetchBeforeDying(self):
+    import shutil
+    a,b = self.getFileNamePairOfLogger()
+    self.DumpInFile( b )
+    shutil.move( b, a)
+
+def LogManagerGetLatestMonitoringDumpFile(self):
+    import shutil
+    import logging
+    a,b = self.getFileNamePairOfLogger()
+    if a=="" or b=="":
+        return ""
+    if a == b:
+        return a
+    lastVersion = self.getLastVersionOfFileNameLogger()
+    if lastVersion == a:
+        logging.debug("LogManagerGetLatestMonitoringDumpFile SITUATION A")
+        if os.path.exists( b ):
+            os.remove( b )
+        self.FinalFetchBeforeDying()
+        return a
+    if lastVersion == b:
+        logging.debug("LogManagerGetLatestMonitoringDumpFile SITUATION B")
+        if os.path.exists( b ):
+            shutil.move( b, a)
+        self.FinalFetchBeforeDying()
+        return a
+    logging.warning("in LogManagerGetLatestMonitoringDumpFile an unexpected situation araises.")
+    return ""
+
 #to expose all objects to pydoc
-__all__=dir()
+__all__ = dir()