Self-resetting PrivContext

When nova-compute, an oslo.service, receives SIGHUP, running PrivContext
clients terminate, resulting in the shutdown of their corresponding
ClientChannel threads. Subsequent attempts to execute privileged methods
fail with EPIPE as a result.

The PrivContext._wrap'per (the meat of the entrypoint decorator) already
had a check to lazily start() the ClientChannel if that hasn't already
happened.

This commit makes ClientChannel store state indicating whether it's
still running; and adds logic to PrivContext._wrap to check that state
and reset (stop() and re-start()) the ClientChannel if it was previously
created but terminated.

Change-Id: I8096fc7fd014e6dd299fae8ab073336c7cae362a
Closes-Bug: #1715374
This commit is contained in:
Eric Fried 2019-08-23 18:45:43 -05:00
parent 14fbdc967f
commit e896ed39c4
2 changed files with 7 additions and 0 deletions

View File

@ -113,6 +113,7 @@ class Future(object):
class ClientChannel(object): class ClientChannel(object):
def __init__(self, sock): def __init__(self, sock):
self.running = False
self.writer = Serializer(sock) self.writer = Serializer(sock)
self.lock = threading.Lock() self.lock = threading.Lock()
self.reader_thread = threading.Thread( self.reader_thread = threading.Thread(
@ -127,6 +128,8 @@ class ClientChannel(object):
def _reader_main(self, reader): def _reader_main(self, reader):
"""This thread owns and demuxes the read channel""" """This thread owns and demuxes the read channel"""
with self.lock:
self.running = True
for msg in reader: for msg in reader:
msgid, data = msg msgid, data = msg
if msgid is None: if msgid is None:
@ -148,6 +151,7 @@ class ClientChannel(object):
with self.lock: with self.lock:
for mbox in self.outstanding_msgs.values(): for mbox in self.outstanding_msgs.values():
mbox.set_exception(exc) mbox.set_exception(exc)
self.running = False
def out_of_band(self, msg): def out_of_band(self, msg):
"""Received OOB message. Subclasses might want to override this.""" """Received OOB message. Subclasses might want to override this."""

View File

@ -237,6 +237,9 @@ class PrivContext(object):
def _wrap(self, func, *args, **kwargs): def _wrap(self, func, *args, **kwargs):
if self.client_mode: if self.client_mode:
name = '%s.%s' % (func.__module__, func.__name__) name = '%s.%s' % (func.__module__, func.__name__)
if self.channel is not None and not self.channel.running:
LOG.warning("RESTARTING PrivContext for %s", name)
self.stop()
if self.channel is None: if self.channel is None:
self.start() self.start()
return self.channel.remote_call(name, args, kwargs) return self.channel.remote_call(name, args, kwargs)