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:
parent
5fa8ef2c56
commit
8c0fd3f138
@ -1288,6 +1288,9 @@ def run_wsgi(conf_path, app_section, *args, **kwargs):
|
|||||||
myself = os.path.realpath(sys.argv[0])
|
myself = os.path.realpath(sys.argv[0])
|
||||||
logger.info("Old server PID=%d re'execing as: %r",
|
logger.info("Old server PID=%d re'execing as: %r",
|
||||||
orig_server_pid, [myself] + list(sys.argv))
|
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)
|
os.execv(myself, sys.argv)
|
||||||
logger.error('Somehow lived past os.execv()?!')
|
logger.error('Somehow lived past os.execv()?!')
|
||||||
exit('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)
|
os.getpid(), orig_server_pid)
|
||||||
try:
|
try:
|
||||||
got_pid = os.read(read_fd, 30)
|
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:
|
except Exception as e:
|
||||||
logger.warning('Unexpected exception while reading from '
|
logger.warning('Unexpected exception while reading from '
|
||||||
'pipe:', exc_info=True)
|
'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:
|
try:
|
||||||
os.close(read_fd)
|
os.close(read_fd)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
@ -27,7 +27,6 @@ from uuid import uuid4
|
|||||||
|
|
||||||
from six.moves import http_client as httplib
|
from six.moves import http_client as httplib
|
||||||
|
|
||||||
from swift.common.storage_policy import POLICIES
|
|
||||||
from swift.common.ring import Ring
|
from swift.common.ring import Ring
|
||||||
from swift.common.manager import Manager
|
from swift.common.manager import Manager
|
||||||
|
|
||||||
@ -230,9 +229,9 @@ class TestObjectServerReloadBase(TestWSGIServerProcessHandling):
|
|||||||
PID_TIMEOUT = 35
|
PID_TIMEOUT = 35
|
||||||
|
|
||||||
def get_ip_port(self):
|
def get_ip_port(self):
|
||||||
policy = random.choice(list(POLICIES))
|
self.policy.load_ring('/etc/swift')
|
||||||
policy.load_ring('/etc/swift')
|
self.ring_node = random.choice(
|
||||||
self.ring_node = random.choice(policy.object_ring.get_part_nodes(1))
|
self.policy.object_ring.get_part_nodes(1))
|
||||||
return self.ring_node['ip'], self.ring_node['port']
|
return self.ring_node['ip'], self.ring_node['port']
|
||||||
|
|
||||||
def start_write_req(self, conn, suffix):
|
def start_write_req(self, conn, suffix):
|
||||||
@ -240,7 +239,8 @@ class TestObjectServerReloadBase(TestWSGIServerProcessHandling):
|
|||||||
self.ring_node['device'], self.account, self.container, suffix),
|
self.ring_node['device'], self.account, self.container, suffix),
|
||||||
headers={'X-Timestamp': str(time.time()),
|
headers={'X-Timestamp': str(time.time()),
|
||||||
'Content-Type': 'application/octet-string',
|
'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):
|
def finish_write_req(self, conn):
|
||||||
conn.send(self.BODY)
|
conn.send(self.BODY)
|
||||||
@ -250,12 +250,12 @@ class TestObjectServerReloadBase(TestWSGIServerProcessHandling):
|
|||||||
got_body = resp.read()
|
got_body = resp.read()
|
||||||
self.assertEqual(resp.status // 100, 2, 'Got status %d; %r' %
|
self.assertEqual(resp.status // 100, 2, 'Got status %d; %r' %
|
||||||
(resp.status, got_body))
|
(resp.status, got_body))
|
||||||
self.assertEqual('', got_body)
|
self.assertEqual(b'', got_body)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
class TestObjectServerReload(OldReloadMixin, TestObjectServerReloadBase):
|
class TestObjectServerReload(OldReloadMixin, TestObjectServerReloadBase):
|
||||||
BODY = 'test-object' * 10
|
BODY = b'test-object' * 10
|
||||||
|
|
||||||
def test_object_reload(self):
|
def test_object_reload(self):
|
||||||
self._check_reload()
|
self._check_reload()
|
||||||
@ -263,7 +263,7 @@ class TestObjectServerReload(OldReloadMixin, TestObjectServerReloadBase):
|
|||||||
|
|
||||||
class TestObjectServerReloadSeamless(SeamlessReloadMixin,
|
class TestObjectServerReloadSeamless(SeamlessReloadMixin,
|
||||||
TestObjectServerReloadBase):
|
TestObjectServerReloadBase):
|
||||||
BODY = 'test-object' * 10
|
BODY = b'test-object' * 10
|
||||||
|
|
||||||
def test_object_reload_seamless(self):
|
def test_object_reload_seamless(self):
|
||||||
self._check_reload()
|
self._check_reload()
|
||||||
@ -331,12 +331,12 @@ class TestProxyServerReloadBase(TestWSGIServerProcessHandling):
|
|||||||
got_body = resp.read()
|
got_body = resp.read()
|
||||||
self.assertEqual(resp.status // 100, 2, 'Got status %d; %r' %
|
self.assertEqual(resp.status // 100, 2, 'Got status %d; %r' %
|
||||||
(resp.status, got_body))
|
(resp.status, got_body))
|
||||||
self.assertEqual('', got_body)
|
self.assertEqual(b'', got_body)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
class TestProxyServerReload(OldReloadMixin, TestProxyServerReloadBase):
|
class TestProxyServerReload(OldReloadMixin, TestProxyServerReloadBase):
|
||||||
BODY = 'proxy' * 10
|
BODY = b'proxy' * 10
|
||||||
|
|
||||||
def test_proxy_reload(self):
|
def test_proxy_reload(self):
|
||||||
self._check_reload()
|
self._check_reload()
|
||||||
@ -344,7 +344,7 @@ class TestProxyServerReload(OldReloadMixin, TestProxyServerReloadBase):
|
|||||||
|
|
||||||
class TestProxyServerReloadSeamless(SeamlessReloadMixin,
|
class TestProxyServerReloadSeamless(SeamlessReloadMixin,
|
||||||
TestProxyServerReloadBase):
|
TestProxyServerReloadBase):
|
||||||
BODY = 'proxy-seamless' * 10
|
BODY = b'proxy-seamless' * 10
|
||||||
|
|
||||||
def test_proxy_reload_seamless(self):
|
def test_proxy_reload_seamless(self):
|
||||||
self._check_reload()
|
self._check_reload()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user