Signed-off-by: Jiří Župka jzupka@redhat.com --- Common/Logs.py | 2 +- Common/SlaveUtils.py | 27 ++++++++++++++++++--------- NetTest/NetTestController.py | 5 ++--- 3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/Common/Logs.py b/Common/Logs.py index 34dae3e..44d4f98 100644 --- a/Common/Logs.py +++ b/Common/Logs.py @@ -194,7 +194,7 @@ class Logs: ':%(lineno)4.4d| %(levelname)s: ' '%(message)s', '%d/%m %H:%M:%S', " "*4) cls.log_root = log_root - cls.logFolder = find_test_root(__file__, "nettest") + cls.logFolder = os.path.dirname(sys.argv[0]) cls.logger = logger cls.debug = debug cls.date = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S") diff --git a/Common/SlaveUtils.py b/Common/SlaveUtils.py index c9e24d0..d8db772 100644 --- a/Common/SlaveUtils.py +++ b/Common/SlaveUtils.py @@ -11,23 +11,32 @@ from Common.ShellProcess import ShellProcess
def prepare_client_session(host, port, login, passwd=None, command=None, - prompt=None): + prompt=None, install_path=None, test_dir=None): """ Copy nettest to client start client part and create session with client part. - @param command: Command which is started after login to guest. - @param prompt: Prompt in guest side which means that guest side stared correctly. + @param command: Command which is started after login to guest, in root + path of installed test. + @param prompt: Prompt in guest side which means that guest side stared + correctly. + @param test_dir: Path in install_path where is installed testing framework. + @param install_path: Path to create and install test_dir folder. """ - s = ShellProcess("tar -cvzf nettest.tar.gz --exclude *.pyc --exclude 'Logs/*' *") + if install_path is None: + install_path = "/tmp" + if test_dir is None: + test_dir = "lnst" + s = ShellProcess("tar -cjf lnst.tar.bz2 --exclude *.pyc --exclude 'Logs/*' *") s.wait() scp_to_remote(host, port, login, passwd, - "nettest.tar.gz","/tmp/") + "lnst.tar.bz2","/%s/" % (install_path)) wait_for_login(host, port, login, passwd, "PASS:", - command = "mkdir -p /tmp/nettest && tar -xvzf " - "/tmp/nettest.tar.gz -C /tmp/nettest/ && echo PASS:", - timeout=60) + command = "mkdir -p /%(ip)s/%(td)s && tar -xvjf " + "/%(ip)s/lnst.tar.bz2 -C /%(ip)s/%(td)s && echo PASS:" % + {"td":test_dir, "ip":install_path} , timeout=60)
if prompt is None: prompt = "Started" + command = "/%s/%s/%s" % (install_path, test_dir, command) return wait_for_login(host, port, login, passwd, prompt, - command=command, timeout=10) + command=command, timeout=10) \ No newline at end of file diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index 7626157..b0b2437 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -52,9 +52,8 @@ class NetTestController: passwd = info["rootpass"] else: passwd = None - session = prepare_client_session(hostname, port, - login, passwd, - "/tmp/nettest/nettestslave.py") + session = prepare_client_session(hostname, port, login, passwd, + "nettestslave.py") session.add_kill_handler(self._session_die) info["session"] = session
Compatibility problem with python 2.4.
Example: 1) Create process. 2) Get process pid. 3) ProcessManager.register_pid(pid, handler) handler can be None. 4) When the process ends ProcessManager calls handler. Handler is called in separate thread. 4.1) If in handler raise exception then ProcessManager ends nettest. 5) For waiting on end of process can be use os.waitpid.
Signed-off-by: Jiří Župka jzupka@redhat.com --- Common/ProcessManager.py | 110 +++++++++++++++++++++++++++------------------ 1 files changed, 66 insertions(+), 44 deletions(-)
diff --git a/Common/ProcessManager.py b/Common/ProcessManager.py index 86d7b4b..1995d15 100644 --- a/Common/ProcessManager.py +++ b/Common/ProcessManager.py @@ -9,64 +9,86 @@ published by the Free Software Foundation; see COPYING for details. __autor__ = """ jzupka@redhat.com (Jiri Zupka) """ -import os, signal +import os, signal, thread, logging
class ProcessManager: + class SubProcess: + def __init__(self, pid, handler): + self.pid = pid + self.lock = thread.allocate_lock() + self.lock.acquire() + self.handler = handler + self.enabled = True + self.status = None + thread.start_new_thread(self.waitpid, (self.pid, self.lock, + self.handler)) + + def isAlive(self): + return self.lock.locked() + + def kill(self): + os.kill(self.pid, signal.SIGTERM) + + def waitpid(self, pid, lock, handler): + _pid, status = ProcessManager.std_waitpid(pid, 0) + self.status = status + status = os.WEXITSTATUS(status) + lock.release() + if self.enabled: + ProcessManager.lock.acquire() + if handler is not None: + try: + handler(status) + except: + import sys, traceback + type, value, tb = sys.exc_info() + logging.error(''.join(traceback.format_exception(type, value, tb))) + os.kill(os.getpid(), signal.SIGTERM) + else: + print "Process pid %s exit with exitcode %s" % (pid, status) + ProcessManager.lock.release() + thread.exit() + pids = {} - signals = 0 + lock = thread.allocate_lock() + std_waitpid = None
@classmethod def register_pid(cls, pid, handler=None): - cls.pids[pid] = handler + cls.pids[pid] = ProcessManager.SubProcess(pid, handler)
@classmethod def remove_pid(cls, pid): if pid in cls.pids: - del (cls.pids[pid]) + cls.pids[pid].enabled = False
@classmethod - def check_pids(cls): - finished = {} - pid_tr = [] - + def kill_all(cls): for pid in cls.pids: - _pid = 0 - status = None - try: - _pid, status = os.waitpid(pid, os.WNOHANG) - except OSError, e: - if e.errno != 10: - raise - else: - finished[pid] = (None, cls.pids[pid]) - pid_tr.append(pid) - else: - if pid == _pid: - finished[pid] = (os.WEXITSTATUS(status), cls.pids[pid]) - pid_tr.append(pid) - - for pid in pid_tr: - cls.remove_pid(pid) - return finished + cls.pids[pid].kill()
@classmethod - def handler(cls, signum, frame): - if (signum == signal.SIGCHLD): - cls.signals += 1 - if cls.signals == 1: - while cls.signals > 0: - finished = ProcessManager.check_pids() - for pid in finished: - status, handler = finished[pid] - if handler is None: - print("Process %d finish with status %s." % (pid, status)) - else: - handler(status) - if cls.signals > 1: - cls.signals = 1 - else: - cls.signals = 0 + def waitpid(cls, pid, wait): + if pid not in cls.pids: + return ProcessManager.std_waitpid(pid, wait) + if not wait: + cls.pids[pid].lock.acquire() + cls.pids[pid].lock.release() + status = cls.pids[pid].status + del cls.pids[pid] + return pid, status + else: + status = cls.pids[pid].status + if status is not None: + del cls.pids[pid] + else: + pid = 0 + return pid, status
-signal.siginterrupt(signal.SIGCHLD, False) -signal.signal(signal.SIGCHLD, ProcessManager.handler) +lock = thread.allocate_lock() +lock.acquire() +if os.waitpid != ProcessManager.waitpid: + ProcessManager.std_waitpid = os.waitpid + os.waitpid = ProcessManager.waitpid +lock.release() \ No newline at end of file
both applied. Thanks
Wed, Jun 08, 2011 at 02:54:22PM CEST, jzupka@redhat.com wrote:
Signed-off-by: Jiří Župka jzupka@redhat.com
Common/Logs.py | 2 +- Common/SlaveUtils.py | 27 ++++++++++++++++++--------- NetTest/NetTestController.py | 5 ++--- 3 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/Common/Logs.py b/Common/Logs.py index 34dae3e..44d4f98 100644 --- a/Common/Logs.py +++ b/Common/Logs.py @@ -194,7 +194,7 @@ class Logs: ':%(lineno)4.4d| %(levelname)s: ' '%(message)s', '%d/%m %H:%M:%S', " "*4) cls.log_root = log_root
cls.logFolder = find_test_root(__file__, "nettest")
cls.logFolder = os.path.dirname(sys.argv[0]) cls.logger = logger cls.debug = debug cls.date = datetime.datetime.now().strftime("%Y-%m-%d_%H:%M:%S")diff --git a/Common/SlaveUtils.py b/Common/SlaveUtils.py index c9e24d0..d8db772 100644 --- a/Common/SlaveUtils.py +++ b/Common/SlaveUtils.py @@ -11,23 +11,32 @@ from Common.ShellProcess import ShellProcess
def prepare_client_session(host, port, login, passwd=None, command=None,
prompt=None):
""" Copy nettest to client start client part and create session with client part.prompt=None, install_path=None, test_dir=None):
- @param command: Command which is started after login to guest.
- @param prompt: Prompt in guest side which means that guest side stared correctly.
- @param command: Command which is started after login to guest, in root
path of installed test.- @param prompt: Prompt in guest side which means that guest side stared
correctly.- @param test_dir: Path in install_path where is installed testing framework.
- @param install_path: Path to create and install test_dir folder. """
- s = ShellProcess("tar -cvzf nettest.tar.gz --exclude *.pyc --exclude 'Logs/*' *")
- if install_path is None:
install_path = "/tmp"- if test_dir is None:
test_dir = "lnst"- s = ShellProcess("tar -cjf lnst.tar.bz2 --exclude *.pyc --exclude 'Logs/*' *") s.wait() scp_to_remote(host, port, login, passwd,
"nettest.tar.gz","/tmp/")
wait_for_login(host, port, login, passwd, "PASS:","lnst.tar.bz2","/%s/" % (install_path))
command = "mkdir -p /tmp/nettest && tar -xvzf ""/tmp/nettest.tar.gz -C /tmp/nettest/ && echo PASS:",timeout=60)
command = "mkdir -p /%(ip)s/%(td)s && tar -xvjf ""/%(ip)s/lnst.tar.bz2 -C /%(ip)s/%(td)s && echo PASS:" %{"td":test_dir, "ip":install_path} , timeout=60)if prompt is None: prompt = "Started"
command = "/%s/%s/%s" % (install_path, test_dir, command) return wait_for_login(host, port, login, passwd, prompt,
command=command, timeout=10)
command=command, timeout=10)\ No newline at end of file diff --git a/NetTest/NetTestController.py b/NetTest/NetTestController.py index 7626157..b0b2437 100644 --- a/NetTest/NetTestController.py +++ b/NetTest/NetTestController.py @@ -52,9 +52,8 @@ class NetTestController: passwd = info["rootpass"] else: passwd = None
session = prepare_client_session(hostname, port,login, passwd,"/tmp/nettest/nettestslave.py")
session = prepare_client_session(hostname, port, login, passwd,"nettestslave.py") session.add_kill_handler(self._session_die) info["session"] = session-- 1.7.4.4
lnst-developers@lists.fedorahosted.org