Find correct listener for WSGI based monasca-api

With this commit in place, monasca-api will find the correct
listener process for monasca-api rather than one of the WSGI
workers.

Change-Id: Id6356bbfee9c3069d9232d990b20174b2fb67ba7
Story: 1674406
Task: 3952
This commit is contained in:
Johannes Grassler 2017-03-20 18:47:32 +01:00 committed by Tomasz Trębski
parent 74588f1396
commit e1b2892d76
2 changed files with 43 additions and 7 deletions

View File

@ -21,10 +21,15 @@ from monasca_setup.detection.utils import watch_process_by_username
log = logging.getLogger(__name__)
_PYTHON_LANG_MARKERS = 'python', 'gunicorn', 'httpd', 'apache',
_APACHE_MARKERS = 'httpd', 'apache',
"""List of all strings in process command line that indicate application
runs in Apache/mod_wsgi"""
_PYTHON_LANG_MARKERS = ('python', 'gunicorn') + _APACHE_MARKERS
"""List of all strings that if found in process exe
mean that application runs under Python"""
_JAVA_LANG_MARKERS = 'java',
"""List of all strings that if found in process exe
mean that application runs under Java"""
_DEFAULT_API_PORT = 8070
"""Default TCP port which monasca-api process should be available by"""
@ -91,11 +96,36 @@ class MonAPI(monasca_setup.detection.Plugin):
return True
return False
def correct_apache_listener(process):
"""Sets api_process to the parent httpd process.
Method evaluates if process executable is correlated
with apache-mod_wsgi. If so, retrieves parent process.
Otherwise returns None
:param process: current process
:type process: psutil.Process
:returns: parent process or None
:rtype: (psutil.Process, None)
"""
p_exe = process.as_dict()['exe']
for m in _APACHE_MARKERS:
if m in p_exe:
return process.parent()
return None
api_process = find_process_cmdline('monasca-api')
process_found = api_process is not None
if process_found:
impl_lang = _get_impl_lang(api_process)
if impl_lang == 'python':
apache_process = correct_apache_listener(api_process)
if apache_process:
log.info('\tmonasca-api runs under Apache WSGI')
api_process = apache_process
impl_helper = self._init_impl_helper(impl_lang)
impl_helper.load_configuration()

View File

@ -102,6 +102,15 @@ class FakeProcesses(object):
return FakeProcesses.inetConnections
class FakeWSGIWorkers(FakeProcesses):
def __init__(self, cmdline=None):
self.cmdLine = cmdline
def parent(self):
return FakeProcesses()
def connections(self, *args):
return []
class TestGetImplLang(unittest.TestCase):
@mock.patch('psutil.Process')
def test_should_return_python_lang_for_gunicorn_process(self, proc):
@ -330,12 +339,10 @@ class TestMonAPIDetectionPlugin(unittest.TestCase):
@mock.patch('monasca_setup.detection.plugins.mon._MonAPIPythonHelper')
def test_should_use_python_helper_if_api_is_wsgi(self, impl_helper):
FakeProcesses.cmdLine = [_PYTHON_WSGI_CMD_API]
self._mon_api._init_impl_helper = iih = mock.Mock(
return_value=impl_helper)
self._detect()
self._detect([FakeWSGIWorkers([_PYTHON_WSGI_CMD_API])])
iih.assert_called_once_with('python')
self.assertTrue(impl_helper.load_configuration.called_once)
@ -543,12 +550,11 @@ class TestMonAPIDetectionPlugin(unittest.TestCase):
self.assertNotEqual({}, conf)
return conf
def _detect(self):
def _detect(self, retval=[FakeProcesses()]):
self._mon_api.available = False
process_iter = mock.patch.object(psutil, 'process_iter',
return_value=[FakeProcesses()])
return_value=retval)
with process_iter as mock_process_iter:
self._mon_api._detect()
self.assertTrue(mock_process_iter.called)