Ensure pid file is removed when metadata ns daemon receives SIGTERM
These files from the metadata namespace proxy are not being removed because delete_pid() is registered with atexit. This means it only runs when a process exits normally and won't run when a process receives a signal. This patch registers a signal handler for SIGTERM that calls exit() to make the process exit normally so delete_pid() gets called. Fixes bug: 1223250 Change-Id: I6309802e2109359560ccc084559ec8e4d310cce2
This commit is contained in:
parent
ff514f3938
commit
baf31fdeee
@ -19,6 +19,7 @@
|
|||||||
import atexit
|
import atexit
|
||||||
import fcntl
|
import fcntl
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from neutron.agent.linux import utils
|
from neutron.agent.linux import utils
|
||||||
@ -123,11 +124,15 @@ class Daemon(object):
|
|||||||
|
|
||||||
# write pidfile
|
# write pidfile
|
||||||
atexit.register(self.delete_pid)
|
atexit.register(self.delete_pid)
|
||||||
|
signal.signal(signal.SIGTERM, self.handle_sigterm)
|
||||||
self.pidfile.write(os.getpid())
|
self.pidfile.write(os.getpid())
|
||||||
|
|
||||||
def delete_pid(self):
|
def delete_pid(self):
|
||||||
os.remove(str(self.pidfile))
|
os.remove(str(self.pidfile))
|
||||||
|
|
||||||
|
def handle_sigterm(self, signum, frame):
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start the daemon."""
|
"""Start the daemon."""
|
||||||
|
|
||||||
|
@ -160,13 +160,16 @@ class TestDaemon(base.BaseTestCase):
|
|||||||
d = daemon.Daemon('pidfile')
|
d = daemon.Daemon('pidfile')
|
||||||
with mock.patch.object(d, '_fork') as fork:
|
with mock.patch.object(d, '_fork') as fork:
|
||||||
with mock.patch.object(daemon, 'atexit') as atexit:
|
with mock.patch.object(daemon, 'atexit') as atexit:
|
||||||
|
with mock.patch.object(daemon, 'signal') as signal:
|
||||||
|
signal.SIGTERM = 15
|
||||||
with mock.patch.object(daemon, 'sys') as sys:
|
with mock.patch.object(daemon, 'sys') as sys:
|
||||||
sys.stdin.fileno.return_value = 0
|
sys.stdin.fileno.return_value = 0
|
||||||
sys.stdout.fileno.return_value = 1
|
sys.stdout.fileno.return_value = 1
|
||||||
sys.stderr.fileno.return_value = 2
|
sys.stderr.fileno.return_value = 2
|
||||||
d.daemonize()
|
d.daemonize()
|
||||||
atexit.register.assert_called_once_with(d.delete_pid)
|
|
||||||
|
|
||||||
|
signal.signal.assert_called_once_with(15, d.handle_sigterm)
|
||||||
|
atexit.register.assert_called_once_with(d.delete_pid)
|
||||||
fork.assert_has_calls([mock.call(), mock.call()])
|
fork.assert_has_calls([mock.call(), mock.call()])
|
||||||
|
|
||||||
self.os.assert_has_calls([
|
self.os.assert_has_calls([
|
||||||
@ -185,6 +188,12 @@ class TestDaemon(base.BaseTestCase):
|
|||||||
d.delete_pid()
|
d.delete_pid()
|
||||||
self.os.remove.assert_called_once_with('pidfile')
|
self.os.remove.assert_called_once_with('pidfile')
|
||||||
|
|
||||||
|
def test_handle_sigterm(self):
|
||||||
|
d = daemon.Daemon('pidfile')
|
||||||
|
with mock.patch.object(daemon, 'sys') as sys:
|
||||||
|
d.handle_sigterm(15, 1234)
|
||||||
|
sys.exit.assert_called_once_with(0)
|
||||||
|
|
||||||
def test_start(self):
|
def test_start(self):
|
||||||
self.pidfile.return_value.is_running.return_value = False
|
self.pidfile.return_value.is_running.return_value = False
|
||||||
d = daemon.Daemon('pidfile')
|
d = daemon.Daemon('pidfile')
|
||||||
|
Loading…
Reference in New Issue
Block a user