Make PID availabe as formatstring in backdoor path

When multiple processes are spawned with the same configuration
each process has the same backdoor_socket path configured and
only the first process able to bind to the socket can later be
accessed via the backdoor. To give each process a unique socket path
we now expose the PID of the process as a format string argument,
which can then be used like this:

backdoor_socket = /var/lib/neutron/backdoor-{pid}

Change-Id: I3f86f4867eb0cd5010abadf68620aa3450d3e64d
This commit is contained in:
Sebastian Lohff 2019-05-14 10:55:18 +02:00
parent 539885155a
commit dd174fbfde
4 changed files with 44 additions and 3 deletions

View File

@ -31,7 +31,8 @@ eventlet_backdoor_opts = [
" option is mutually exclusive with 'backdoor_port' in"
" that only one should be provided. If both are provided"
" then the existence of this option overrides the usage of"
" that option.")
" that option. Inside the path {pid} will be replaced with"
" the PID of the current process.")
]
periodic_opts = [

View File

@ -214,8 +214,16 @@ def _initialize_if_enabled(conf):
# listen(). In any case, pull the port number out here.
where_running = sock.getsockname()[1]
else:
sock = _try_open_unix_domain_socket(conf.backdoor_socket)
where_running = conf.backdoor_socket
try:
backdoor_socket_path = conf.backdoor_socket.format(pid=os.getpid())
except (KeyError, IndexError, ValueError) as e:
backdoor_socket_path = conf.backdoor_socket
LOG.warning("Could not apply format string to eventlet "
"backdoor socket path ({}) - continuing with "
"unformatted path"
"".format(e))
sock = _try_open_unix_domain_socket(backdoor_socket_path)
where_running = backdoor_socket_path
# NOTE(johannes): The standard sys.displayhook will print the value of
# the last expression and set it to __builtin__._, which overwrites

View File

@ -38,6 +38,30 @@ class BackdoorSocketPathTest(base.ServiceBaseTestCase):
path = eventlet_backdoor.initialize_if_enabled(self.conf)
self.assertEqual("/tmp/my_special_socket", path)
@mock.patch.object(eventlet, 'spawn')
@mock.patch.object(eventlet, 'listen')
def test_backdoor_path_with_format_string(self, listen_mock, spawn_mock):
self.config(backdoor_socket="/tmp/my_special_socket-{pid}")
listen_mock.side_effect = mock.Mock()
path = eventlet_backdoor.initialize_if_enabled(self.conf)
expected_path = "/tmp/my_special_socket-{}".format(os.getpid())
self.assertEqual(expected_path, path)
@mock.patch.object(eventlet, 'spawn')
@mock.patch.object(eventlet, 'listen')
def test_backdoor_path_with_broken_format_string(self, listen_mock,
spawn_mock):
broken_socket_paths = [
"/tmp/my_special_socket-{}",
"/tmp/my_special_socket-{broken",
"/tmp/my_special_socket-{broken}",
]
for socket_path in broken_socket_paths:
self.config(backdoor_socket=socket_path)
listen_mock.side_effect = mock.Mock()
path = eventlet_backdoor.initialize_if_enabled(self.conf)
self.assertEqual(socket_path, path)
@mock.patch.object(os, 'unlink')
@mock.patch.object(eventlet, 'spawn')
@mock.patch.object(eventlet, 'listen')

View File

@ -0,0 +1,8 @@
---
features:
- |
The config option backdoor_socket_path now is a format string that
supports {pid}, which will be replaced with the PID of the current
process. This makes the eventlet backdoor accessible when spawning
multiple processes with the same backdoor_socket_path inside the
configuration.