py3: Make seamless reloads work

Starting with Python 3.4, newly-created file descriptors are non-inheritable
[0], which causes trouble when we try to use a pipe for IPC. Fortunately, the
same PEP that implemented this change *also* provided a new API to mark file
descriptors as being inheritable -- so just do that.

While we're at it,

* Fix up the probe tests to work on py3
* Fix up the probe tests to work when policy-0 is erasure-coded
* Decode the bytes read so py3 doesn't log a b'pid'
* Log a warning if the read() is empty; something surely went wrong
  in the re-exec

[0] https://www.python.org/dev/peps/pep-0446/

Change-Id: I2a8a9f3dc78abb99bf9cbcf6b44c32ca644bb07b
Related-Change: I3e5229d2fb04be67e53533ff65b0870038accbb7
This commit is contained in:
Tim Burke 2019-12-11 01:07:19 +00:00
parent 5fa8ef2c56
commit 8c0fd3f138
2 changed files with 24 additions and 14 deletions

View File

@ -1288,6 +1288,9 @@ def run_wsgi(conf_path, app_section, *args, **kwargs):
myself = os.path.realpath(sys.argv[0])
logger.info("Old server PID=%d re'execing as: %r",
orig_server_pid, [myself] + list(sys.argv))
if hasattr(os, 'set_inheritable'):
# See https://www.python.org/dev/peps/pep-0446/
os.set_inheritable(write_fd, True)
os.execv(myself, sys.argv)
logger.error('Somehow lived past os.execv()?!')
exit('Somehow lived past os.execv()?!')
@ -1299,12 +1302,19 @@ def run_wsgi(conf_path, app_section, *args, **kwargs):
os.getpid(), orig_server_pid)
try:
got_pid = os.read(read_fd, 30)
logger.info('Old server temporary child PID=%d notified '
'to shutdown old listen sockets by PID=%s',
os.getpid(), got_pid)
except Exception as e:
logger.warning('Unexpected exception while reading from '
'pipe:', exc_info=True)
else:
got_pid = got_pid.decode('ascii')
if got_pid:
logger.info('Old server temporary child PID=%d notified '
'to shutdown old listen sockets by PID=%s',
os.getpid(), got_pid)
else:
logger.warning('Old server temporary child PID=%d *NOT* '
'notified to shutdown old listen sockets; '
'the pipe just *died*.', os.getpid())
try:
os.close(read_fd)
except Exception:

View File

@ -27,7 +27,6 @@ from uuid import uuid4
from six.moves import http_client as httplib
from swift.common.storage_policy import POLICIES
from swift.common.ring import Ring
from swift.common.manager import Manager
@ -230,9 +229,9 @@ class TestObjectServerReloadBase(TestWSGIServerProcessHandling):
PID_TIMEOUT = 35
def get_ip_port(self):
policy = random.choice(list(POLICIES))
policy.load_ring('/etc/swift')
self.ring_node = random.choice(policy.object_ring.get_part_nodes(1))
self.policy.load_ring('/etc/swift')
self.ring_node = random.choice(
self.policy.object_ring.get_part_nodes(1))
return self.ring_node['ip'], self.ring_node['port']
def start_write_req(self, conn, suffix):
@ -240,7 +239,8 @@ class TestObjectServerReloadBase(TestWSGIServerProcessHandling):
self.ring_node['device'], self.account, self.container, suffix),
headers={'X-Timestamp': str(time.time()),
'Content-Type': 'application/octet-string',
'Content-Length': len(self.BODY)})
'Content-Length': len(self.BODY),
'X-Backend-Storage-Policy-Index': str(self.policy.idx)})
def finish_write_req(self, conn):
conn.send(self.BODY)
@ -250,12 +250,12 @@ class TestObjectServerReloadBase(TestWSGIServerProcessHandling):
got_body = resp.read()
self.assertEqual(resp.status // 100, 2, 'Got status %d; %r' %
(resp.status, got_body))
self.assertEqual('', got_body)
self.assertEqual(b'', got_body)
return resp
class TestObjectServerReload(OldReloadMixin, TestObjectServerReloadBase):
BODY = 'test-object' * 10
BODY = b'test-object' * 10
def test_object_reload(self):
self._check_reload()
@ -263,7 +263,7 @@ class TestObjectServerReload(OldReloadMixin, TestObjectServerReloadBase):
class TestObjectServerReloadSeamless(SeamlessReloadMixin,
TestObjectServerReloadBase):
BODY = 'test-object' * 10
BODY = b'test-object' * 10
def test_object_reload_seamless(self):
self._check_reload()
@ -331,12 +331,12 @@ class TestProxyServerReloadBase(TestWSGIServerProcessHandling):
got_body = resp.read()
self.assertEqual(resp.status // 100, 2, 'Got status %d; %r' %
(resp.status, got_body))
self.assertEqual('', got_body)
self.assertEqual(b'', got_body)
return resp
class TestProxyServerReload(OldReloadMixin, TestProxyServerReloadBase):
BODY = 'proxy' * 10
BODY = b'proxy' * 10
def test_proxy_reload(self):
self._check_reload()
@ -344,7 +344,7 @@ class TestProxyServerReload(OldReloadMixin, TestProxyServerReloadBase):
class TestProxyServerReloadSeamless(SeamlessReloadMixin,
TestProxyServerReloadBase):
BODY = 'proxy-seamless' * 10
BODY = b'proxy-seamless' * 10
def test_proxy_reload_seamless(self):
self._check_reload()