From: Richard Purdie Date: Fri, 16 Nov 2018 09:33:28 +0000 (+0000) Subject: oeqa/utils/httpserver: Rework to avoid hangs and improve logging X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4eac9a5337d93b6cbd3916af97f62bb04881c9cd;p=thirdparty%2Fopenembedded%2Fopenembedded-core-contrib.git oeqa/utils/httpserver: Rework to avoid hangs and improve logging testimage.bbclass installs a SIGTERM handler which conflicts with the use of multiprocessing here. This is paritcularly problematic if the http service is terminated before its started and hence before its had a chance to reset the default signal handler (as the code was written). Instead, temporarily remove testimage's handler whilst forking the http process which means the correct handler is installed and won't deadlock. Also take the opportunity to add in some log messages about the server start and shutdown so that future debugging is easier and its clearer what the code is doing. (From OE-Core rev: cc0471439aa0085ca87deccf061c5b676ef12388) Signed-off-by: Richard Purdie Signed-off-by: Armin Kuster --- diff --git a/meta/lib/oeqa/runtime/cases/apt.py b/meta/lib/oeqa/runtime/cases/apt.py index 8d4dd35c578..793143f72cf 100644 --- a/meta/lib/oeqa/runtime/cases/apt.py +++ b/meta/lib/oeqa/runtime/cases/apt.py @@ -18,7 +18,7 @@ class AptRepoTest(AptTest): @classmethod def setUpClass(cls): service_repo = os.path.join(cls.tc.td['DEPLOY_DIR_DEB'], 'all') - cls.repo_server = HTTPService(service_repo, cls.tc.target.server_ip) + cls.repo_server = HTTPService(service_repo, cls.tc.target.server_ip, logger=cls.tc.logger) cls.repo_server.start() @classmethod diff --git a/meta/lib/oeqa/runtime/cases/dnf.py b/meta/lib/oeqa/runtime/cases/dnf.py index dd7affca0a9..ef81a8cb7df 100644 --- a/meta/lib/oeqa/runtime/cases/dnf.py +++ b/meta/lib/oeqa/runtime/cases/dnf.py @@ -55,7 +55,7 @@ class DnfRepoTest(DnfTest): @classmethod def setUpClass(cls): cls.repo_server = HTTPService(os.path.join(cls.tc.td['WORKDIR'], 'oe-testimage-repo'), - cls.tc.target.server_ip) + cls.tc.target.server_ip, logger=cls.tc.logger) cls.repo_server.start() @classmethod diff --git a/meta/lib/oeqa/runtime/cases/opkg.py b/meta/lib/oeqa/runtime/cases/opkg.py index 668c876a415..62421413cc6 100644 --- a/meta/lib/oeqa/runtime/cases/opkg.py +++ b/meta/lib/oeqa/runtime/cases/opkg.py @@ -18,7 +18,7 @@ class OpkgRepoTest(OpkgTest): @classmethod def setUp(cls): service_repo = os.path.join(cls.tc.td['DEPLOY_DIR_IPK'], 'all') - cls.repo_server = HTTPService(service_repo, cls.tc.target.server_ip) + cls.repo_server = HTTPService(service_repo, cls.tc.target.server_ip, logger=cls.tc.logger) cls.repo_server.start() @classmethod diff --git a/meta/lib/oeqa/utils/httpserver.py b/meta/lib/oeqa/utils/httpserver.py index 7d12331453a..a48d4994fd7 100644 --- a/meta/lib/oeqa/utils/httpserver.py +++ b/meta/lib/oeqa/utils/httpserver.py @@ -1,13 +1,13 @@ import http.server import multiprocessing import os +import traceback +import signal from socketserver import ThreadingMixIn class HTTPServer(ThreadingMixIn, http.server.HTTPServer): - def server_start(self, root_dir): - import signal - signal.signal(signal.SIGTERM, signal.SIG_DFL) + def server_start(self, root_dir, logger): os.chdir(root_dir) self.serve_forever() @@ -18,19 +18,40 @@ class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): class HTTPService(object): - def __init__(self, root_dir, host=''): + def __init__(self, root_dir, host='', logger=None): self.root_dir = root_dir self.host = host self.port = 0 + self.logger = logger def start(self): + if not os.path.exists(self.root_dir): + self.logger.info("Not starting HTTPService for directory %s which doesn't exist" % (self.root_dir)) + return + self.server = HTTPServer((self.host, self.port), HTTPRequestHandler) if self.port == 0: self.port = self.server.server_port - self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir]) + self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir, self.logger]) + + # The signal handler from testimage.bbclass can cause deadlocks here + # if the HTTPServer is terminated before it can restore the standard + #signal behaviour + orig = signal.getsignal(signal.SIGTERM) + signal.signal(signal.SIGTERM, signal.SIG_DFL) self.process.start() + signal.signal(signal.SIGTERM, orig) + + if self.logger: + self.logger.info("Started HTTPService on %s:%s" % (self.host, self.port)) + def stop(self): - self.server.server_close() - self.process.terminate() - self.process.join() + if hasattr(self, "server"): + self.server.server_close() + if hasattr(self, "process"): + self.process.terminate() + self.process.join() + if self.logger: + self.logger.info("Stopped HTTPService on %s:%s" % (self.host, self.port)) +