From: Viktor UZLOV Date: Tue, 27 Oct 2020 09:21:59 +0000 (+0300) Subject: implementation with psutil X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=e048abb0b8fbffb03c61a7e494f643e6372485d8;p=modules%2Fkernel.git implementation with psutil --- diff --git a/bin/PortManager.py b/bin/PortManager.py index aace9e17b..0095b3906 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,17 @@ 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'] + # psutil realization + ports =[] + template = (AF_INET, SOCK_STREAM, "LISTEN") + for c in psutil.net_connections(kind='inet'): + if (c.family, c.type, c.status) == template: + ports.append(c.laddr.port) + if port in ports: + return True 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 -# + return False + # def getPort(preferredPort=None): logger.debug("GET PORT") diff --git a/bin/killSalome.py b/bin/killSalome.py index d7b8c392e..39e51e173 100755 --- a/bin/killSalome.py +++ b/bin/killSalome.py @@ -28,7 +28,8 @@ import os, sys, re, signal -from killSalomeWithPort import killMyPort, getPiDict, checkUnkilledProcess +from contextlib import suppress +from killSalomeWithPort import killMyPort, getPiDict, checkUnkilledProcesses, killProcesses #from salome_utils import getHostName, getShortHostName from salome_utils import getUserName @@ -37,61 +38,27 @@ def killAllPorts(): Kill all SALOME sessions belonging to the 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 + + def _getPortsFromPiDict(hidden, pattern): + fpidict = getPiDict('#####', hidden=hidden) + dirpidict = os.path.dirname(fpidict) + fpidict = os.path.basename(fpidict) + fpidict = fpidict.replace('#####', r'(\d*)') + fnamere = re.compile(pattern.format(fpidict)) + with suppress(IOError): + for _f in os.listdir(dirpidict): + _mo = fnamere.match(_f) + if _mo: + killMyPort(_mo.group(1)) + + _getPortsFromPiDict(True, "^{}") + _getPortsFromPiDict(False, "^{}$") # kill other processes - for pid in checkUnkilledProcess(): - try: - os.kill(pid, signal.SIGKILL) - except: - pass - pass + killProcesses(checkUnkilledProcesses()) 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__": try: diff --git a/bin/killSalomeWithPort.py b/bin/killSalomeWithPort.py index 2ffbdd42a..eec6a4465 100755 --- a/bin/killSalomeWithPort.py +++ b/bin/killSalomeWithPort.py @@ -31,11 +31,11 @@ # \endcode # -import re, os, sys, pickle, signal, glob +import argparse, re, os, sys, pickle, signal, glob, psutil import subprocess import shlex from salome_utils import verbose - +from contextlib import suppress def getPiDict(port,appname='salome',full=True,hidden=True,hostname=None): """ @@ -227,7 +227,26 @@ def shutdownMyPort(port, cleanup=True): # a RuntimeError is raised; we explicitly exit this function with code 0 to # prevent parent thread from crashing. +def killProcesses(_procs): + ''' + Terminate and kill all psutil.Process() + :param _procs: list psutil.Process() + ''' + for _p in _procs: + _p.terminate() + _, alive = psutil.wait_procs(_procs, timeout=5) + for _p in alive: + _p.kill() + def __killMyPort(port, filedict): + def _killPiDictProcesses(_process_id): + procs = [] + for _p in _process_id: + try: + procs.append(psutil.Process(_p)) + except psutil.NoSuchProcess: + if verbose(): print(" ------------------ process {} : not found".format(_p)) + killProcesses(procs) # bug fix: ensure port is an integer if port: port = int(port) @@ -236,23 +255,7 @@ def __killMyPort(port, filedict): 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 + _killPiDictProcesses(process_id) except: print("Cannot find or open SALOME PIDs file for port", port) pass @@ -366,7 +369,7 @@ def killMyPortSpy(pid, port): dt = 1.0 while 1: from salome_utils import killpid - ret = killpid(pid, 0) + ret = killpid(int(pid), 0) if ret == 0: break elif ret < 0: @@ -400,66 +403,58 @@ def killMyPortSpy(pid, port): killMyPort(port) return -def checkUnkilledProcess(): - #check processes in system after kill +def checkUnkilledProcesses(): + ''' + Check all unkilled SALOME processes + :return: list unkilled processes + ''' 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 \'{{print("%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 \'{{print("%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 + processes = list() + def compareNames(_process): + # On OS Windows: psutil.Process().username() get 'usergroup' + 'username' + return getUserName() == _process.username() + + def _getDictfromOutput(_prlist, _cond=None): + for _p in psutil.process_iter(['name', 'username']): + with suppress(psutil.AccessDenied): + if (compareNames(_p) and re.match(_cond, _p.info['name'])): + _prlist.append(_p) + + _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 .") - 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 +def main(): + ''' + Main function + ''' + parser = argparse.ArgumentParser(description="killSalomeWithPort utility") + parser.add_argument("ports", + help="ports of Salome services to kill", + nargs="*", type=int) + parser.add_argument("--spy", + help="kill spy port by pair PID, PORT", nargs=2, + type=int, metavar=("PID", "PORT")) + parser.add_argument("--find", + help="Get unkilled processes for SALOME", + action='store_true') + args = parser.parse_args() + + if args.spy: + killMyPortSpy(args.spy[0], args.spy[1]) sys.exit(0) - pass - elif sys.argv[1] == "--find": - processes = checkUnkilledProcess() - if processes: + if args.find: + pidcmd = checkUnkilledProcesses() + if pidcmd: print("Unkilled processes: ") print(" --------------------") print(" PID : Process name") print(" --------------------") - for pair in processes.items(): - print('%6d : %s' % pair) + for p in pidcmd: + print("{0:6} : {1}".format(p.pid, p.name())) sys.exit(0) try: from salomeContextUtils import setOmniOrbUserPath #@UnresolvedImport @@ -467,7 +462,8 @@ if __name__ == "__main__": except Exception as e: print(e) sys.exit(1) - for port in sys.argv[1:]: + for port in args.ports: killMyPort(port) - pass - pass + +if __name__ == "__main__": + main() diff --git a/bin/salome_utils.py b/bin/salome_utils.py index a80132894..c5d55fcee 100644 --- a/bin/salome_utils.py +++ b/bin/salome_utils.py @@ -549,34 +549,15 @@ 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 + import psutil + + proc_names = {} + template = (port, "omniNames") + for p in psutil.process_iter(['pid', 'name']): + proc_names[p.info['pid']] = p.info['name'] + for c in psutil.net_connections(kind='inet'): + if (c.laddr.port, proc_names[c.pid]) == template: + return c.pid # -- def killOmniNames(port):