Commit a55b647a authored by Sebastien Robin's avatar Sebastien Robin

erp5testnode: make sure to kill grandchild when we kill a process

parent 0389e5f5
...@@ -466,7 +466,9 @@ branch = foo ...@@ -466,7 +466,9 @@ branch = foo
self.assertEqual(result['status_code'], expected_status) self.assertEqual(result['status_code'], expected_status)
process_manager = ProcessManager(log=self.log, max_timeout=1) process_manager = ProcessManager(log=self.log, max_timeout=1)
_checkCorrectStatus(0, *['sleep','0']) _checkCorrectStatus(0, *['sleep','0'])
_checkCorrectStatus(-15, *['sleep','2']) # We must make sure that if the command is too long that
# it will be automatically killed
self.assertRaises(SubprocessError, process_manager.spawn, 'sleep','3')
def test_13_SlaposControlerResetSoftware(self): def test_13_SlaposControlerResetSoftware(self):
test_node = self.getTestNode() test_node = self.getTestNode()
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
# #
############################################################################## ##############################################################################
import os import os
import psutil
import re import re
import subprocess import subprocess
import threading import threading
...@@ -98,6 +99,25 @@ def subprocess_capture(p, log, log_prefix, get_output=True): ...@@ -98,6 +99,25 @@ def subprocess_capture(p, log, log_prefix, get_output=True):
return (p.stdout and ''.join(stdout), return (p.stdout and ''.join(stdout),
p.stderr and ''.join(stderr)) p.stderr and ''.join(stderr))
def killCommand(pid):
"""
To avoid letting orphaned childs, we stop the process and all it's
child (until childs does not change) and then we brutally kill
everyone at the same time
"""
process = psutil.Process(pid)
child_set = set([x.pid for x in process.get_children(recursive=True)])
new_child_set = None
os.kill(pid, signal.SIGSTOP)
while new_child_set != child_set:
for child_pid in child_set:
os.kill(child_pid, signal.SIGSTOP)
time.sleep(1)
new_child_set = set([x.pid for x in process.get_children(recursive=True)])
for child_pid in child_set:
os.kill(child_pid, signal.SIGKILL)
os.kill(pid, signal.SIGKILL)
class ProcessManager(object): class ProcessManager(object):
stdin = file(os.devnull) stdin = file(os.devnull)
...@@ -115,7 +135,7 @@ class ProcessManager(object): ...@@ -115,7 +135,7 @@ class ProcessManager(object):
def timeoutExpired(p, log): def timeoutExpired(p, log):
if p.poll() is None: if p.poll() is None:
log('PROCESS TOO LONG OR DEAD, GOING TO BE TERMINATED') log('PROCESS TOO LONG OR DEAD, GOING TO BE TERMINATED')
p.terminate() killCommand(p.pid)
if self.under_cancellation: if self.under_cancellation:
raise CancellationError("Test Result was cancelled") raise CancellationError("Test Result was cancelled")
...@@ -147,7 +167,7 @@ class ProcessManager(object): ...@@ -147,7 +167,7 @@ class ProcessManager(object):
self.process_pid_set.discard(p.pid) self.process_pid_set.discard(p.pid)
if self.under_cancellation: if self.under_cancellation:
raise CancellationError("Test Result was cancelled") raise CancellationError("Test Result was cancelled")
if raise_error_if_fail and p.returncode != -15 and p.returncode: if raise_error_if_fail and p.returncode:
raise SubprocessError(result) raise SubprocessError(result)
return result return result
...@@ -163,7 +183,7 @@ class ProcessManager(object): ...@@ -163,7 +183,7 @@ class ProcessManager(object):
self.under_cancellation = True self.under_cancellation = True
for pgpid in self.process_pid_set: for pgpid in self.process_pid_set:
try: try:
os.kill(pgpid, signal.SIGTERM) killCommand(pgpid)
except: except:
pass pass
try: try:
......
...@@ -49,9 +49,10 @@ setup(name=name, ...@@ -49,9 +49,10 @@ setup(name=name,
namespace_packages=['erp5', 'erp5.util'], namespace_packages=['erp5', 'erp5.util'],
install_requires=[ install_requires=[
'setuptools', # namespaces 'setuptools', # namespaces
'psutil >= 0.5.0',
], ],
extras_require={ extras_require={
'testnode': ['slapos.core', 'xml_marshaller'], 'testnode': ['slapos.core', 'xml_marshaller', 'psutil >= 0.5.0'],
'testbrowser': ['zope.testbrowser >= 3.11.1', 'z3c.etestbrowser'], 'testbrowser': ['zope.testbrowser >= 3.11.1', 'z3c.etestbrowser'],
'benchmark': benchmark_install_require_list, 'benchmark': benchmark_install_require_list,
'benchmark-report': [name+'[benchmark]', 'matplotlib', 'numpy'], 'benchmark-report': [name+'[benchmark]', 'matplotlib', 'numpy'],
...@@ -76,6 +77,7 @@ setup(name=name, ...@@ -76,6 +77,7 @@ setup(name=name,
tests_require=[ tests_require=[
'slapos.core', 'slapos.core',
'xml_marshaller', 'xml_marshaller',
'psutil >= 0.5.0',
], ],
) )
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment