Merge "daemon: avoid raising UnboundLocalError to callers"

This commit is contained in:
Jenkins 2015-06-25 13:31:25 +00:00 committed by Gerrit Code Review
commit 62ea46f625
2 changed files with 57 additions and 38 deletions

View File

@ -90,46 +90,48 @@ def daemon_start(config, filters):
manager_cls = get_manager_class(config, filters) manager_cls = get_manager_class(config, filters)
manager = manager_cls(address=socket_path) manager = manager_cls(address=socket_path)
server = manager.get_server() server = manager.get_server()
# allow everybody to connect to the socket
rw_rw_rw_ = (stat.S_IRUSR | stat.S_IWUSR |
stat.S_IRGRP | stat.S_IWGRP |
stat.S_IROTH | stat.S_IWOTH)
os.chmod(socket_path, rw_rw_rw_)
try: try:
# In Python 3 we have to use buffer to push in bytes directly # allow everybody to connect to the socket
stdout = sys.stdout.buffer rw_rw_rw_ = (stat.S_IRUSR | stat.S_IWUSR |
except AttributeError: stat.S_IRGRP | stat.S_IWGRP |
stdout = sys.stdout stat.S_IROTH | stat.S_IWOTH)
stdout.write(socket_path.encode('utf-8')) os.chmod(socket_path, rw_rw_rw_)
stdout.write(b'\n')
stdout.write(bytes(server.authkey))
sys.stdin.close()
sys.stdout.close()
sys.stderr.close()
# Gracefully shutdown on INT or TERM signals
stop = functools.partial(daemon_stop, server)
signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGINT, stop)
LOG.info("Starting rootwrap daemon main loop")
server.serve_forever()
finally:
conn = server.listener
# This will break accept() loop with EOFError if it was not in the main
# thread (as in Python 3.x)
conn.close()
# Closing all currently connected client sockets for reading to break
# worker threads blocked on recv()
for cl_conn in conn.get_accepted():
try: try:
cl_conn.half_close() # In Python 3 we have to use buffer to push in bytes directly
except Exception: stdout = sys.stdout.buffer
# Most likely the socket have already been closed except AttributeError:
LOG.debug("Failed to close connection") stdout = sys.stdout
LOG.info("Waiting for all client threads to finish.") stdout.write(socket_path.encode('utf-8'))
for thread in threading.enumerate(): stdout.write(b'\n')
if thread.daemon: stdout.write(bytes(server.authkey))
LOG.debug("Joining thread %s", thread) sys.stdin.close()
thread.join() sys.stdout.close()
sys.stderr.close()
# Gracefully shutdown on INT or TERM signals
stop = functools.partial(daemon_stop, server)
signal.signal(signal.SIGTERM, stop)
signal.signal(signal.SIGINT, stop)
LOG.info("Starting rootwrap daemon main loop")
server.serve_forever()
finally:
conn = server.listener
# This will break accept() loop with EOFError if it was not in the
# main thread (as in Python 3.x)
conn.close()
# Closing all currently connected client sockets for reading to
# break worker threads blocked on recv()
for cl_conn in conn.get_accepted():
try:
cl_conn.half_close()
except Exception:
# Most likely the socket have already been closed
LOG.debug("Failed to close connection")
LOG.info("Waiting for all client threads to finish.")
for thread in threading.enumerate():
if thread.daemon:
LOG.debug("Joining thread %s", thread)
thread.join()
finally:
LOG.debug("Removing temporary directory %s", temp_dir) LOG.debug("Removing temporary directory %s", temp_dir)
shutil.rmtree(temp_dir) shutil.rmtree(temp_dir)

View File

@ -24,6 +24,7 @@ from six import moves
import testtools import testtools
from oslo_rootwrap import cmd from oslo_rootwrap import cmd
from oslo_rootwrap import daemon
from oslo_rootwrap import filters from oslo_rootwrap import filters
from oslo_rootwrap import wrapper from oslo_rootwrap import wrapper
@ -583,3 +584,19 @@ class RunOneCommandTestCase(testtools.TestCase):
def test_negative_returncode(self): def test_negative_returncode(self):
self._test_returncode_helper(-1, 129) self._test_returncode_helper(-1, 129)
class DaemonCleanupException(Exception):
pass
class DaemonCleanupTestCase(testtools.TestCase):
@mock.patch('os.chmod')
@mock.patch('shutil.rmtree')
@mock.patch('tempfile.mkdtemp')
@mock.patch('multiprocessing.managers.BaseManager.get_server',
side_effect=DaemonCleanupException)
def test_daemon_no_cleanup_for_uninitialized_server(self, gs, *args):
self.assertRaises(DaemonCleanupException, daemon.daemon_start,
config=None, filters=None)