diff --git a/masakarimonitors/conf/process.py b/masakarimonitors/conf/process.py index b5de217..1dcee81 100644 --- a/masakarimonitors/conf/process.py +++ b/masakarimonitors/conf/process.py @@ -15,6 +15,9 @@ from oslo_config import cfg monitor_process_opts = [ + cfg.IntOpt('check_interval', + default=5, + help='Interval in seconds for checking a process.'), cfg.StrOpt('process_list_path', default='/etc/masakarimonitors/process_list.yaml', help='The file path of process list.'), diff --git a/masakarimonitors/processmonitor/process.py b/masakarimonitors/processmonitor/process.py index bebe32e..e52b480 100644 --- a/masakarimonitors/processmonitor/process.py +++ b/masakarimonitors/processmonitor/process.py @@ -14,6 +14,7 @@ import yaml +import eventlet from oslo_log import log as oslo_logging import masakarimonitors.conf @@ -46,6 +47,9 @@ class ProcessmonitorManager(manager.Manager): LOG.exception(_LE("Exception caught: %s"), e) return + def stop(self): + self.running = False + def main(self): """Main method.""" @@ -62,6 +66,24 @@ class ProcessmonitorManager(manager.Manager): # Initial start of processes. self.process_handler.start_processes() + self.running = True + while self.running: + # Monitor processes. + down_process_list = self.process_handler.monitor_processes() + + if len(down_process_list) != 0: + # Restart down processes. + pass + + # Reload process list and set to the process handler. + process_list = self._load_process_list() + if process_list is None: + LOG.error(_LE("Failed to reload process list file.")) + break + self.process_handler.set_process_list(process_list) + + eventlet.greenthread.sleep(CONF.process.check_interval) + except Exception as e: LOG.exception(_LE("Exception caught: %s"), e) return diff --git a/masakarimonitors/processmonitor/process_handler/handle_process.py b/masakarimonitors/processmonitor/process_handler/handle_process.py index 5b3e780..59f4e67 100644 --- a/masakarimonitors/processmonitor/process_handler/handle_process.py +++ b/masakarimonitors/processmonitor/process_handler/handle_process.py @@ -77,3 +77,30 @@ class HandleProcess(object): LOG.info( _LI("Start of process with executing command: %s"), cmd_str) self._execute_cmd(cmd_str, process['run_as_root']) + + def monitor_processes(self): + """Monitor processes. + + This method monitors the processes using process name written in the + process list. + + :returns: List of down process + """ + down_process_list = [] + for process in self.process_list: + process_name = process['process_name'] + + try: + # Execute monitoring command. + out, err = utils.execute('ps', '-ef', run_as_root=False) + if process_name in out: + LOG.debug("Process '%s' is found." % process_name) + else: + # Append down_process_list. + down_process_list.append(process) + LOG.warning( + _LW("Process '%s' is not found."), process_name) + except Exception as e: + LOG.error(_LW("Monitoring command raised exception: %s"), e) + + return down_process_list diff --git a/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py b/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py index cdfc90e..8e1deab 100644 --- a/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py +++ b/masakarimonitors/tests/unit/processmonitor/process_handler/test_handle_process.py @@ -36,6 +36,10 @@ MOCK_PROCESS_LIST = [ }, ] +PS_RESULT = "\n" \ + "UID PID PPID C STIME TTY TIME CMD\n" \ + "root 11187 1 0 18:52 ? 00:00:00 mock_process_name_A\n" + class TestHandleProcess(testtools.TestCase): @@ -61,3 +65,15 @@ class TestHandleProcess(testtools.TestCase): mock_execute.assert_called_once_with( MOCK_PROCESS_LIST[0].get('start_command'), run_as_root=MOCK_PROCESS_LIST[0].get('run_as_root')) + + @mock.patch.object(utils, 'execute') + def test_monitor_processes(self, + mock_execute): + process_list = MOCK_PROCESS_LIST + obj = handle_process.HandleProcess() + obj.set_process_list(process_list) + + mock_execute.return_value = (PS_RESULT, '') + + down_process_list = obj.monitor_processes() + self.assertEqual([], down_process_list) diff --git a/masakarimonitors/tests/unit/processmonitor/test_process.py b/masakarimonitors/tests/unit/processmonitor/test_process.py index 7f201ee..fea8b12 100644 --- a/masakarimonitors/tests/unit/processmonitor/test_process.py +++ b/masakarimonitors/tests/unit/processmonitor/test_process.py @@ -34,6 +34,17 @@ MOCK_PROCESS_LIST = [ 'post_restart_command': 'mock_post_restart_command', 'run_as_root': True }, + { + 'id': 2, + 'process_name': 'mock_process_name_B', + '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 + }, ] @@ -42,17 +53,27 @@ class TestProcessmonitorManager(testtools.TestCase): def setUp(self): super(TestProcessmonitorManager, self).setUp() + def _get_mock_process_list(self, call_count): + if call_count == 0: + return MOCK_PROCESS_LIST + else: + return + + @mock.patch.object(handle_process.HandleProcess, 'monitor_processes') @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, mock_set_process_list, - mock_start_processes): + mock_start_processes, + mock_monitor_processes): - mock_load.return_value = MOCK_PROCESS_LIST + mock_load.side_effect = [self._get_mock_process_list(0), + self._get_mock_process_list(1)] mock_set_process_list.return_value = None mock_start_processes.return_value = None + mock_monitor_processes.return_value = [] obj = processmonitor_manager.ProcessmonitorManager() obj.main()