From f7399482ce86a71ef49bb514be4083e8160f025b Mon Sep 17 00:00:00 2001 From: dnomd343 Date: Wed, 7 Sep 2022 15:35:36 +0800 Subject: [PATCH] update: process utils --- {Basis => Utils}/Process.py | 90 ++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 45 deletions(-) rename {Basis => Utils}/Process.py (64%) diff --git a/Basis/Process.py b/Utils/Process.py similarity index 64% rename from Basis/Process.py rename to Utils/Process.py index 5b942e7..34e2c5f 100644 --- a/Basis/Process.py +++ b/Utils/Process.py @@ -6,12 +6,12 @@ import copy import time import ctypes import signal -from Basis.Logger import logging -from Basis.Functions import genFlag -from Basis.Exception import processException +from Utils.Logger import logger +from Utils.Common import genFlag +from Utils.Exception import processException from subprocess import Popen, STDOUT, DEVNULL -libcPaths = [ +libcSysPaths = [ '/usr/lib/libc.so.6', # CentOS '/usr/lib64/libc.so.6', '/lib/libc.musl-i386.so.1', # Alpine @@ -23,18 +23,18 @@ libcPaths = [ ] libcPath = None -for libc in libcPaths: - if os.path.exists(libc): # try to locate libc.so - libcPath = libc +for path in libcSysPaths: + if os.path.exists(path): # try to locate libc.so + libcPath = path break if libcPath is None: # lost libc.so -> unable to utilize prctl - logging.warning('libc.so not found') + logger.warning('libc.so not found') else: - logging.info('libc.so -> ' + str(libcPath)) + logger.info('libc.so -> %s' % libcPath) class Process(object): - """ Manage a sub process and it's file. + """ Manage a sub process and it's configure file. Arguments: cmd: Command list, which use to start the program. @@ -65,34 +65,34 @@ class Process(object): def __checkWorkDir(self) -> None: # check if the working directory is normal if os.path.isdir(self.workDir): return - logging.warning('[%s] Work directory %s not exist' % (self.id, self.workDir)) + logger.warning('[%s] Work directory %s not exist' % (self.id, self.workDir)) try: os.makedirs(self.workDir) # just like `mkdir -p ...` - logging.info('[%s] New directory -> %s' % (self.id, self.workDir)) + logger.info('[%s] New directory -> %s' % (self.id, self.workDir)) except: if os.path.exists(self.workDir): - logging.error('[%s] %s already exist but not folder' % (self.id, self.workDir)) + logger.error('[%s] %s already exist but not folder' % (self.id, self.workDir)) else: - logging.error('[%s] Unable to create new folder -> %s' % (self.id, self.workDir)) + logger.error('[%s] Unable to create new folder -> %s' % (self.id, self.workDir)) raise processException('Working directory error') # fatal error def __killProcess(self, killSignal: int) -> None: try: pgid = os.getpgid(self.__process.pid) # progress group id os.killpg(pgid, killSignal) # kill sub process group - logging.debug('[%s] Send signal %i to PGID %i' % (self.id, killSignal, pgid)) + logger.debug('[%s] Send signal %i to PGID %i' % (self.id, killSignal, pgid)) except: - logging.warning('[%s] Failed to get PGID of sub process (PID = %i)' % (self.id, self.__process.pid)) + logger.warning('[%s] Failed to get PGID of sub process (PID = %i)' % (self.id, self.__process.pid)) def __deleteFile(self, filePath: str) -> None: if not os.path.isfile(filePath): # file not found (or not a file) - logging.warning('[%s] File %s not found' % (self.id, filePath)) + logger.warning('[%s] File %s not found' % (self.id, filePath)) return try: os.remove(filePath) # remove config file - logging.debug('[%s] File %s deleted successfully' % (self.id, filePath)) + logger.debug('[%s] File %s deleted successfully' % (self.id, filePath)) except: - logging.error('[%s] Unable to delete file %s' % (self.id, filePath)) + logger.error('[%s] Unable to delete file %s' % (self.id, filePath)) def __init__(self, workDir: str, taskId: str = '', isStart: bool = True, cmd: str or list or None = None, env: dict or None = None, file: dict or list or None = None) -> None: @@ -102,53 +102,53 @@ class Process(object): self.cmd = copy.copy([cmd] if type(cmd) == str else cmd) # depth = 1 self.file = copy.deepcopy([file] if type(file) == dict else file) # depth = 2 self.__checkWorkDir() # ensure the working direction is normal - logging.debug('[%s] Process command -> %s (%s)' % (self.id, self.cmd, self.env)) + logger.debug('[%s] Process command -> %s (%s)' % (self.id, self.cmd, self.env)) if self.file is not None: if len(self.file) > 1: - logging.debug('[%s] Manage %i files' % (self.id, len(self.file))) + logger.debug('[%s] Manage %i files' % (self.id, len(self.file))) for file in self.file: # traverse all files if not isStart: # don't print log twice - logging.debug('[%s] File %s -> %s' % (self.id, file['path'], file['content'])) + logger.debug('[%s] File %s -> %s' % (self.id, file['path'], file['content'])) if isStart: self.start() def setCmd(self, cmd: str or list) -> None: self.cmd = copy.copy([cmd] if type(cmd) == str else cmd) - logging.info('[%s] Process setting command -> %s' % (self.id, self.cmd)) + logger.info('[%s] Process setting command -> %s' % (self.id, self.cmd)) def setEnv(self, env: dict or None) -> None: self.env = copy.copy(env) - logging.info('[%s] Process setting environ -> %s' % (self.id, self.env)) + logger.info('[%s] Process setting environ -> %s' % (self.id, self.env)) def setFile(self, file: dict or list or None) -> None: self.file = copy.deepcopy([file] if type(file) == dict else file) if self.file is None: - logging.info('[%s] Process setting file -> None' % self.id) + logger.info('[%s] Process setting file -> None' % self.id) return for file in self.file: # traverse all files - logging.info('[%s] Process setting file %s -> %s' % (self.id, file['path'], file['content'])) + logger.info('[%s] Process setting file %s -> %s' % (self.id, file['path'], file['content'])) def start(self, isCapture: bool = True) -> None: self.__capture = isCapture - logging.debug('[%s] Process ready to start (%s)' % ( - self.id, ('with' if self.__capture else 'without') + ' output capture' + logger.debug('[%s] Process ready to start (%s output capture)' % ( + self.id, 'with' if self.__capture else 'without' )) if self.cmd is None: # ERROR CASE - logging.error('[%s] Process miss start command' % self.id) + logger.error('[%s] Process miss start command' % self.id) raise processException('Miss start command') if self.__process is not None and self.__process.poll() is None: # ERROR CASE - logging.error('[%s] Process try to start but it is running' % self.id) + logger.error('[%s] Process try to start but it is running' % self.id) raise processException('Process is still running') if self.env is not None and 'PATH' not in self.env and '/' not in self.cmd[0]: # WARNING CASE - logging.warning('[%s] Executable file in relative path but miss PATH in environ' % self.id) + logger.warning('[%s] Executable file in relative path but miss PATH in environ' % self.id) if self.file is not None: # create and write file contents for file in self.file: with open(file['path'], 'w', encoding = 'utf-8') as fileObject: # save file content fileObject.write(file['content']) - logging.debug('[%s] File %s -> %s' % (self.id, file['path'], file['content'])) + logger.debug('[%s] File %s -> %s' % (self.id, file['path'], file['content'])) if self.__capture: # with output capture - self.__logfile = os.path.join(self.workDir, self.id + '.log') - logging.debug('[%s] Process output capture -> %s' % (self.id, self.__logfile)) + self.__logfile = os.path.join(self.workDir, '%s.log' % self.id) + logger.debug('[%s] Process output capture -> %s' % (self.id, self.__logfile)) stdout = open(self.__logfile, 'w', encoding = 'utf-8') stderr = STDOUT # combine the stderr with stdout else: # discard all the output of sub process @@ -161,48 +161,48 @@ class Process(object): preexec_fn = None if libcPath is None else Process.__preExec ) except Exception as exp: - logging.error('[%s] Process unable to start -> %s' % (self.id, exp)) + logger.error('[%s] Process unable to start -> %s' % (self.id, exp)) raise processException('Unable to start process') - logging.info('[%s] Process running -> PID = %i' % (self.id, self.__process.pid)) + logger.info('[%s] Process running -> PID = %i' % (self.id, self.__process.pid)) def signal(self, signalNum: int) -> None: # send specified signal to sub process try: signalName = signal.Signals(signalNum).name except: signalName = 'unknown' - logging.info('[%s] Send signal -> %i (%s)' % (self.id, signalNum, signalName)) + logger.info('[%s] Send signal -> %i (%s)' % (self.id, signalNum, signalName)) self.__process.send_signal(signalNum) def status(self) -> bool: # check if the sub process is still running status = self.__process.poll() is None - logging.debug('[%s] Process check status -> %s' % (self.id, 'running' if status else 'exit')) + logger.debug('[%s] Process check status -> %s' % (self.id, 'running' if status else 'exit')) return status def wait(self, timeout: int or None = None) -> None: # blocking wait sub process - logging.info('[%s] Process wait -> timeout = %s' % (self.id, str(timeout))) + logger.info('[%s] Process wait -> timeout = %s' % (self.id, str(timeout))) try: self.__process.wait(timeout = timeout) - logging.info('[%s] Process wait timeout -> exit' % self.id) + logger.info('[%s] Process wait timeout -> exit' % self.id) except: - logging.info('[%s] Process wait timeout -> running' % self.id) + logger.info('[%s] Process wait timeout -> running' % self.id) def quit(self, isForce: bool = False, waitTime: int = 50) -> None: # wait 50ms in default killSignal = signal.SIGKILL if isForce else signal.SIGTERM # 9 -> force kill / 15 -> terminate signal - logging.debug('[%s] Kill signal -> %i (%s)' % (self.id, killSignal, signal.Signals(killSignal).name)) + logger.debug('[%s] Kill signal -> %i (%s)' % (self.id, killSignal, signal.Signals(killSignal).name)) self.__killProcess(killSignal) time.sleep(waitTime / 1000) # sleep (ms -> s) while self.__process.poll() is None: # confirm sub process exit self.__killProcess(killSignal) time.sleep(waitTime / 1000) - logging.info('[%s] Process terminated -> PID = %i' % (self.id, self.__process.pid)) + logger.info('[%s] Process terminated -> PID = %i' % (self.id, self.__process.pid)) if self.__capture: try: with open(self.__logfile, 'r', encoding = 'utf-8') as fileObject: # read sub process output self.output = fileObject.read() - logging.debug('[%s] Process output capture -> length = %s' % (self.id, len(self.output))) + logger.debug('[%s] Process output capture -> length = %s' % (self.id, len(self.output))) self.__deleteFile(self.__logfile) except: - logging.error('[%s] Failed to read capture file -> %s' % (self.id, self.__logfile)) + logger.error('[%s] Failed to read capture file -> %s' % (self.id, self.__logfile)) if self.file is not None: # with config file for file in self.file: self.__deleteFile(file['path'])