From: Viktor UZLOV Date: Tue, 27 Oct 2020 09:21:59 +0000 (+0300) Subject: Use psutil package for cross-platform management of processes X-Git-Tag: V9_7_0a1~4^2 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=e1c10f3610b5857a9aa7c287cb973343e55fd79d;p=modules%2Fkernel.git Use psutil package for cross-platform management of processes --- diff --git a/bin/PortManager.py b/bin/PortManager.py index aace9e17b..0b05bb134 100644 --- a/bin/PortManager.py +++ b/bin/PortManager.py @@ -23,6 +23,9 @@ # import os import sys +import psutil + +from socket import AF_INET, SOCK_STREAM try: import cPickle as pickle #@UnusedImport @@ -103,55 +106,10 @@ def __isPortUsed(port, config): # def __isNetworkConnectionActiveOnPort(port): - # :NOTE: Under windows: - # netstat options -l and -t are unavailable - # grep command is unavailable - if sys.platform == "win32": - cmd = ['netstat','-a','-n','-p','tcp'] - else: - cmd = ['netstat','-ant'] - pass - - err = None - try: - from subprocess import Popen, PIPE, STDOUT - p = Popen(cmd, stdout=PIPE, stderr=STDOUT) - out, err = p.communicate() - except: - print("Error when trying to access active network connections.") - if err: print(err) - print("... Presumably this package is not installed...Please install netstat if available for your distribution.") - print("... Trying socket based approach") - try: - import socket - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - result = sock.connect_ex(("127.0.0.1", port)) - if result == 0: - print("Port %r: Closed" % (port)) - sock.close() - return True - else: - sock.close() - return False - except: - import traceback - traceback.print_exc() - return False - - from io import StringIO - buf = StringIO(out.decode('utf-8', 'ignore')) - ports = buf.readlines() - # search for TCP - LISTEN connections - import re - regObj = re.compile( ".*tcp.*:([0-9]+).*:.*listen", re.IGNORECASE ); - for item in ports: - try: - p = int(regObj.match(item).group(1)) - if p == port: return True - except: - pass - return False -# + # psutil realization + return port in [c.laddr.port for c in psutil.net_connections(kind='inet') if \ + (c.family, c.type, c.status) == (AF_INET, SOCK_STREAM, "LISTEN")] + # def getPort(preferredPort=None): logger.debug("GET PORT") diff --git a/bin/killSalome.py b/bin/killSalome.py index d7b8c392e..6b87bb731 100755 --- a/bin/killSalome.py +++ b/bin/killSalome.py @@ -22,83 +22,76 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -## \file killSalome.py -# Stop all %SALOME servers from all sessions by killing them -# +## @file killSalome.py +# @brief Forcibly stop all running %SALOME sessions. + +""" +Forcibly stop all running SALOME sessions. + +To stop all SALOME sessions, do the following: + +* in shell: + + $ killSalome.py -import os, sys, re, signal +* in Python script: -from killSalomeWithPort import killMyPort, getPiDict, checkUnkilledProcess -#from salome_utils import getHostName, getShortHostName -from salome_utils import getUserName + from killSalome import killAllPorts + killAllPorts() +""" + +# pragma pylint: disable=invalid-name + +import os +import os.path as osp +import re +import sys +from contextlib import suppress +from glob import glob + +from killSalomeWithPort import getPiDict, killMyPort, killUnkilledProcesses def killAllPorts(): """ - Kill all SALOME sessions belonging to the user. + Stop all running SALOME sessions owned by the current user. """ - user = getUserName() - #hostname = getHostName() - #shostname = getShortHostName() - # new-style dot-prefixed pidict file - #fpidict = getPiDict('(\d*)',hidden=True) - #problem with WIN32 path slashes - fpidict = getPiDict('#####',hidden=True) - dirpidict = os.path.dirname(fpidict) - fpidict = os.path.basename(fpidict) - #if hostname in fpidict: - # fpidict = fpidict.replace(hostname, shostname+".*") - fpidict = fpidict.replace('#####', '(\d*)') - fnamere = re.compile("^%s" % fpidict) - try: - for f in os.listdir(dirpidict): - mo = fnamere.match(f) - try: - killMyPort(mo.group(1)) - except: - pass - pass - pass - except: - pass - # provide compatibility with old-style pidict file (not dot-prefixed) - #fpidict = getPiDict('(\d*)',hidden=False) - fpidict = getPiDict('#####',hidden=False) - dirpidict = os.path.dirname(fpidict) - fpidict = os.path.basename(fpidict) - #if hostname in fpidict: - # fpidict = fpidict.replace(hostname, shostname+".*") - fpidict = fpidict.replace('#####', '(\d*)') - fnamere = re.compile("^%s$" % fpidict) - try: - for f in os.listdir(dirpidict): - mo = fnamere.match(f) - try: - killMyPort(mo.group(1)) - except: - pass - pass - pass - except: - pass - # kill other processes - for pid in checkUnkilledProcess(): - try: - os.kill(pid, signal.SIGKILL) - except: - pass - pass - if sys.platform != 'win32': - # delete uri files needed by ompi-server - cmd = "rm -f " + os.path.expanduser("~") + "/.urifile_*" - os.system(cmd) - pass - -if __name__ == "__main__": + # detect ports used by SALOME session and kill processes + for hidden in (True, False): + pidict_t = getPiDict(port='#####', hidden=hidden) + dir_pidict_t = osp.dirname(pidict_t) + fn_pidict_t = osp.basename(pidict_t).replace('#####', r'(\d*)') + fn_rex = re.compile('^{}'.format(fn_pidict_t)) + with suppress(IOError): + for fname in os.listdir(dir_pidict_t): + m_res = fn_rex.match(fname) + if m_res: + killMyPort(m_res.group(1)) + + # kill possibly unkilled processes + killUnkilledProcesses() + + # other clean-up actions + # - delete uri files needed by ompi-server + for path in glob(osp.join(osp.expanduser('~'), '.urifile_*')): + with suppress(IOError): + os.remove(path) + +def main(): + """ + Main function + """ + from argparse import ArgumentParser + parser = ArgumentParser(description='Forcibly stop all running SALOME sessions') + parser.parse_args() + try: from salomeContextUtils import setOmniOrbUserPath setOmniOrbUserPath() - except Exception as e: - print(e) + except Exception as exc: # pragma pylint: disable=broad-except + print(exc) sys.exit(1) + killAllPorts() - pass + +if __name__ == '__main__': + main() diff --git a/bin/killSalomeWithPort.py b/bin/killSalomeWithPort.py index 26b959f30..bb9ac64b8 100755 --- a/bin/killSalomeWithPort.py +++ b/bin/killSalomeWithPort.py @@ -22,170 +22,174 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # -## \file killSalomeWithPort.py -# Stop all %SALOME servers from given sessions by killing them +## @file killSalomeWithPort.py +# @brief Forcibly stop %SALOME processes from given session(s). # -# The sessions are indicated by their ports on the command line as in : -# \code +# The sessions are indicated by their ports on the command line as in below example: +# @code # killSalomeWithPort.py 2811 2815 -# \endcode -# +# @endcode + +""" +Forcibly stop given SALOME session(s). + +To stop one or more SALOME sessions, specify network ports they are bound to, +for example: + +* in shell + + $ killSalomeWithPort.py 2811 2815 + +* in Python script: -import re, os, sys, pickle, signal, glob -import subprocess -import shlex -from salome_utils import verbose + from killSalomeWithPort import killMyPort + killMyPort(2811, 2815) +""" -def getPiDict(port,appname='salome',full=True,hidden=True,hostname=None): +# pragma pylint: disable=invalid-name + +import itertools +import os +import os.path as osp +import pickle +import re +import shutil +import sys +from contextlib import suppress +from glob import glob +from threading import Thread +from time import sleep + +import psutil + +from salome_utils import (generateFileName, getHostName, getLogDir, getShortHostName, + getUserName, killOmniNames, killPid, verbose) + +def getPiDict(port, appname='salome', full=True, hidden=True, hostname=None): """ - Get file with list of SALOME processes. + Get path to the file that stores the list of SALOME processes. + This file is located in the user's home directory and named .___SALOME_pidict where - is user name - is host name - is port number - - Parameters: - - port : port number - - appname : application name (default is 'SALOME') - - full : if True, full path to the file is returned, otherwise only file name is returned - - hidden : if True, file name is prefixed with . (dot) symbol; this internal parameter is used - to support compatibility with older versions of SALOME + + - is user name + - is host name + - is port number + + :param port : port number + :param appname : application name (default: 'salome') + :param full : if True, full path to the file is returned, + otherwise only file name is returned + :param hidden : if True, file name is prefixed with . (dot) symbol; + this internal parameter is only used to support + compatibility with older versions of SALOME + :param hostname : host name (if not given, it is auto-detected) + :return pidict file's name or path """ - # bug fix: ensure port is an integer - # Note: this function is also called with port='#####' !!! - try: + # ensure port is an integer + # warning: this function is also called with port='#####'!!! + with suppress(ValueError): port = int(port) - except: - pass - - from salome_utils import generateFileName, getLogDir - dir = "" - if not hostname: - hostname = os.getenv("NSHOST") - if hostname: hostname = hostname.split(".")[0] - pass - if full: - # full path to the pidict file is requested - if hidden: - # new-style dot-prefixed pidict files - # are in the system-dependant temporary directory - dir = getLogDir() - else: - # old-style non-dot-prefixed pidict files - # are in the user's home directory - dir = os.path.expanduser("~") - pass - pass - - return generateFileName(dir, - suffix="pidict", + + # hostname (if not specified via parameter) + with suppress(AttributeError): + hostname = hostname or os.getenv('NSHOST').split('.')[0] + + # directory to store pidict file (if `full` is True) + # old style: pidict files aren't dot-prefixed, stored in the user's home directory + # new style: pidict files are dot-prefixed, stored in the system-dependant temporary directory + pidict_dir = getLogDir() if hidden else osp.expanduser('~') + + return generateFileName(pidict_dir if full else '', + suffix='pidict', hidden=hidden, with_username=True, - with_hostname=hostname or True, + with_hostname=(hostname or True), with_port=port, with_app=appname.upper()) def appliCleanOmniOrbConfig(port): """ - Remove omniorb config files related to the port in SALOME application: + Remove omniorb config files related to given `port` in SALOME application: - ${OMNIORB_USER_PATH}/.omniORB_${USER}_${HOSTNAME}_${NSPORT}.cfg - ${OMNIORB_USER_PATH}/.omniORB_${USER}_last.cfg the last is removed only if the link points to the first file. + :param port : port number """ + omniorb_user_path = os.getenv('OMNIORB_USER_PATH') + if not omniorb_user_path: + # outside application context + return + if verbose(): - print("clean OmniOrb config for port %s"%port) + print("Cleaning OmniOrb config for port {}".format(port)) - from salome_utils import generateFileName, getUserName - omniorbUserPath = os.getenv("OMNIORB_USER_PATH") - if omniorbUserPath is None: - #Run outside application context - pass - else: - omniorb_config = generateFileName(omniorbUserPath, prefix="omniORB", - extension="cfg", - hidden=True, - with_username=True, - with_hostname=True, - with_port=port) - last_running_config = generateFileName(omniorbUserPath, prefix="omniORB", - with_username=True, - suffix="last", - extension="cfg", - hidden=True) - if os.access(last_running_config,os.F_OK): - if not sys.platform == 'win32': - pointedPath = os.readlink(last_running_config) - if pointedPath[0] != '/': - pointedPath=os.path.join(os.path.dirname(last_running_config), pointedPath) - pass - if pointedPath == omniorb_config: - os.unlink(last_running_config) - pass - pass - else: - os.remove(last_running_config) - pass - pass - - if os.access(omniorb_config,os.F_OK): - os.remove(omniorb_config) - pass - - if os.path.lexists(last_running_config):return - - #try to relink last.cfg to an existing config file if any - files = glob.glob(os.path.join(omniorbUserPath,".omniORB_"+getUserName()+"_*.cfg")) - current_config=None - current=0 - for f in files: - stat=os.stat(f) - if stat.st_atime > current: - current=stat.st_atime - current_config=f - if current_config: - if sys.platform == "win32": - import shutil - shutil.copyfile(os.path.normpath(current_config), last_running_config) - pass - else: - os.symlink(os.path.normpath(current_config), last_running_config) - pass - pass - pass - pass - -########## kills all salome processes with the given port ########## + omniorb_config = generateFileName(omniorb_user_path, + prefix='omniORB', + extension='cfg', + hidden=True, + with_username=True, + with_hostname=True, + with_port=port) + last_running_config = generateFileName(omniorb_user_path, + prefix='omniORB', + suffix='last', + extension='cfg', + hidden=True, + with_username=True) + + if os.access(last_running_config, os.F_OK): + if sys.platform == 'win32' or osp.samefile(last_running_config, omniorb_config): + os.remove(last_running_config) + + if os.access(omniorb_config, os.F_OK): + os.remove(omniorb_config) + + if osp.lexists(last_running_config): + return + + # try to relink last.cfg to an existing config file if any + cfg_files = [(cfg_file, os.stat(cfg_file)) for cfg_file in \ + glob(osp.join(omniorb_user_path, + '.omniORB_{}_*.cfg'.format(getUserName())))] + next_config = next((i[0] for i in sorted(cfg_files, key=lambda i: i[1])), None) + if next_config: + if sys.platform == 'win32': + shutil.copyfile(osp.normpath(next_config), last_running_config) + else: + os.symlink(osp.normpath(next_config), last_running_config) def shutdownMyPort(port, cleanup=True): """ Shutdown SALOME session running on the specified port. - Parameters: - - port - port number + :param port : port number + :param cleanup : perform additional cleanup actions (kill omniNames, etc.) """ - if not port: return - # bug fix: ensure port is an integer - port = int(port) + if not port: + return - try: + # ensure port is an integer + with suppress(ValueError): + port = int(port) + + # release port + with suppress(ImportError): + # DO NOT REMOVE NEXT LINE: it tests PortManager availability! from PortManager import releasePort releasePort(port) - except ImportError: - pass - from salome_utils import generateFileName - - # set OMNIORB_CONFIG variable to the proper file - omniorbUserPath = os.getenv("OMNIORB_USER_PATH") + # set OMNIORB_CONFIG variable to the proper file (if not set yet) + omniorb_user_path = os.getenv('OMNIORB_USER_PATH') kwargs = {} - if omniorbUserPath is not None: - kwargs["with_username"]=True + if omniorb_user_path is not None: + kwargs['with_username'] = True else: - omniorbUserPath = os.path.realpath(os.path.expanduser('~')) - omniorb_config = generateFileName(omniorbUserPath, prefix="omniORB", - extension="cfg", + omniorb_user_path = osp.realpath(osp.expanduser('~')) + omniorb_config = generateFileName(omniorb_user_path, + prefix='omniORB', + extension='cfg', hidden=True, with_hostname=True, with_port=port, @@ -194,281 +198,285 @@ def shutdownMyPort(port, cleanup=True): os.environ['NSPORT'] = str(port) # give the chance to the servers to shutdown properly - try: - import time + with suppress(Exception): from omniORB import CORBA - from LifeCycleCORBA import LifeCycleCORBA - # shutdown all orb = CORBA.ORB_init([''], CORBA.ORB_ID) - lcc = LifeCycleCORBA(orb) # see (1) - print("Terminating SALOME on port %s..."%(port)) + lcc = LifeCycleCORBA(orb) # see (1) below + # shutdown all + if verbose(): + print("Terminating SALOME session on port {}...".format(port)) lcc.shutdownServers() # give some time to shutdown to complete - time.sleep(1) + sleep(1) # shutdown omniNames if cleanup: - from salome_utils import killOmniNames - killOmniNames(port) - filedict=getPiDict(port) - __killMyPort(port, filedict) - from PortManager import releasePort - releasePort(port) - time.sleep(1) - pass - pass - except: - pass - sys.exit(0) # see (1) - pass + killOmniNames(port) + __killMyPort(port, getPiDict(port)) + # DO NOT REMOVE NEXT LINE: it tests PortManager availability! + from PortManager import releasePort + releasePort(port) + sleep(1) + sys.exit(0) # see (1) below + # (1) If --shutdown-servers option is set to 1, session close procedure is # called twice: first explicitly by salome command, second by automatic # atexit to handle Ctrl-C. During second call, LCC does not exist anymore and # a RuntimeError is raised; we explicitly exit this function with code 0 to # prevent parent thread from crashing. +def __killProcesses(processes): + ''' + Terminate and kill all given processes (inernal). + :param processes : list of processes, each one is an instance of psutil.Process + ''' + # terminate processes + for process in processes: + process.terminate() + # wait a little, then check for alive + _, alive = psutil.wait_procs(processes, timeout=5) + # finally kill alive + for process in alive: + process.kill() + +def __killPids(pids): + """ + Kill processes with given `pids`. + :param pids : processes IDs + """ + processes = [] + for pid in pids: + try: + processes.append(psutil.Process(pid)) + except psutil.NoSuchProcess: + if verbose(): + print(" ------------------ Process {} not found".format(pid)) + __killProcesses(processes) + def __killMyPort(port, filedict): - # bug fix: ensure port is an integer - if port: + """ + Kill processes for given port (internal). + :param port : port number + :param filedict : pidict file + """ + # ensure port is an integer + with suppress(ValueError): port = int(port) - try: - with open(filedict, 'rb') as fpid: - process_ids=pickle.load(fpid) - for process_id in process_ids: - for pid, cmd in list(process_id.items()): - pid = int(pid) - if verbose(): print("stop process %s : %s"% (pid, cmd[0])) - try: - from salome_utils import killpid - killpid(pid) - except: - if verbose(): print(" ------------------ process %s : %s not found"% (pid, cmd[0])) - if pid in checkUnkilledProcess(): - try: - killpid(pid) - except: - pass - pass - pass # for pid ... - pass # for process_id ... - # end with - except: - print("Cannot find or open SALOME PIDs file for port", port) - pass + # read pids from pidict file + with suppress(Exception), open(filedict, 'rb') as fpid: + pids_lists = pickle.load(fpid) + # note: pids_list is a list of tuples! + for pids in pids_lists: + __killPids(pids) + + # finally remove pidict file os.remove(filedict) - pass -# def __guessPiDictFilename(port): - from salome_utils import getShortHostName, getHostName - filedicts = [ - # new-style dot-prefixed pidict file - getPiDict(port, hidden=True), - # provide compatibility with old-style pidict file (not dot-prefixed) - getPiDict(port, hidden=False), - # provide compatibility with old-style pidict file (short hostname) - getPiDict(port, hidden=True, hostname=getShortHostName()), - # provide compatibility with old-style pidict file (not dot-prefixed, short hostname - getPiDict(port, hidden=False, hostname=getShortHostName()), - # provide compatibility with old-style pidict file (long hostname) - getPiDict(port, hidden=True, hostname=getHostName()), - # provide compatibility with old-style pidict file (not dot-prefixed, long hostname) - getPiDict(port, hidden=False, hostname=getHostName()) - ] - - log_msg = "" - for filedict in filedicts: - log_msg += "Trying %s..."%filedict - if os.path.exists(filedict): - log_msg += " ... OK\n" - break - else: - log_msg += " ... not found\n" - - if verbose(): - print(log_msg) + """ + Guess and return pidict file for given `port` (internal). + :param port : port number + :return pidict file's path + """ + # Check all possible versions of pidict file + # new-style - dot-prefixed pidict file: hidden is True, auto hostname + # old-style - not dot-prefixed pidict file: hidden is False, auto hostname + # old-style - dot-prefixed pidict file: hidden is True, short hostname + # old-style - not dot-prefixed pidict file: hidden is False, short hostname + # old-style - dot-prefixed pidict file: hidden is True, long hostname + # old-style - not dot-prefixed pidict file: hidden is False, long hostname + for hostname, hidden in itertools.product((None, getShortHostName(), getHostName()), + (True, False)): + filedict = getPiDict(port, hidden=hidden, hostname=hostname) + if not osp.exists(filedict): + if verbose(): + print('Trying {}... not found'.format(filedict)) + continue + if verbose(): + print('Trying {}... OK'.format(filedict)) + return filedict - return filedict -# + return None -def killMyPort(port): +def killMyPort(*ports): """ Kill SALOME session running on the specified port. - Parameters: - - port - port number + :param ports : port numbers """ - # bug fix: ensure port is an integer - if port: - port = int(port) - - try: - import PortManager # do not remove! Test for PortManager availability! - filedict = getPiDict(port) - if not os.path.isfile(filedict): # removed by previous call, see (1) - if verbose(): - print("SALOME on port %s: already removed by previous call"%port) - # Remove port from PortManager config file - try: - from PortManager import releasePort + for port in ports: + # ensure port is an integer + with suppress(ValueError): + port = int(port) + + with suppress(Exception): + # DO NOT REMOVE NEXT LINE: it tests PortManager availability! + from PortManager import releasePort + # get pidict file + filedict = getPiDict(port) + if not osp.isfile(filedict): # removed by previous call, see (1) above if verbose(): - print("Removing port from PortManager configuration file") - releasePort(port) - except ImportError: - pass - return - except: - pass - - # try to shutdown session normally - import threading, time - threading.Thread(target=shutdownMyPort, args=(port,True)).start() - time.sleep(3) # wait a little, then kill processes (should be done if shutdown procedure hangs up) - - try: - import PortManager # do not remove! Test for PortManager availability! - filedict = getPiDict(port) - #filedict = __guessPiDictFilename(port) - import glob - all_files = glob.glob("%s*"%filedict) - for f in all_files: - __killMyPort(port, f) - except ImportError: - filedict = __guessPiDictFilename(port) - __killMyPort(port, filedict) - # + print("SALOME session on port {} is already stopped".format(port)) + # remove port from PortManager config file + with suppress(ImportError): + if verbose(): + print("Removing port from PortManager configuration file") + releasePort(port) + return + + # try to shutdown session normally + Thread(target=shutdownMyPort, args=(port, True)).start() + # wait a little... + sleep(3) + # ... then kill processes (should be done if shutdown procedure hangs up) + try: + # DO NOT REMOVE NEXT LINE: it tests PortManager availability! + import PortManager # pragma pylint: disable=unused-import + for file_path in glob('{}*'.format(getPiDict(port))): + __killMyPort(port, file_path) + except ImportError: + __killMyPort(port, __guessPiDictFilename(port)) - appliCleanOmniOrbConfig(port) - pass + # clear-up omniOrb config files + appliCleanOmniOrbConfig(port) def cleanApplication(port): """ Clean application running on the specified port. - Parameters: - - port - port number + :param port : port number """ - # bug fix: ensure port is an integer - if port: + # ensure port is an integer + with suppress(ValueError): port = int(port) - try: - filedict=getPiDict(port) + # remove pidict file + with suppress(Exception): + filedict = getPiDict(port) os.remove(filedict) - except: - #import traceback - #traceback.print_exc() - pass + # clear-up omniOrb config files appliCleanOmniOrbConfig(port) - pass def killMyPortSpy(pid, port): - dt = 1.0 - while 1: - from salome_utils import killpid - ret = killpid(pid, 0) + """ + Start daemon process which watches for given process and kills session when process exits. + :param pid : process ID + :param port : port number (to kill) + """ + while True: + ret = killPid(int(pid), 0) # 0 is used to check process existence without actual killing it if ret == 0: - break + break # process does not exist: exit loop elif ret < 0: - return - from time import sleep - sleep(dt) - pass - filedict = getPiDict(port, hidden=True) - if not os.path.exists(filedict): + return # something got wrong + sleep(1) + + filedict = getPiDict(port) + if not osp.exists(filedict): return + + # check Session server try: import omniORB orb = omniORB.CORBA.ORB_init(sys.argv, omniORB.CORBA.ORB_ID) import SALOME_NamingServicePy - ns = SALOME_NamingServicePy.SALOME_NamingServicePy_i(orb, 3, True) - import SALOME #@UnresolvedImport @UnusedImport - session = ns.Resolve("/Kernel/Session") + naming_service = SALOME_NamingServicePy.SALOME_NamingServicePy_i(orb, 3, True) + import SALOME #@UnresolvedImport @UnusedImport # pragma pylint: disable=unused-import + session = naming_service.Resolve('/Kernel/Session') assert session - except: + except: # pragma pylint: disable=bare-except killMyPort(port) return try: status = session.GetStatSession() - except: - # -- session is in naming service but has crash + except: # pragma pylint: disable=bare-except + # -- session is in naming service but likely crashed status = None - pass - if status: - if not status.activeGUI: - return - pass + if status is not None and not status.activeGUI: + return killMyPort(port) - return - -def checkUnkilledProcess(): - #check processes in system after kill - from salome_utils import getUserName - user = getUserName() - processes = dict() - - if sys.platform != 'win32': - - def _getDictfromOutput(_output, _dic, _cond = None): - _pids = dict(zip(list(map(int, _output[::2])), _output[1::2])) - if _cond: - _pids = {pid:cmd for pid,cmd in _pids.items() if re.match(_cond, cmd)} - _dic.update(_pids) - - # 1. SALOME servers plus omniNames - cmd = 'ps --noheading -U {user} -o pid,cmd | awk \'{{printf("%s %s\\n", $1, $2)}}\''.format(user=user) - _getDictfromOutput(subprocess.getoutput(cmd).split(), processes, '^(SALOME_|omniNames)') - # 2. ghs3d - cmd = 'ps -fea | grep \'{user}\' | grep \'ghs3d\' | grep \'f /tmp/GHS3D_\' | grep -v \'grep\' | awk \'{{printf("%s %s\\n", $2, $8)}}\''.format(user=user) - _getDictfromOutput(subprocess.getoutput(cmd).split(), processes) - # 3. ompi-server - cmd = 'ps -fea | grep \'{user}\' | grep \'ompi-server\' | grep -v \'grep\' | awk \'{{printf("%s %s\\n", $2, $8)}}\''.format(user=user) - _getDictfromOutput(subprocess.getoutput(cmd).split(), processes) - else: - cmd = 'tasklist /fo csv | findstr /i "SALOME_ omniNames"' - prc = subprocess.getoutput(cmd) - try: - prc = prc.split() - prc = [prc[i].split(',') for i in range(0, len(prc)) if i % 2 == 0] - prc = dict([(int(prc[j][1].replace('"', '')), prc[j][0].replace('"', '')) for j in range(0, len(prc))]) - processes.update(prc) - except: - pass + +def __checkUnkilledProcesses(): + ''' + Check all unkilled SALOME processes (internal). + :return: list of unkilled processes + ''' + def _checkUserName(_process): + # The following is a workaround for Windows on which + # psutil.Process().username() returns 'usergroup' + 'username' + return getUserName() == _process.username() + + def _getDictfromOutput(_processes, _wildcard=None): + for _process in psutil.process_iter(['name', 'username']): + with suppress(psutil.AccessDenied): + if _checkUserName(_process) and re.match(_wildcard, _process.info['name']): + _processes.append(_process) + + processes = list() + _getDictfromOutput(processes, '(SALOME_*)') + _getDictfromOutput(processes, '(omniNames)') + _getDictfromOutput(processes, '(ghs3d)') + _getDictfromOutput(processes, '(ompi-server)') + return processes -if __name__ == "__main__": - if len(sys.argv) < 2: - print("Usage: ") - print(" %s " % os.path.basename(sys.argv[0])) - print() - print("Kills SALOME session running on specified .") +def killUnkilledProcesses(): + """ + Kill processes which could remain even after shutdowning SALOME sessions. + """ + __killProcesses(__checkUnkilledProcesses()) + +def main(): + ''' + Main function + ''' + from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter + formatter = lambda prog: ArgumentDefaultsHelpFormatter(prog, max_help_position=50, width=120) + parser = ArgumentParser(description='Forcibly stop given SALOME session(s)', + formatter_class=formatter) + parser.add_argument('ports', + help='ports to kill', + nargs='*', type=int) + group = parser.add_mutually_exclusive_group() + group.add_argument('-s', '--spy', + help='start daemon to watch PID and then kill given PORT', + nargs=2, type=int, metavar=('PID', 'PORT')) + group.add_argument('-l', '--list', + help='list unkilled SALOME processes', + action='store_true') + args = parser.parse_args() + + if args.ports and (args.spy or args.list): + print("{}: error: argument ports cannot be used with -s/--spy or -l/--list" + .format(parser.prog), file=sys.stderr) sys.exit(1) - pass - if sys.argv[1] == "--spy": - if len(sys.argv) > 3: - pid = sys.argv[2] - port = sys.argv[3] - killMyPortSpy(pid, port) - pass + + if args.spy: + killMyPortSpy(*args.spy) sys.exit(0) - pass - elif sys.argv[1] == "--find": - processes = checkUnkilledProcess() + + if args.list: + processes = __checkUnkilledProcesses() if processes: print("Unkilled processes: ") - print(" --------------------") - print(" PID : Process name") - print(" --------------------") - for pair in processes.items(): - print('%6d : %s' % pair) + print("---------------------") + print(" PID : Process name") + print("--------------------") + for process in processes: + print("{0:6} : {1}".format(process.pid, process.name())) + else: + print("No SALOME related processed found") sys.exit(0) + try: from salomeContextUtils import setOmniOrbUserPath #@UnresolvedImport setOmniOrbUserPath() - except Exception as e: - print(e) + except Exception as exc: # pragma pylint: disable=broad-except + if verbose(): + print(exc) sys.exit(1) - for port in sys.argv[1:]: - killMyPort(port) - pass - pass + + killMyPort(*args.ports) + +if __name__ == '__main__': + main() diff --git a/bin/salome_utils.py b/bin/salome_utils.py index ba151eef8..3a5ef383a 100644 --- a/bin/salome_utils.py +++ b/bin/salome_utils.py @@ -1,594 +1,449 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -# - -# --- -# File : salome_utils.py -# Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com) -# --- - -## @package salome_utils -# \brief Set of utility functions used by SALOME python scripts. - -# -# Exported functions -# - -__all__ = [ - 'getORBcfgInfo', - 'getHostFromORBcfg', - 'getPortFromORBcfg', - 'getUserName', - 'getHostName', - 'getShortHostName', - 'getAppName', - 'getPortNumber', - 'getLogDir', - 'getTmpDir', - 'getHomeDir', - 'generateFileName', - 'makeTmpDir', - 'uniteFiles', - ] - -# --- - -def _try_bool( arg ): - """ - Check if specified parameter represents boolean value and returns its value. - String values like 'True', 'TRUE', 'YES', 'Yes', 'y', 'NO', 'false', 'n', etc - are supported. - If does not represent a boolean, an exception is raised. - """ - if isinstance(arg, bool) : - return arg - elif isinstance(arg, (str, bytes)): - v = str( arg ).lower() - if v in [ "yes", "y", "true" ]: return True - elif v in [ "no", "n", "false" ]: return False - pass - raise Exception("Not boolean value") - -# --- - -def getORBcfgInfo(): - """ - Get omniORB current configuration. - Returns a list of three values: [ orb_version, host_name, port_number ]. - - The information is retrieved from the omniORB configuration file defined - by the OMNIORB_CONFIG environment variable. - If omniORB configuration file can not be accessed, a list of three empty - strings is returned. - """ - import os, re - ret = [ "", "", "" ] - try: - f = open( os.getenv( "OMNIORB_CONFIG" ) ) - lines = f.readlines() - f.close() - regvar = re.compile( "(ORB)?InitRef.*corbaname::(.*):(\d+)\s*$" ) - for l in lines: - try: - m = regvar.match( l ) - if m: - if m.group(1) is None: - ret[0] = "4" - else: - ret[0] = "3" - pass - ret[1] = m.group(2) - ret[2] = m.group(3) - break - pass - except: - pass - pass - pass - except: - pass - return ret - -# --- - -def getHostFromORBcfg(): - """ - Get current omniORB host. - """ - return getORBcfgInfo()[1] -# --- - -def getPortFromORBcfg(): - """ - Get current omniORB port. - """ - return getORBcfgInfo()[2] - -# --- - -def getUserName(): - """ - Get user name: - 1. try USER environment variable (USERNAME on windows) - 2. if fails, try LOGNAME (un*x) - 3. if fails return 'unknown' as default user name - """ - import os, sys - if sys.platform == "win32": - return os.getenv("USERNAME", "unknown") - else: - user = os.getenv("USER") - if user: - return user - return os.getenv("LOGNAME", "unknown") -# --- - -def getHostName(): - """ - Get host name: - 1. try socket python module gethostname() function - 2. if fails, try HOSTNAME environment variable - 3. if fails, try HOST environment variable - 4. if fails, return 'unknown' as default host name - """ - try: - import socket - host = socket.gethostname() - except: - host = None - pass - if not host: host = os.getenv("HOSTNAME") - if not host: host = os.getenv("HOST") - if not host: host = "unknown" # 'unknown' is default host name - try: - socket.gethostbyname(host) - except: - host = "localhost" - pass - return host - -# --- - -def getShortHostName(): - """ - Get short host name: - 1. try socket python module gethostname() function - 2. if fails, try HOSTNAME environment variable - 3. if fails, try HOST environment variable - 4. if fails, return 'unknown' as default host name - """ - try: - return getHostName().split('.')[0] - except: - pass - return "unknown" # 'unknown' is default host name - -# --- - -def getAppName(): - """ - Get application name: - 1. try APPNAME environment variable - 2. if fails, return 'SALOME' as default application name - """ - import os - return os.getenv( "APPNAME", "SALOME" ) # 'SALOME' is default user name - -# --- - -def getPortNumber(use_default=True): - """ - Get current naming server port number: - 1. try NSPORT environment variable - 1. if fails, try to parse config file defined by OMNIORB_CONFIG environment variable - 2. if fails, return 2809 as default port number (if use_default is True) or None (id use_default is False) - """ - import os - try: - return int( os.getenv( "NSPORT" ) ) - except: - pass - try: - port = int( getPortFromORBcfg() ) - if port is not None: return port - except: - pass - if use_default: return 2809 # '2809' is default port number - return None - -# --- - -def getHomeDir(): - """ - Get home directory. - """ - import os - return os.path.realpath(os.path.expanduser('~')) -# --- - -def getLogDir(): - """ - Get directory to be used for the log files. - """ - import os - return os.path.join(getTmpDir(), "logs", getUserName()) -# --- - -def getTmpDir(): - """ - Get directory to be used for the temporary files. - """ - import os, tempfile - f = tempfile.NamedTemporaryFile() - tmpdir = os.path.dirname(f.name) - f.close() - return tmpdir -# --- - -def generateFileName( dir, prefix = None, suffix = None, extension = None, - unique = False, separator = "_", hidden = False, **kwargs ): - """ - Generate file name by specified parameters. If necessary, file name - can be generated to be unique. - - Parameters: - - dir : directory path - - prefix : file prefix (not added by default) - - suffix : file suffix (not added by default) - - extension : file extension (not added by default) - - unique : if this parameter is True, the unique file name is generated: - in this case, if the file with the generated name already exists - in the directory, an integer suffix is added to the end of the - file name. This parameter is False by default. - - separator : separator of the words ('_' by default) - - hidden : if this parameter is True, the file name is prepended by . (dot) - symbol. This parameter is False by default. - - Other keyword parameters are: - - with_username : 'add user name' flag/option: - * boolean value can be passed to determine user name automatically - * string value to be used as user name - - with_hostname : 'add host name' flag/option: - * boolean value can be passed to determine host name automatically - * string value to be used as host name - - with_port : 'add port number' flag/option: - * boolean value can be passed to determine port number automatically - * string value to be used as port number - - with_app : 'add application name' flag/option: - * boolean value can be passed to determine application name automatically - * string value to be used as application name - All parameters are optional. - """ - supported = [ 'with_username', 'with_hostname', 'with_port', 'with_app' ] - from launchConfigureParser import verbose - filename = [] - # separator - if separator is None: - separator = "" - pass - else: - separator = str( separator ) - pass - # prefix (if specified) - if prefix is not None: - filename.append( str( prefix ) ) - pass - # additional keywords - ### check unsupported parameters - for kw in kwargs: - if kw not in supported and verbose(): - print('Warning! salome_utilitie.py: generateFileName(): parameter %s is not supported' % kw) - pass - pass - ### process supported keywords - for kw in supported: - if kw not in kwargs: continue - ### user name - if kw == 'with_username': - try: - # auto user name ? - if _try_bool( kwargs[kw] ): filename.append( getUserName() ) - pass - except: - # user name given as parameter - filename.append( kwargs[kw] ) - pass - pass - ### host name - elif kw == 'with_hostname': - try: - # auto host name ? - if _try_bool( kwargs[kw] ): filename.append( getShortHostName() ) - pass - except: - # host name given as parameter - filename.append( kwargs[kw] ) - pass - pass - ### port number - elif kw == 'with_port': - try: - # auto port number ? - if _try_bool( kwargs[kw] ): filename.append( str( getPortNumber() ) ) - pass - except: - # port number given as parameter - filename.append( str( kwargs[kw] ) ) - pass - pass - ### application name - elif kw == 'with_app': - try: - # auto application name ? - if _try_bool( kwargs[kw] ): filename.append( getAppName() ) - pass - except: - # application name given as parameter - filename.append( kwargs[kw] ) - pass - pass - pass - # suffix (if specified) - if suffix is not None: - filename.append( str( suffix ) ) - pass - # raise an exception if file name is empty - if not filename: - raise Exception("Empty file name") - # - if extension is not None and extension.startswith("."): extension = extension[1:] - # - import os - name = separator.join( filename ) - if hidden: name = "." + name # add dot for hidden files - if extension: name = name + "." + str( extension ) # add extension if defined - name = os.path.join( dir, name ) - if unique: - # create unique file name - index = 0 - while os.path.exists( name ): - index = index + 1 - name = separator.join( filename ) + separator + str( index ) - if hidden: name = "." + name # add dot for hidden files - if extension: name = name + "." + str( extension ) # add extension if defined - name = os.path.join( dir, name ) - pass - pass - return os.path.normpath(name) - -# --- - -def makeTmpDir( path, mode=0o777 ): - """ - Make temporary directory with the specified path. - If the directory exists then clear its contents. - - Parameters: - - path : absolute path to the directory to be created. - - mode : access mode - """ - import os - if os.path.exists( path ): - import sys - if sys.platform == "win32": - os.system( "rmdir /S /Q " + '"' + path + '"' ) - os.system( "mkdir " + '"' + path + '"' ) - else: - os.system( "rm -rf " + path + "/*" ) - else: - dirs = path.split("/") - shift1 = shift2 = 0 - if not dirs[0]: shift1 = 1 - if dirs[-1]: shift2 = 1 - for i in range(1+shift1,len(dirs)+shift2): - p = "/".join(dirs[:i]) - try: - os.mkdir(p, mode) - os.chmod(p, mode) - except: - pass - -# --- - -def uniteFiles( src_file, dest_file ): - """ - Unite contents of the source file with contents of the destination file - and put result of the uniting to the destination file. - If the destination file does not exist then the source file is simply - copied to its path. - - Parameters: - - src_file : absolute path to the source file - - dest_file : absolute path to the destination file - """ - import os - - if not os.path.exists( src_file ): - return - pass - - if os.path.exists( dest_file ): - # add a symbol of new line to contents of the destination file (just in case) - dest = open( dest_file, 'r' ) - dest_lines = dest.readlines() - dest.close() - - dest_lines.append( "\n" ) - - dest = open( dest_file, 'w' ) - dest.writelines( dest_lines ) - dest.close() - - import sys - if sys.platform == "win32": - command = "type " + '"' + src_file + '"' + " >> " + '"' + dest_file + '"' - else: - command = "cat " + src_file + " >> " + dest_file - pass - pass - else: - import sys - if sys.platform == "win32": - command = "copy " + '"' + src_file + '"' + " " + '"' + dest_file + '"' + " > nul" - else: - command = "cp " + src_file + " " + dest_file - pass - pass - - os.system( command ) - -# -- - -_verbose = None - -def verbose(): - """ - Get verbosity level. Default verbosity level is specified via the environment variable - SALOME_VERBOSE, e.g.: - [bash %] export SALOME_VERBOSE=1 - The function setVerbose() can be used to change verbosity level explicitly. - """ - global _verbose - # verbose has already been called - if _verbose is not None: - return _verbose - # first time - try: - from os import getenv - _verbose = int(getenv('SALOME_VERBOSE')) - except: - _verbose = 0 - pass - # - return _verbose -# -- - -def setVerbose(level): - """ - Change verbosity level. The function verbose() can be used to get current verbosity level. - """ - global _verbose - _verbose = level - return -# -- - -import signal -def killpid(pid, sig = 9): - """ - Send signal sig to the process by pid. - - Parameters: - - pid : PID of process - - sig : signal for sending - Possible values of signals: - 9 means kill the process - 0 only check existing of the process - NOTE: Other values are not processed on Windows - Returns: - 1 Success - 0 Fail, no such process - -1 Fail, another reason - - """ - if not pid: return - import os, sys - if sig != 0: - if verbose(): print("######## killpid pid = ", pid) - try: - if sys.platform == "win32": - import ctypes - if sig == 0: - # PROCESS_QUERY_INFORMATION (0x0400) Required to retrieve certain information about a process - SYNCHRONIZE = 0x100000 - handle = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, int(pid)) - waitObj = ctypes.windll.kernel32.WaitForSingleObject(handle, 0) - if waitObj: - ret = 1 - ctypes.windll.kernel32.CloseHandle(handle) - else: - ret = 0 - if sig == 9: - # PROCESS_TERMINATE (0x0001) Required to terminate a process using TerminateProcess. - handle = ctypes.windll.kernel32.OpenProcess(0x0001, False, int(pid)) - ret = ctypes.windll.kernel32.TerminateProcess(handle, -1) - ctypes.windll.kernel32.CloseHandle(handle) - pass - pass - else: - # Default: signal.SIGKILL = 9 - os.kill(int(pid),sig) - ret = 1 - pass - pass - except OSError as e: - # errno.ESRCH == 3 is 'No such process' - if e.errno == 3: - ret = 0 - else: - ret = -1 - pass - pass - return ret -# -- - -def getOmniNamesPid(port): - """ - Return OmniNames pid by port number. - """ - import sys,subprocess,re - if sys.platform == "win32": - # Get process list by WMI Command Line Utility(WMIC) - # Output is formatted with each value listed on a separate line and with the name of the property: - # ... - # Caption= - # CommandLine= - # ProcessId= - # - # - # - # Caption= - # CommandLine= - # ProcessId= - # ... - cmd = 'WMIC PROCESS get Caption,Commandline,Processid /VALUE' - proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) - # Get stdout - allProc = proc.communicate()[0].decode() - # find Pid of omniNames - pid = re.findall(r'Caption=.*omniNames.*\n?CommandLine=.*omniNames.*\D%s\D.*\n?ProcessId=(\d*)'%(port),allProc)[0] - else: - cmd = "ps -eo pid,command | grep -v grep | grep -E \"omniNames.*%s\" | awk '{print $1}'"%(port) - proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) - pid = proc.communicate()[0] - pass - - return pid -# -- - -def killOmniNames(port): - """ - Kill OmniNames process by port number. - """ - try: - pid = getOmniNamesPid(port) - if pid: killpid(pid) - except: - pass - pass -# -- +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +## @package salome_utils +# @brief Set of utility functions used by SALOME python scripts. + +""" +Various utilities for SALOME. +""" + +# pragma pylint: disable=invalid-name + +import os +import os.path as osp +import re +import shutil +import socket +import sys +import tempfile +from contextlib import suppress + +import psutil + +def _try_bool(arg): + """ + Convert given `arg` to a boolean value. + String values like 'True', 'TRUE', 'YES', 'Yes', 'y', 'NO', 'false', 'n', etc. + are supported. + If `arg` does not represent a boolean, an exception is raised. + :param arg : value being converted + :return result of conversion: `True` or `False` + """ + if isinstance(arg, bool): + return arg + if isinstance(arg, bytes): + arg = arg.decode('utf-8', errors='ignore') + if isinstance(arg, str): + if arg.lower() in ('yes', 'y', 'true', 't'): + return True + if arg.lower() in ('no', 'n', 'false', 'f'): + return False + raise ValueError('Not a boolean value') + +# --- + +def getORBcfgInfo(): + """ + Get current omniORB configuration. + + The information is retrieved from the omniORB configuration file defined + by the OMNIORB_CONFIG environment variable. + If omniORB configuration file can not be accessed, a tuple of three empty + strings is returned. + + :return tuple of three strings: (orb_version, host_name, port_number) + """ + orb_version = '' + hostname = '' + port_number = '' + with suppress(Exception), open(os.getenv('OMNIORB_CONFIG')) as forb: + regvar = re.compile(r'(ORB)?InitRef.*corbaname::(.*):(\d+)\s*$') + for line in forb.readlines(): + match = regvar.match(line) + if match: + orb_version = '4' if match.group(1) is None else '3' + hostname = match.group(2) + port_number = match.group(3) + break + return orb_version, hostname, port_number + +# --- + +def getHostFromORBcfg(): + """ + Get current omniORB host name. + :return host name + """ + return getORBcfgInfo()[1] + +# --- + +def getPortFromORBcfg(): + """ + Get current omniORB port. + :return port number + """ + return getORBcfgInfo()[2] + +# --- + +def getUserName(): + """ + Get user name. + + The following procedure is perfomed to deduce user name: + 1. try USER (USERNAME on Windows) environment variable. + 2. if (1) fails, try LOGNAME (un*x only). + 3. if (2) fails, return 'unknown' as default user name + + :return user name + """ + return os.getenv('USERNAME', 'unknown') if sys.platform == 'win32' \ + else os.getenv('USER', os.getenv('LOGNAME', 'unknown')) + +# --- + +def getHostName(): + """ + Get host name. + + The following procedure is perfomed to deduce host name: + 1. try socket python module, gethostname() function + 2. if (1) fails, try HOSTNAME environment variable + 3. if (2) fails, try HOST environment variable + 4. if (3) fails, tries 'unknown' as default host name + 5. finally, checks that IP is configured for hostname; if not, returns 'localhost' + + :return host name + """ + host = None + with suppress(Exception): + host = socket.gethostname() + if not host: + host = os.getenv('HOSTNAME', os.getenv('HOST', 'unknown')) + try: + # the following line just checks that IP is configured for hostname + socket.gethostbyname(host) + except (TypeError, OSError): + host = 'localhost' + return host + +# --- + +def getShortHostName(): + """ + Get short host name (with domain stripped). + See `getHostName()` for more details. + :return short host name + """ + with suppress(AttributeError, IndexError): + return getHostName().split('.')[0] + return 'unknown' # default host name + +# --- + +def getAppName(): + """ + Get application name. + The following procedure is perfomed to deduce application name: + 1. try APPNAME environment variable + 2. if (1) fails, return 'SALOME' as default application name + :return application name + """ + return os.getenv('APPNAME', 'SALOME') # 'SALOME' is default user name + +# --- + +def getPortNumber(use_default=True): + """ + Get currently used omniORB port. + The following procedure is perfomed to deduce port number: + 1. try NSPORT environment variable + 2. if (1) fails, try to parse config file defined by OMNIORB_CONFIG environment variable + 3. if (2) fails, return 2809 as default port number (if use_default is `True`) or `None` + (if use_default is `False`) + :return port number + """ + with suppress(TypeError, ValueError): + return int(os.getenv('NSPORT')) + with suppress(TypeError, ValueError): + port = int(getPortFromORBcfg()) + if port: + return port + return 2809 if use_default else None + +# --- + +def getHomeDir(): + """ + Get home directory. + :return home directory path + """ + return osp.realpath(osp.expanduser('~')) + +# --- + +def getLogDir(): + """ + Get directory that stores log files. + :return path to the log directory + """ + return osp.join(getTmpDir(), 'logs', getUserName()) + +# --- + +def getTmpDir(): + """ + Get directory to store temporary files. + :return temporary directory path + """ + with tempfile.NamedTemporaryFile() as tmp: + return osp.dirname(tmp.name) + return None + +# --- + +# pragma pylint: disable=too-many-arguments +def generateFileName(path, prefix=None, suffix=None, extension=None, + unique=False, separator='_', hidden=False, **kwargs): + """ + Generate file name. + + :param path : directory path + :param prefix : file name prefix (none by default) + :param suffix : file name suffix (none by default) + :param extension : file extension (none by default) + :param unique : if `True`, function generates unique file name - + in this case, if file with the generated name already + exists in `path` directory, an integer suffix is appended + to the file name (`False` by default) + :param separator : words separator ('_' by default) + :param hidden : if `True`, file name is prepended with dot symbol + (`False` by default) + :param kwargs : additional keywrods arguments (see below) + :return generated file name + + Additionally supported keyword parameters: + - with_username : use user name: + - with_hostname : use host name: + - with_port : use port number: + - with_app : use application name: + + Any of these keyword arguments can accept either explicit string value, + or `True` to automatically deduce value from current configuration. + """ + filename = [] + + def _with_str(_str): + _str = '' if _str is None else str(_str) + if _str: + filename.append(_str) + + def _with_kwarg(_kwarg, _func): + _value = kwargs.get(_kwarg, False) + try: + if _try_bool(_value): + filename.append(str(_func())) + except ValueError: + _with_str(_value) + + _with_str(prefix) + _with_kwarg('with_username', getUserName) + _with_kwarg('with_hostname', getShortHostName) + _with_kwarg('with_port', getPortNumber) + _with_kwarg('with_app', getAppName) + _with_str(suffix) + + # raise an exception if file name is empty + if not filename: + raise ValueError('Empty file name') + + # extension + extension = '' if extension is None else str(extension) + if extension.startswith('.'): + extension = extension[1:] + + # separator + separator = '' if separator is None else str(separator) + + def _generate(_index=None): + # join all components together, add index if necessary + if _index is not None: + _name = separator.join(filename+[str(_index)]) + else: + _name = separator.join(filename) + # prepend with dot if necessary + if hidden: + _name = '.' + _name + # append extension if ncessary + if extension: + _name = _name + '.' + extension + # now get full path + return osp.join(path, _name) + + name = _generate() + if unique: + index = 0 + while osp.exists(name): + index = index + 1 + name = _generate(index) + return osp.normpath(name) + +# --- + +def cleanDir(path): + """ + Clear contents of directory. + :param path directory path + """ + if osp.exists(path): + for filename in os.listdir(path): + file_path = osp.join(path, filename) + with suppress(OSError): + if osp.isdir(file_path): + shutil.rmtree(file_path) + else: + os.unlink(file_path) + +# --- + +def makeTmpDir(path, mode=0o777): + """ + Make temporary directory with the specified path. + If the directory exists, clear all its contents. + :param path : directory path + :param mode : access mode + """ + with suppress(OSError): + os.makedirs(path, mode=mode, exist_ok=True) + cleanDir(path) + +# --- + +def uniteFiles(src_file, dest_file): + """ + Join contents of `src_file` and `dest_file` and put result to `dest_file`. + File `dest_file` may not exist. + :param src_file : source file path + :param dest_file : destination file path + """ + if not osp.exists(src_file): + return + + if osp.exists(dest_file): + with suppress(OSError), open(src_file, 'rb') as src, open(dest_file, 'ab') as dest: + dest.write(b'\n') + dest.write(src.read()) + else: + with suppress(OSError): + shutil.copy(src_file, dest_file) + +# -- + +def verbose(): + """ + Get current verbosity level. + + Default verbosity level is specified via the environment variable SALOME_VERBOSE, + e.g. in bash: + + $ export SALOME_VERBOSE=1 + + The function `setVerbose()` can be used to explicitly set verbosity level. + + :return current verbosity level + """ + if not hasattr(verbose, 'verbosity_level'): + verbose.verbosity_level = 0 # default value + with suppress(TypeError, ValueError): + # from SALOME_VERBOSE environment variable + verbose.verbosity_level = int(os.getenv('SALOME_VERBOSE', '0')) + return verbose.verbosity_level +# -- + +def setVerbose(level): + """ + Change verbosity level. + The function `verbose()` can be used to get current verbosity level. + :param level : verbosity level + """ + with suppress(TypeError, ValueError): + verbose.verbosity_level = int(level) +# -- + +def killPid(pid, sig=9): + """ + Send signal `sig` to the process with given `pid`. + + :param pid : PID of the process + :param sig : signal to send; some of possible values: + - 9 : kill process + - 0 : do nothing, just check process existence (see below) + NOTE: other values are not processed on Windows + :return result of execution: + - 1 : success + - 0 : fail, no such process + - -1 : fail, another reason + """ + if not pid: + return -1 + + with suppress(ValueError): + pid = int(pid) + + if sig == 0: + ret = 1 if psutil.pid_exists(pid) else 0 + else: + if verbose(): + print("######## killPid pid = ", pid) + try: + process = psutil.Process(pid) + process.terminate() + _, alive = psutil.wait_procs([process], timeout=5) + for proc in alive: + proc.kill() + ret = 1 + except psutil.NoSuchProcess: + ret = 0 + except OSError: + ret = -1 + return ret +# -- + +def getOmniNamesPid(port): + """ + Get PID of omniNames process running on given `port`. + :param port : port number + :return omniNames process's PID + """ + processes = {p.info['pid']: p.info['name'] for p in psutil.process_iter(['pid', 'name'])} + return next((c.pid for c in psutil.net_connections(kind='inet') \ + if c.laddr.port == port and processes.get(c.pid) == 'omniNames'), None) +# -- + +def killOmniNames(port): + """ + Kill omniNames process running on given `port`. + :param port : port number + """ + with suppress(Exception): + killPid(getOmniNamesPid(port)) +# -- diff --git a/bin/server.py b/bin/server.py index ac1ebcef2..29c9334f9 100644 --- a/bin/server.py +++ b/bin/server.py @@ -1,145 +1,145 @@ -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE -# -# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -# - -import os, sys, string -from salome_utils import getHostName -process_id = {} - -# ----------------------------------------------------------------------------- -# -# Definition des classes d'objets pour le lancement des Server CORBA -# - -class Server: - """Generic class for CORBA server launch""" - - server_launch_mode = "daemon" - - def initArgs(self): - self.PID=None - self.CMD=[] - self.ARGS=[] - if self.args.get('xterm'): - if sys.platform != "win32": - self.ARGS=['xterm', '-iconic', '-sb', '-sl', '500', '-hold'] - else: - self.ARGS=['cmd', '/c', 'start cmd.exe', '/K'] - - def __init__(self,args): - self.args=args - self.initArgs() - - @staticmethod - def set_server_launch_mode(mode): - if mode == "daemon" or mode == "fork": - Server.server_launch_mode = mode - else: - raise Exception("Unsupported server launch mode: %s" % mode) - - def run(self, daemon=False): - global process_id - myargs=self.ARGS - if self.args.get('xterm'): - # (Debian) send LD_LIBRARY_PATH to children shells (xterm) - if sys.platform == "darwin": - env_ld_library_path=['env', 'DYLD_LIBRARY_PATH=' - + os.getenv("DYLD_FALLBACK_LIBRARY_PATH")] - myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path - elif sys.platform != "win32": - env_ld_library_path=['env', 'LD_LIBRARY_PATH=' - + os.getenv("LD_LIBRARY_PATH")] - myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path - command = myargs + self.CMD - # print("command = ", command) - if sys.platform == "win32": - import subprocess - if daemon: - DETACHED_PROCESS = 0x00000008 - pid = subprocess.Popen(command, creationflags=DETACHED_PROCESS).pid - else: - pid = subprocess.Popen(command).pid - elif Server.server_launch_mode == "fork": - pid = os.spawnvp(os.P_NOWAIT, command[0], command) - else: # Server launch mode is daemon - pid=self.daemonize(command) - if pid is not None: - #store process pid if it really exists - process_id[pid]=self.CMD - self.PID = pid - return pid - - def daemonize(self,args): - # to daemonize a process need to do the UNIX double-fork magic - # see Stevens, "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) - # and UNIX Programming FAQ 1.7 How do I get my program to act like a daemon? - # http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 - #open a pipe - c2pread, c2pwrite = os.pipe() - #do first fork - pid=os.fork() - if pid > 0: - #first parent - os.close(c2pwrite) - #receive real pid from child - data=os.read(c2pread,24) #read 24 bytes - os.waitpid(pid,0) #remove zombie - os.close(c2pread) - # return : first parent - childpid=int(data) - if childpid==-1: - return None - try: - os.kill(childpid,0) - return childpid - except: - return None - - #first child - # decouple from parent environment - os.setsid() - os.close(c2pread) - - # do second fork : second child not a session leader - try: - pid = os.fork() - if pid > 0: - #send real pid to parent - pid_str = "%d" % pid - os.write(c2pwrite,pid_str.encode()) - os.close(c2pwrite) - # exit from second parent - os._exit(0) - except OSError as e: - print("fork #2 failed: %d (%s)" % (e.errno, e.strerror), file=sys.stderr) - os.write(c2pwrite,"-1") - os.close(c2pwrite) - sys.exit(1) - - #I am a daemon - os.close(0) #close stdin - os.open("/dev/null", os.O_RDWR) # redirect standard input (0) to /dev/null - try: - os.execvp(args[0], args) - except OSError as e: - print("(%s) launch failed: %d (%s)" % (args[0],e.errno, e.strerror), file=sys.stderr) - os._exit(127) +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE +# +# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +import os, sys, string +from salome_utils import getHostName +process_id = {} + +# ----------------------------------------------------------------------------- +# +# Definition des classes d'objets pour le lancement des Server CORBA +# + +class Server: + """Generic class for CORBA server launch""" + + server_launch_mode = "daemon" + + def initArgs(self): + self.PID=None + self.CMD=[] + self.ARGS=[] + if self.args.get('xterm'): + if sys.platform != "win32": + self.ARGS=['xterm', '-iconic', '-sb', '-sl', '500', '-hold'] + else: + self.ARGS=['cmd', '/c', 'start cmd.exe', '/K'] + + def __init__(self,args): + self.args=args + self.initArgs() + + @staticmethod + def set_server_launch_mode(mode): + if mode == "daemon" or mode == "fork": + Server.server_launch_mode = mode + else: + raise Exception("Unsupported server launch mode: %s" % mode) + + def run(self, daemon=False): + global process_id + myargs=self.ARGS + if self.args.get('xterm'): + # (Debian) send LD_LIBRARY_PATH to children shells (xterm) + if sys.platform == "darwin": + env_ld_library_path=['env', 'DYLD_LIBRARY_PATH=' + + os.getenv("DYLD_FALLBACK_LIBRARY_PATH")] + myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path + elif sys.platform != "win32": + env_ld_library_path=['env', 'LD_LIBRARY_PATH=' + + os.getenv("LD_LIBRARY_PATH")] + myargs = myargs +['-T']+self.CMD[:1]+['-e'] + env_ld_library_path + command = myargs + self.CMD + # print("command = ", command) + if sys.platform == "win32": + import subprocess + if daemon: + DETACHED_PROCESS = 0x00000008 + pid = subprocess.Popen(command, creationflags=DETACHED_PROCESS).pid + else: + pid = subprocess.Popen(command).pid + elif Server.server_launch_mode == "fork": + pid = os.spawnvp(os.P_NOWAIT, command[0], command) + else: # Server launch mode is daemon + pid=self.daemonize(command) + if pid is not None: + #store process pid if it really exists + process_id[pid]=self.CMD + self.PID = pid + return pid + + def daemonize(self,args): + # to daemonize a process need to do the UNIX double-fork magic + # see Stevens, "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) + # and UNIX Programming FAQ 1.7 How do I get my program to act like a daemon? + # http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 + #open a pipe + c2pread, c2pwrite = os.pipe() + #do first fork + pid=os.fork() + if pid > 0: + #first parent + os.close(c2pwrite) + #receive real pid from child + data=os.read(c2pread,24) #read 24 bytes + os.waitpid(pid,0) #remove zombie + os.close(c2pread) + # return : first parent + childpid=int(data) + if childpid==-1: + return None + try: + os.kill(childpid,0) + return childpid + except: + return None + + #first child + # decouple from parent environment + os.setsid() + os.close(c2pread) + + # do second fork : second child not a session leader + try: + pid = os.fork() + if pid > 0: + #send real pid to parent + pid_str = "%d" % pid + os.write(c2pwrite,pid_str.encode()) + os.close(c2pwrite) + # exit from second parent + os._exit(0) + except OSError as e: + print("fork #2 failed: %d (%s)" % (e.errno, e.strerror), file=sys.stderr) + os.write(c2pwrite,"-1") + os.close(c2pwrite) + sys.exit(1) + + #I am a daemon + os.close(0) #close stdin + os.open("/dev/null", os.O_RDWR) # redirect standard input (0) to /dev/null + try: + os.execvp(args[0], args) + except OSError as e: + print("(%s) launch failed: %d (%s)" % (args[0],e.errno, e.strerror), file=sys.stderr) + os._exit(127) diff --git a/src/NamingService/SALOME_NamingServicePy.py b/src/NamingService/SALOME_NamingServicePy.py index 7228423df..32455869f 100644 --- a/src/NamingService/SALOME_NamingServicePy.py +++ b/src/NamingService/SALOME_NamingServicePy.py @@ -1,313 +1,313 @@ -#! /usr/bin/env python3 -# -*- coding: iso-8859-1 -*- -# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE -# -# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, -# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# -# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com -# - -# SALOME NamingService : wrapping NamingService services -# File : SALOME_NamingServicePy.py -# Author : Estelle Deville, CEA -# Module : SALOME -# $Header$ -## @package SALOME_NamingServicePy -# \brief Module to manage SALOME naming service from python -# -import sys -import time -from omniORB import CORBA -import CosNaming -import string -from string import * - -from SALOME_utilities import * -#============================================================================= - -class SALOME_NamingServicePy_i(object): - """ - A class to manage SALOME naming service from python code - """ - _orb = None - _root_context=None - _current_context=None - _obj=None - - #------------------------------------------------------------------------- - - def __init__(self, orb=None, steps=240, spy=False): - """ - Standard Constructor, with ORB reference. - - Initializes the naming service root context - """ - #MESSAGE ( "SALOME_NamingServicePy_i::__init__" ) - if orb is None: - orb=CORBA.ORB_init([''], CORBA.ORB_ID) - self._orb = orb - # initialize root context and current context - ok = 0 - while steps > 0 and ok == 0: - try: - obj =self._orb.resolve_initial_references("NameService") - self._root_context =obj._narrow(CosNaming.NamingContext) - self._current_context = self._root_context - - - if self._root_context is None : - #MESSAGE ( "Name Service Reference is invalid" ) - #sys.exit(1) - MESSAGE(" Name service not found") - else: - ok = 1 - except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): - MESSAGE(" Name service not found") - time.sleep(0.25) - steps = steps - 1 - if steps == 0 and self._root_context is None: - MESSAGE ( "Name Service Reference is invalid" ) - if spy: - raise ValueError("Name Service Reference is invalid") - else: - sys.exit(1) - - #------------------------------------------------------------------------- - - def Register(self,ObjRef, Path): - """ ns.Register(object,pathname ) - - register a CORBA object under a pathname - """ - - MESSAGE ( "SALOME_NamingServicePy_i::Register" ) - _not_exist = 0 - path_list = list(Path) - if path_list[0]=='/': - self._current_context = self._root_context - #delete first '/' before split - Path=Path[1:] - - result_resolve_path = Path.split('/') - if len(result_resolve_path)>1: - # A directory is treated (not only an object name) - # We had to test if the directory where ObjRef should be recorded - # is already done - # If not, the new context has to be created - _context_name = [] - for i in range(len(result_resolve_path)-1): - _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir")) - - try: - obj = self._current_context.resolve(_context_name) - self._current_context = obj._narrow(CosNaming.NamingContext) - except CosNaming.NamingContext.NotFound as ex: - _not_exist = 1 - except CosNaming.NamingContext.InvalidName as ex: - MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" ) - except CosNaming.NamingContext.CannotProceed as ex: - MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" ) - except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): - MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) - - if _not_exist: - # at least one context of the complete path is not created, we had - # to create it or them - _context_name = [] - for i in range(len(result_resolve_path)-1): - _context_name = [CosNaming.NameComponent(result_resolve_path[i],"dir")] - - try: - obj = self._current_context.resolve(_context_name) - self._current_context = obj._narrow(CosNaming.NamingContext) - except CosNaming.NamingContext.NotFound as ex: - #This context is not created. It will be done - self._current_context = self._current_context.bind_new_context(_context_name) - - #The current directory is now the directory where the object should - #be recorded - - _context_name = [CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object")] - try: - self._current_context.bind(_context_name,ObjRef) - except CosNaming.NamingContext.NotFound as ex: - MESSAGE ( "Register : CosNaming.NamingContext.NotFound" ) - except CosNaming.NamingContext.InvalidName as ex: - MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" ) - except CosNaming.NamingContext.CannotProceed as ex: - MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" ) - except CosNaming.NamingContext.AlreadyBound as ex: - MESSAGE ( "Register : CosNaming.NamingContext.AlreadyBound, object will be rebind" ) - self._current_context.rebind(_context_name,ObjRef) - except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): - MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) - - #------------------------------------------------------------------------- - - def Resolve(self, Path): - """ ns.Resolve(pathname) -> object - - find a CORBA object (ior) by its pathname - """ - #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" ) - path_list = list(Path) - if path_list[0]=='/': - self._current_context = self._root_context - #delete first '/' before split - Path=Path[1:] - - result_resolve_path = Path.split('/') - _context_name=[] - for i in range(len(result_resolve_path)-1): - _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir")) - _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object")) - try: - self._obj = self._current_context.resolve(_context_name) - except CosNaming.NamingContext.NotFound as ex: - MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" ) - self._obj = None - except CosNaming.NamingContext.InvalidName as ex: - MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" ) - self._obj = None - except CosNaming.NamingContext.CannotProceed as ex: - MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" ) - self._obj = None - except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): - MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) - self._obj = None - return self._obj - - #------------------------------------------------------------------------- - - def Resolve_Dir(self, Path): - """ ns.Resolve_Dir(pathname) -> dir - - find a CORBA object (ior) by its pathname - """ - #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" ) - path_list = list(Path) - if path_list[0]=='/': - self._current_context = self._root_context - #delete first '/' before split - Path=Path[1:] - - result_resolve_path = Path.split('/') - _context_name=[] - for i in range(len(result_resolve_path)-1): - _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir")) - _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"dir")) - print(_context_name) - return None - try: - self._obj = self._current_context.resolve(_context_name) - except CosNaming.NamingContext.NotFound as ex: - MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" ) - self._obj = None - except CosNaming.NamingContext.InvalidName as ex: - MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" ) - self._obj = None - except CosNaming.NamingContext.CannotProceed as ex: - MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" ) - self._obj = None - except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): - MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) - self._obj = None - return self._obj - - - #------------------------------------------------------------------------- - - def Create_Directory(self,ObjRef, Path): - """ ns.Create_Directory(ObjRef, Path) - - create a sub directory - """ - MESSAGE ( "SALOME_NamingServicePy_i::Create_Directory" ) - _not_exist = 0 - path_list = list(Path) - if path_list[0]=='/': - self._current_context = self._root_context - #delete first '/' before split - Path=Path[1:] - - result_resolve_path = Path.split('/') - _context_name = [] - for i in range(len(result_resolve_path)): - _context_name[CosNaming.NameComponent(result_resolve_path[i],"dir")] - try: - obj = self._current_context.resolve(_context_name) - self._current_context = obj._narrow(CosNaming.NamingContext) - except CosNaming.NamingContext.NotFound as ex: - self._current_context = self._current_context.bind_new_context(_context_name) - except CosNaming.NamingContext.InvalidName as ex: - MESSAGE ( "Create_Directory : CosNaming.NamingContext.InvalidName" ) - except CosNaming.NamingContext.CannotProceed as ex: - MESSAGE ( "Create_Directory : CosNaming.NamingContext.CannotProceed" ) - except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): - MESSAGE ( "Create_Directory : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) - - def Destroy_Name(self,Path): - """ ns.Destroy_Name(Path) - - remove a name in naming service - """ - resolve_path=Path.split('/') - if resolve_path[0] == '': del resolve_path[0] - dir_path=resolve_path[:-1] - context_name=[] - for e in dir_path: - context_name.append(CosNaming.NameComponent(e,"dir")) - context_name.append(CosNaming.NameComponent(resolve_path[-1],"object")) - - try: - self._root_context.unbind(context_name) - except CosNaming.NamingContext.NotFound as ex: - return - except CORBA.Exception as ex: - return - - def Destroy_FullDirectory(self,Path): - """ ns.Destroy_FullDirectory(Path) - - remove recursively a directory - """ - context_name=[] - for e in Path.split('/'): - if e == '':continue - context_name.append(CosNaming.NameComponent(e,"dir")) - - try: - context=self._root_context.resolve(context_name) - except CosNaming.NamingContext.NotFound as ex: - return - except CORBA.Exception as ex: - return - - bl,bi=context.list(0) - if bi is not None: - ok,b=bi.next_one() - while(ok): - for s in b.binding_name : - if s.kind == "object": - context.unbind([s]) - elif s.kind == "dir": - context.unbind([s]) - ok,b=bi.next_one() - - context.destroy() - self._root_context.unbind(context_name) +#! /usr/bin/env python3 +# -*- coding: iso-8859-1 -*- +# Copyright (C) 2007-2020 CEA/DEN, EDF R&D, OPEN CASCADE +# +# Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +# CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +# SALOME NamingService : wrapping NamingService services +# File : SALOME_NamingServicePy.py +# Author : Estelle Deville, CEA +# Module : SALOME +# $Header$ +## @package SALOME_NamingServicePy +# \brief Module to manage SALOME naming service from python +# +import sys +import time +from omniORB import CORBA +import CosNaming +import string +from string import * + +from SALOME_utilities import * +#============================================================================= + +class SALOME_NamingServicePy_i(object): + """ + A class to manage SALOME naming service from python code + """ + _orb = None + _root_context=None + _current_context=None + _obj=None + + #------------------------------------------------------------------------- + + def __init__(self, orb=None, steps=240, spy=False): + """ + Standard Constructor, with ORB reference. + + Initializes the naming service root context + """ + #MESSAGE ( "SALOME_NamingServicePy_i::__init__" ) + if orb is None: + orb=CORBA.ORB_init([''], CORBA.ORB_ID) + self._orb = orb + # initialize root context and current context + ok = 0 + while steps > 0 and ok == 0: + try: + obj =self._orb.resolve_initial_references("NameService") + self._root_context =obj._narrow(CosNaming.NamingContext) + self._current_context = self._root_context + + + if self._root_context is None : + #MESSAGE ( "Name Service Reference is invalid" ) + #sys.exit(1) + MESSAGE(" Name service not found") + else: + ok = 1 + except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): + MESSAGE(" Name service not found") + time.sleep(0.25) + steps = steps - 1 + if steps == 0 and self._root_context is None: + MESSAGE ( "Name Service Reference is invalid" ) + if spy: + raise ValueError("Name Service Reference is invalid") + else: + sys.exit(1) + + #------------------------------------------------------------------------- + + def Register(self,ObjRef, Path): + """ ns.Register(object,pathname ) + + register a CORBA object under a pathname + """ + + MESSAGE ( "SALOME_NamingServicePy_i::Register" ) + _not_exist = 0 + path_list = list(Path) + if path_list[0]=='/': + self._current_context = self._root_context + #delete first '/' before split + Path=Path[1:] + + result_resolve_path = Path.split('/') + if len(result_resolve_path)>1: + # A directory is treated (not only an object name) + # We had to test if the directory where ObjRef should be recorded + # is already done + # If not, the new context has to be created + _context_name = [] + for i in range(len(result_resolve_path)-1): + _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir")) + + try: + obj = self._current_context.resolve(_context_name) + self._current_context = obj._narrow(CosNaming.NamingContext) + except CosNaming.NamingContext.NotFound as ex: + _not_exist = 1 + except CosNaming.NamingContext.InvalidName as ex: + MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" ) + except CosNaming.NamingContext.CannotProceed as ex: + MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" ) + except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): + MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) + + if _not_exist: + # at least one context of the complete path is not created, we had + # to create it or them + _context_name = [] + for i in range(len(result_resolve_path)-1): + _context_name = [CosNaming.NameComponent(result_resolve_path[i],"dir")] + + try: + obj = self._current_context.resolve(_context_name) + self._current_context = obj._narrow(CosNaming.NamingContext) + except CosNaming.NamingContext.NotFound as ex: + #This context is not created. It will be done + self._current_context = self._current_context.bind_new_context(_context_name) + + #The current directory is now the directory where the object should + #be recorded + + _context_name = [CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object")] + try: + self._current_context.bind(_context_name,ObjRef) + except CosNaming.NamingContext.NotFound as ex: + MESSAGE ( "Register : CosNaming.NamingContext.NotFound" ) + except CosNaming.NamingContext.InvalidName as ex: + MESSAGE ( "Register : CosNaming.NamingContext.InvalidName" ) + except CosNaming.NamingContext.CannotProceed as ex: + MESSAGE ( "Register : CosNaming.NamingContext.CannotProceed" ) + except CosNaming.NamingContext.AlreadyBound as ex: + MESSAGE ( "Register : CosNaming.NamingContext.AlreadyBound, object will be rebind" ) + self._current_context.rebind(_context_name,ObjRef) + except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): + MESSAGE ( "Register : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) + + #------------------------------------------------------------------------- + + def Resolve(self, Path): + """ ns.Resolve(pathname) -> object + + find a CORBA object (ior) by its pathname + """ + #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" ) + path_list = list(Path) + if path_list[0]=='/': + self._current_context = self._root_context + #delete first '/' before split + Path=Path[1:] + + result_resolve_path = Path.split('/') + _context_name=[] + for i in range(len(result_resolve_path)-1): + _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir")) + _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"object")) + try: + self._obj = self._current_context.resolve(_context_name) + except CosNaming.NamingContext.NotFound as ex: + MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" ) + self._obj = None + except CosNaming.NamingContext.InvalidName as ex: + MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" ) + self._obj = None + except CosNaming.NamingContext.CannotProceed as ex: + MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" ) + self._obj = None + except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): + MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) + self._obj = None + return self._obj + + #------------------------------------------------------------------------- + + def Resolve_Dir(self, Path): + """ ns.Resolve_Dir(pathname) -> dir + + find a CORBA object (ior) by its pathname + """ + #MESSAGE ( "SALOME_NamingServicePy_i::Resolve" ) + path_list = list(Path) + if path_list[0]=='/': + self._current_context = self._root_context + #delete first '/' before split + Path=Path[1:] + + result_resolve_path = Path.split('/') + _context_name=[] + for i in range(len(result_resolve_path)-1): + _context_name.append(CosNaming.NameComponent(result_resolve_path[i],"dir")) + _context_name.append(CosNaming.NameComponent(result_resolve_path[len(result_resolve_path)-1],"dir")) + print(_context_name) + return None + try: + self._obj = self._current_context.resolve(_context_name) + except CosNaming.NamingContext.NotFound as ex: + MESSAGE ( "Resolve : CosNaming.NamingContext.NotFound" ) + self._obj = None + except CosNaming.NamingContext.InvalidName as ex: + MESSAGE ( "Resolve : CosNaming.NamingContext.InvalidName" ) + self._obj = None + except CosNaming.NamingContext.CannotProceed as ex: + MESSAGE ( "Resolve : CosNaming.NamingContext.CannotProceed" ) + self._obj = None + except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): + MESSAGE ( "Resolve : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) + self._obj = None + return self._obj + + + #------------------------------------------------------------------------- + + def Create_Directory(self,ObjRef, Path): + """ ns.Create_Directory(ObjRef, Path) + + create a sub directory + """ + MESSAGE ( "SALOME_NamingServicePy_i::Create_Directory" ) + _not_exist = 0 + path_list = list(Path) + if path_list[0]=='/': + self._current_context = self._root_context + #delete first '/' before split + Path=Path[1:] + + result_resolve_path = Path.split('/') + _context_name = [] + for i in range(len(result_resolve_path)): + _context_name[CosNaming.NameComponent(result_resolve_path[i],"dir")] + try: + obj = self._current_context.resolve(_context_name) + self._current_context = obj._narrow(CosNaming.NamingContext) + except CosNaming.NamingContext.NotFound as ex: + self._current_context = self._current_context.bind_new_context(_context_name) + except CosNaming.NamingContext.InvalidName as ex: + MESSAGE ( "Create_Directory : CosNaming.NamingContext.InvalidName" ) + except CosNaming.NamingContext.CannotProceed as ex: + MESSAGE ( "Create_Directory : CosNaming.NamingContext.CannotProceed" ) + except (CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE): + MESSAGE ( "Create_Directory : CORBA.TRANSIENT,CORBA.OBJECT_NOT_EXIST,CORBA.COMM_FAILURE" ) + + def Destroy_Name(self,Path): + """ ns.Destroy_Name(Path) + + remove a name in naming service + """ + resolve_path=Path.split('/') + if resolve_path[0] == '': del resolve_path[0] + dir_path=resolve_path[:-1] + context_name=[] + for e in dir_path: + context_name.append(CosNaming.NameComponent(e,"dir")) + context_name.append(CosNaming.NameComponent(resolve_path[-1],"object")) + + try: + self._root_context.unbind(context_name) + except CosNaming.NamingContext.NotFound as ex: + return + except CORBA.Exception as ex: + return + + def Destroy_FullDirectory(self,Path): + """ ns.Destroy_FullDirectory(Path) + + remove recursively a directory + """ + context_name=[] + for e in Path.split('/'): + if e == '':continue + context_name.append(CosNaming.NameComponent(e,"dir")) + + try: + context=self._root_context.resolve(context_name) + except CosNaming.NamingContext.NotFound as ex: + return + except CORBA.Exception as ex: + return + + bl,bi=context.list(0) + if bi is not None: + ok,b=bi.next_one() + while(ok): + for s in b.binding_name : + if s.kind == "object": + context.unbind([s]) + elif s.kind == "dir": + context.unbind([s]) + ok,b=bi.next_one() + + context.destroy() + self._root_context.unbind(context_name)