diff --git a/masakarimonitors/privsep.py b/masakarimonitors/privsep.py new file mode 100644 index 0000000..af505b9 --- /dev/null +++ b/masakarimonitors/privsep.py @@ -0,0 +1,24 @@ +# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from oslo_privsep import capabilities as c +from oslo_privsep import priv_context + + +monitors_priv = priv_context.PrivContext( + "masakarimonitors", + cfg_section="masakarimonitors_privileged", + pypath=__name__ + ".monitors_priv", + capabilities=[c.CAP_NET_ADMIN], +) diff --git a/masakarimonitors/processmonitor/process.py b/masakarimonitors/processmonitor/process.py index bb12630..bebe32e 100644 --- a/masakarimonitors/processmonitor/process.py +++ b/masakarimonitors/processmonitor/process.py @@ -19,6 +19,7 @@ from oslo_log import log as oslo_logging import masakarimonitors.conf from masakarimonitors.i18n import _LE from masakarimonitors import manager +from masakarimonitors.processmonitor.process_handler import handle_process LOG = oslo_logging.getLogger(__name__) CONF = masakarimonitors.conf.CONF @@ -30,6 +31,7 @@ class ProcessmonitorManager(manager.Manager): def __init__(self, *args, **kwargs): super(ProcessmonitorManager, self).__init__( service_name="processmonitor", *args, **kwargs) + self.process_handler = handle_process.HandleProcess() def _load_process_list(self): try: @@ -54,6 +56,12 @@ class ProcessmonitorManager(manager.Manager): LOG.error(_LE("Failed to load process list file.")) return + # Set process_list object to the process handler. + self.process_handler.set_process_list(process_list) + + # Initial start of processes. + self.process_handler.start_processes() + except Exception as e: LOG.exception(_LE("Exception caught: %s"), e) return diff --git a/masakarimonitors/processmonitor/process_handler/__init__.py b/masakarimonitors/processmonitor/process_handler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/masakarimonitors/processmonitor/process_handler/handle_process.py b/masakarimonitors/processmonitor/process_handler/handle_process.py new file mode 100644 index 0000000..5b3e780 --- /dev/null +++ b/masakarimonitors/processmonitor/process_handler/handle_process.py @@ -0,0 +1,79 @@ +# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from oslo_log import log as oslo_logging + +import masakarimonitors.conf +from masakarimonitors.i18n import _LE +from masakarimonitors.i18n import _LI +from masakarimonitors.i18n import _LW +from masakarimonitors import utils + +LOG = oslo_logging.getLogger(__name__) +CONF = masakarimonitors.conf.CONF + + +class HandleProcess(object): + """Handle process.""" + + def __init__(self): + self.process_list = None + + def set_process_list(self, process_list): + """Set process list object. + + :param process_list: process list object + """ + self.process_list = process_list + + def _execute_cmd(self, cmd_str, run_as_root): + + # Split command string and delete empty elements. + command = cmd_str.split(' ') + command = filter(lambda x: x != '', command) + + try: + # Execute start command. + out, err = utils.execute(*command, + run_as_root=run_as_root) + + if out: + msg = ("CMD '%s' output stdout: %s") % (cmd_str, out) + LOG.info(_LI("%s"), msg) + + if err: + msg = ("CMD '%s' output stderr: %s") % (cmd_str, err) + LOG.warning(_LW("%s"), msg) + return 1 + + except Exception as e: + msg = ("CMD '%s' raised exception: %s") % (cmd_str, e) + LOG.error(_LE("%s"), e) + return 1 + + return 0 + + def start_processes(self): + """Initial start of processes. + + This method starts the processes using start command written in the + process list. + """ + for process in self.process_list: + cmd_str = process['start_command'] + + # Execute start command. + LOG.info( + _LI("Start of process with executing command: %s"), cmd_str) + self._execute_cmd(cmd_str, process['run_as_root']) diff --git a/masakarimonitors/tests/unit/processmonitor/process_handler/__init__.py b/masakarimonitors/tests/unit/processmonitor/process_handler/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py b/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py new file mode 100644 index 0000000..cdfc90e --- /dev/null +++ b/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py @@ -0,0 +1,63 @@ +# Copyright(c) 2016 Nippon Telegraph and Telephone Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import mock +import testtools + +import eventlet + +from masakarimonitors.processmonitor.process_handler import handle_process +from masakarimonitors import utils + +eventlet.monkey_patch(os=False) + +MOCK_PROCESS_LIST = [ + { + 'id': 1, + 'process_name': 'mock_process_name_A', + 'start_command': 'mock_start_command', + 'pre_start_command': 'mock_pre_start_command', + 'post_start_command': 'mock_post_start_command', + 'restart_command': 'mock_restart_command', + 'pre_restart_command': 'mock_pre_restart_command', + 'post_restart_command': 'mock_post_restart_command', + 'run_as_root': True + }, +] + + +class TestHandleProcess(testtools.TestCase): + + def setUp(self): + super(TestHandleProcess, self).setUp() + + def test_set_process_list(self): + process_list = MOCK_PROCESS_LIST + obj = handle_process.HandleProcess() + obj.set_process_list(process_list) + + @mock.patch.object(utils, 'execute') + def test_start_processes(self, + mock_execute): + process_list = MOCK_PROCESS_LIST + obj = handle_process.HandleProcess() + obj.set_process_list(process_list) + + mock_execute.return_value = ('test_stdout', 'test_stderr') + + obj.start_processes() + + mock_execute.assert_called_once_with( + MOCK_PROCESS_LIST[0].get('start_command'), + run_as_root=MOCK_PROCESS_LIST[0].get('run_as_root')) diff --git a/masakarimonitors/tests/unit/processmonitor/test_process.py b/masakarimonitors/tests/unit/processmonitor/test_process.py index 5b47be1..7f201ee 100644 --- a/masakarimonitors/tests/unit/processmonitor/test_process.py +++ b/masakarimonitors/tests/unit/processmonitor/test_process.py @@ -12,15 +12,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -import eventlet -eventlet.monkey_patch(os=False) - import mock +import testtools import yaml -import testtools +import eventlet from masakarimonitors.processmonitor import process as processmonitor_manager +from masakarimonitors.processmonitor.process_handler import handle_process + +eventlet.monkey_patch(os=False) MOCK_PROCESS_LIST = [ { @@ -41,10 +42,17 @@ class TestProcessmonitorManager(testtools.TestCase): def setUp(self): super(TestProcessmonitorManager, self).setUp() + @mock.patch.object(handle_process.HandleProcess, 'start_processes') + @mock.patch.object(handle_process.HandleProcess, 'set_process_list') @mock.patch.object(yaml, 'load') - def test_main(self, mock_load): + def test_main(self, + mock_load, + mock_set_process_list, + mock_start_processes): mock_load.return_value = MOCK_PROCESS_LIST + mock_set_process_list.return_value = None + mock_start_processes.return_value = None obj = processmonitor_manager.ProcessmonitorManager() obj.main() diff --git a/masakarimonitors/utils.py b/masakarimonitors/utils.py index 286e02e..b37be7c 100644 --- a/masakarimonitors/utils.py +++ b/masakarimonitors/utils.py @@ -21,12 +21,14 @@ import shutil import sys import tempfile +from oslo_concurrency import processutils from oslo_log import log as logging from oslo_utils import importutils import six import masakarimonitors.conf from masakarimonitors.i18n import _LE +from masakarimonitors import privsep CONF = masakarimonitors.conf.CONF @@ -91,3 +93,16 @@ def tempdir(**kwargs): shutil.rmtree(tmpdir) except OSError as e: LOG.error(_LE('Could not remove tmpdir: %s'), e) + + +@privsep.monitors_priv.entrypoint +def privsep_execute(*cmd, **kwargs): + return processutils.execute(*cmd, **kwargs) + + +def execute(*cmd, **kwargs): + """Convenience wrapper around oslo's execute() method.""" + if 'run_as_root' in kwargs and kwargs.get('run_as_root'): + return privsep_execute(*cmd, **kwargs) + else: + return processutils.execute(*cmd, **kwargs) diff --git a/requirements.txt b/requirements.txt index 8d30c7a..85285dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,10 +3,12 @@ # process, which may cause wedges in the gate later. libvirt-python>=1.2.5 # LGPLv2+ +oslo.concurrency>=3.8.0 # Apache-2.0 oslo.config>=3.10.0 # Apache-2.0 oslo.i18n>=2.1.0 # Apache-2.0 oslo.log>=1.14.0 # Apache-2.0 oslo.middleware>=3.0.0 # Apache-2.0 +oslo.privsep>=1.9.0 # Apache-2.0 oslo.service>=1.10.0 # Apache-2.0 oslo.utils>=3.11.0 # Apache-2.0 pbr>=1.8 # Apache-2.0