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:
Darragh O'Reilly 2013-09-10 09:06:28 +00:00
parent ff514f3938
commit baf31fdeee
2 changed files with 20 additions and 6 deletions

View File

@ -19,6 +19,7 @@
import atexit
import fcntl
import os
import signal
import sys
from neutron.agent.linux import utils
@ -123,11 +124,15 @@ class Daemon(object):
# write pidfile
atexit.register(self.delete_pid)
signal.signal(signal.SIGTERM, self.handle_sigterm)
self.pidfile.write(os.getpid())
def delete_pid(self):
os.remove(str(self.pidfile))
def handle_sigterm(self, signum, frame):
sys.exit(0)
def start(self):
"""Start the daemon."""

View File

@ -160,13 +160,16 @@ class TestDaemon(base.BaseTestCase):
d = daemon.Daemon('pidfile')
with mock.patch.object(d, '_fork') as fork:
with mock.patch.object(daemon, 'atexit') as atexit:
with mock.patch.object(daemon, 'sys') as sys:
sys.stdin.fileno.return_value = 0
sys.stdout.fileno.return_value = 1
sys.stderr.fileno.return_value = 2
d.daemonize()
atexit.register.assert_called_once_with(d.delete_pid)
with mock.patch.object(daemon, 'signal') as signal:
signal.SIGTERM = 15
with mock.patch.object(daemon, 'sys') as sys:
sys.stdin.fileno.return_value = 0
sys.stdout.fileno.return_value = 1
sys.stderr.fileno.return_value = 2
d.daemonize()
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()])
self.os.assert_has_calls([
@ -185,6 +188,12 @@ class TestDaemon(base.BaseTestCase):
d.delete_pid()
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):
self.pidfile.return_value.is_running.return_value = False
d = daemon.Daemon('pidfile')