Merge "Add setproctitle support to the workers module"
This commit is contained in:
commit
66c415280a
@ -78,6 +78,7 @@ requests==2.14.2
|
|||||||
requestsexceptions==1.2.0
|
requestsexceptions==1.2.0
|
||||||
rfc3986==0.3.1
|
rfc3986==0.3.1
|
||||||
Routes==2.3.1
|
Routes==2.3.1
|
||||||
|
setproctitle==1.1.10
|
||||||
six==1.10.0
|
six==1.10.0
|
||||||
snowballstemmer==1.2.1
|
snowballstemmer==1.2.1
|
||||||
Sphinx==1.6.2
|
Sphinx==1.6.2
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from neutron_lib.callbacks import events
|
from neutron_lib.callbacks import events
|
||||||
@ -34,6 +36,14 @@ class _BaseWorker(worker.BaseWorker):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# Same as _BaseWorker, but looks like a process launch instead of eventlet
|
||||||
|
class _ProcWorker(_BaseWorker):
|
||||||
|
|
||||||
|
def __init__(self, worker_process_count=1, set_proctitle='on'):
|
||||||
|
super(_ProcWorker, self).__init__(worker_process_count, set_proctitle)
|
||||||
|
self._my_pid = -1 # make it appear to be a separate process
|
||||||
|
|
||||||
|
|
||||||
class TestBaseWorker(base.BaseTestCase):
|
class TestBaseWorker(base.BaseTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -51,3 +61,77 @@ class TestBaseWorker(base.BaseTestCase):
|
|||||||
base_worker.start()
|
base_worker.start()
|
||||||
self._reg.notify.assert_called_once_with(
|
self._reg.notify.assert_called_once_with(
|
||||||
resources.PROCESS, events.AFTER_INIT, base_worker.start)
|
resources.PROCESS, events.AFTER_INIT, base_worker.start)
|
||||||
|
|
||||||
|
# Forked workers, should call setproctitle
|
||||||
|
|
||||||
|
def test_proctitle_default(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start()
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^neutron-server: _ProcWorker \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_proctitle_custom_desc(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start(desc="fancy title")
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^neutron-server: fancy title \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_proctitle_custom_name(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start(name="tardis")
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^tardis: _ProcWorker \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_proctitle_empty(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start(desc="")
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^neutron-server: _ProcWorker \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_proctitle_nonstring(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start(desc=2)
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^neutron-server: 2 \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_proctitle_both_empty(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start(name="", desc="")
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^: _ProcWorker \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_proctitle_name_none(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker().start(name=None)
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^None: _ProcWorker \(.*python.*\)$')
|
||||||
|
|
||||||
|
# Forked, but proctitle disabled
|
||||||
|
|
||||||
|
def test_proctitle_off(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker(set_proctitle='off').start()
|
||||||
|
self.assertIsNone(spt.call_args)
|
||||||
|
|
||||||
|
# Eventlet style worker, should never call setproctitle
|
||||||
|
|
||||||
|
def test_proctitle_same_process(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_BaseWorker().start()
|
||||||
|
self.assertIsNone(spt.call_args)
|
||||||
|
|
||||||
|
def test_setproctitle_on(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker(set_proctitle='on').start(name="foo", desc="bar")
|
||||||
|
six.assertRegex(self, spt.call_args[0][0],
|
||||||
|
'^foo: bar \(.*python.*\)$')
|
||||||
|
|
||||||
|
def test_setproctitle_off(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker(set_proctitle='off').start(name="foo", desc="bar")
|
||||||
|
self.assertIsNone(spt.call_args)
|
||||||
|
|
||||||
|
def test_setproctitle_brief(self):
|
||||||
|
with mock.patch('setproctitle.setproctitle') as spt:
|
||||||
|
_ProcWorker(set_proctitle='brief').start(name="foo", desc="bar")
|
||||||
|
self.assertEqual(spt.call_args[0][0], 'foo: bar')
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from oslo_service import service
|
from oslo_service import service
|
||||||
|
import setproctitle
|
||||||
|
|
||||||
from neutron_lib.callbacks import events
|
from neutron_lib.callbacks import events
|
||||||
from neutron_lib.callbacks import registry
|
from neutron_lib.callbacks import registry
|
||||||
@ -45,15 +48,24 @@ class BaseWorker(service.ServiceBase):
|
|||||||
# default class value for case when super().__init__ is not called
|
# default class value for case when super().__init__ is not called
|
||||||
_default_process_count = 1
|
_default_process_count = 1
|
||||||
|
|
||||||
def __init__(self, worker_process_count=_default_process_count):
|
def __init__(self, worker_process_count=_default_process_count,
|
||||||
|
set_proctitle='on'):
|
||||||
"""Initialize a worker instance.
|
"""Initialize a worker instance.
|
||||||
|
|
||||||
:param worker_process_count: Defines how many processes to spawn for
|
:param worker_process_count: Defines how many processes to spawn for
|
||||||
worker:
|
worker:
|
||||||
0 - spawn 1 new worker thread,
|
0 - spawn 1 new worker thread,
|
||||||
1..N - spawn N new worker processes
|
1..N - spawn N new worker processes
|
||||||
|
set_proctitle:
|
||||||
|
'off' - do not change process title
|
||||||
|
'on' - set process title to descriptive string and parent
|
||||||
|
'brief' - set process title to descriptive string
|
||||||
"""
|
"""
|
||||||
self._worker_process_count = worker_process_count
|
self._worker_process_count = worker_process_count
|
||||||
|
self._my_pid = os.getpid()
|
||||||
|
self._set_proctitle = set_proctitle
|
||||||
|
if set_proctitle == 'on':
|
||||||
|
self._parent_proctitle = setproctitle.getproctitle()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def worker_process_count(self):
|
def worker_process_count(self):
|
||||||
@ -63,13 +75,33 @@ class BaseWorker(service.ServiceBase):
|
|||||||
"""
|
"""
|
||||||
return self._worker_process_count
|
return self._worker_process_count
|
||||||
|
|
||||||
def start(self):
|
def setproctitle(self, name="neutron-server", desc=None):
|
||||||
|
if self._set_proctitle == "off" or os.getpid() == self._my_pid:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not desc:
|
||||||
|
desc = self.__class__.__name__
|
||||||
|
|
||||||
|
proctitle = "%s: %s" % (name, desc)
|
||||||
|
if self._set_proctitle == "on":
|
||||||
|
proctitle += " (%s)" % self._parent_proctitle
|
||||||
|
|
||||||
|
setproctitle.setproctitle(proctitle)
|
||||||
|
|
||||||
|
def start(self, name="neutron-server", desc=None):
|
||||||
"""Start the worker.
|
"""Start the worker.
|
||||||
|
|
||||||
If worker_process_count is greater than 0, a callback notification
|
If worker_process_count is greater than 0, a callback notification
|
||||||
is sent. Subclasses should call this method before doing their
|
is sent. Subclasses should call this method before doing their
|
||||||
own start() work.
|
own start() work.
|
||||||
|
|
||||||
|
Automatically sets the process title to indicate that this is a
|
||||||
|
child worker, customizable via the name and desc arguments.
|
||||||
|
|
||||||
:returns: None
|
:returns: None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# If we are a child process, set our proctitle to something useful
|
||||||
|
self.setproctitle(name, desc)
|
||||||
if self.worker_process_count > 0:
|
if self.worker_process_count > 0:
|
||||||
registry.notify(resources.PROCESS, events.AFTER_INIT, self.start)
|
registry.notify(resources.PROCESS, events.AFTER_INIT, self.start)
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
features:
|
||||||
|
- |
|
||||||
|
``neutron_lib.worker.BaseWorker`` will now set the process title
|
||||||
|
on process start, if it is a new process. By default, the name
|
||||||
|
will be "neutron-server", and the description will be the name
|
||||||
|
of the worker class, followed by the original process title.
|
||||||
|
Both fields are customizable via the ``name`` and ``desc``
|
||||||
|
arguments to ``BaseWorker.start()``, and the change
|
||||||
|
can be disabled via the ``set_proctitle`` argument to the
|
||||||
|
``__init__`` function. ``neutron.conf`` will have a setting
|
||||||
|
for disabling this functionality for all in-tree workers, but
|
||||||
|
by default, all out of tree plugin workers will set their name
|
||||||
|
at fork time. Available settings are 'on' (described above, and
|
||||||
|
the default), 'off' (same as today), or 'brief', which settings
|
||||||
|
the process name to just name and description. 'brief' is probably
|
||||||
|
most useful/simple for deployers, but 'on' is the default in order
|
||||||
|
to prevent as many script related breakages as possible.
|
||||||
|
upgrade:
|
||||||
|
- Any plugin which forks worker processes from neutron-server will
|
||||||
|
have its proctitle set to "neutron-server" plus a classname in ps
|
||||||
|
output. Any tool used for monitoring/maintenance that watches
|
||||||
|
the process table should be modified to only look for the string
|
||||||
|
``neutron-server``. On the plus side, it will now be possible
|
||||||
|
to distinguish which process belongs to which plugin, based on
|
||||||
|
the new naming. Note that the original process string is still
|
||||||
|
in the proctitle, so as long as the scripting is not looking for
|
||||||
|
a perfect string match, it should continue to work.
|
@ -22,6 +22,7 @@ oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
|
|||||||
oslo.utils>=3.33.0 # Apache-2.0
|
oslo.utils>=3.33.0 # Apache-2.0
|
||||||
oslo.versionedobjects>=1.31.2 # Apache-2.0
|
oslo.versionedobjects>=1.31.2 # Apache-2.0
|
||||||
osprofiler>=1.4.0 # Apache-2.0
|
osprofiler>=1.4.0 # Apache-2.0
|
||||||
|
setproctitle>=1.1.10 # BSD
|
||||||
WebOb>=1.7.1 # MIT
|
WebOb>=1.7.1 # MIT
|
||||||
weakrefmethod>=1.0.2;python_version=='2.7' # PSF
|
weakrefmethod>=1.0.2;python_version=='2.7' # PSF
|
||||||
os-traits>=0.9.0 # Apache-2.0
|
os-traits>=0.9.0 # Apache-2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user