From bed1dc479f5f7c3e11801065396bbd559278fa9d Mon Sep 17 00:00:00 2001 From: Graham Herceg Date: Sun, 3 Jan 2021 05:37:56 -0500 Subject: [PATCH] monit: add support for all monit services when checking process state (#1532) * add support for all monit service types * ignore case when performing check * add changelog * Escape special characters before matching Co-authored-by: Felix Fontein * escape each element individually Co-authored-by: Felix Fontein --- .../1532-monit-support-all-services.yaml | 2 + plugins/modules/monitoring/monit.py | 7 +++- .../plugins/modules/monitoring/test_monit.py | 39 +++++++++++++------ 3 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 changelogs/fragments/1532-monit-support-all-services.yaml diff --git a/changelogs/fragments/1532-monit-support-all-services.yaml b/changelogs/fragments/1532-monit-support-all-services.yaml new file mode 100644 index 0000000000..e2b0121c80 --- /dev/null +++ b/changelogs/fragments/1532-monit-support-all-services.yaml @@ -0,0 +1,2 @@ +bugfixes: + - monit - add support for all monit service checks (https://github.com/ansible-collections/community.general/pull/1532). diff --git a/plugins/modules/monitoring/monit.py b/plugins/modules/monitoring/monit.py index 7936728f04..1dfe76d65f 100644 --- a/plugins/modules/monitoring/monit.py +++ b/plugins/modules/monitoring/monit.py @@ -62,6 +62,9 @@ STATE_COMMAND_MAP = { 'restarted': 'restart' } +MONIT_SERVICES = ['Process', 'File', 'Fifo', 'Filesystem', 'Directory', 'Remote host', 'System', 'Program', + 'Network'] + @python_2_unicode_compatible class StatusValue(namedtuple("Status", "value, is_pending")): @@ -151,7 +154,9 @@ class Monit(object): return self._parse_status(out, err) def _parse_status(self, output, err): - if "Process '%s'" % self.process_name not in output: + escaped_monit_services = '|'.join([re.escape(x) for x in MONIT_SERVICES]) + pattern = "(%s) '%s'" % (escaped_monit_services, re.escape(self.process_name)) + if not re.search(pattern, output, re.IGNORECASE): return Status.MISSING status_val = re.findall(r"^\s*status\s*([\w\- ]+)", output, re.MULTILINE) diff --git a/tests/unit/plugins/modules/monitoring/test_monit.py b/tests/unit/plugins/modules/monitoring/test_monit.py index 7781f85a04..1d30812efe 100644 --- a/tests/unit/plugins/modules/monitoring/test_monit.py +++ b/tests/unit/plugins/modules/monitoring/test_monit.py @@ -12,7 +12,7 @@ from ansible_collections.community.general.tests.unit.plugins.modules.utils impo TEST_OUTPUT = """ -Process '%s' +%s '%s' status %s monitoring status Not monitored monitoring mode active @@ -106,28 +106,45 @@ def test_status_value(status_name): BASIC_OUTPUT_CASES = [ - (TEST_OUTPUT % ('processX', name), getattr(monit.Status, name.upper())) + (TEST_OUTPUT % ('Process', 'processX', name), getattr(monit.Status, name.upper())) for name in monit.StatusValue.ALL_STATUS ] @pytest.mark.parametrize('output, expected', BASIC_OUTPUT_CASES + [ ('', monit.Status.MISSING), - (TEST_OUTPUT % ('processY', 'OK'), monit.Status.MISSING), - (TEST_OUTPUT % ('processX', 'Not Monitored - start pending'), monit.Status.OK), - (TEST_OUTPUT % ('processX', 'Monitored - stop pending'), monit.Status.NOT_MONITORED), - (TEST_OUTPUT % ('processX', 'Monitored - restart pending'), monit.Status.OK), - (TEST_OUTPUT % ('processX', 'Not Monitored - monitor pending'), monit.Status.OK), - (TEST_OUTPUT % ('processX', 'Does not exist'), monit.Status.DOES_NOT_EXIST), - (TEST_OUTPUT % ('processX', 'Not monitored'), monit.Status.NOT_MONITORED), - (TEST_OUTPUT % ('processX', 'Running'), monit.Status.OK), - (TEST_OUTPUT % ('processX', 'Execution failed | Does not exist'), monit.Status.EXECUTION_FAILED), + (TEST_OUTPUT % ('Process', 'processY', 'OK'), monit.Status.MISSING), + (TEST_OUTPUT % ('Process', 'processX', 'Not Monitored - start pending'), monit.Status.OK), + (TEST_OUTPUT % ('Process', 'processX', 'Monitored - stop pending'), monit.Status.NOT_MONITORED), + (TEST_OUTPUT % ('Process', 'processX', 'Monitored - restart pending'), monit.Status.OK), + (TEST_OUTPUT % ('Process', 'processX', 'Not Monitored - monitor pending'), monit.Status.OK), + (TEST_OUTPUT % ('Process', 'processX', 'Does not exist'), monit.Status.DOES_NOT_EXIST), + (TEST_OUTPUT % ('Process', 'processX', 'Not monitored'), monit.Status.NOT_MONITORED), + (TEST_OUTPUT % ('Process', 'processX', 'Running'), monit.Status.OK), + (TEST_OUTPUT % ('Process', 'processX', 'Execution failed | Does not exist'), monit.Status.EXECUTION_FAILED), ]) def test_parse_status(output, expected): status = monit.Monit(None, '', 'processX', 0)._parse_status(output, '') assert status == expected +@pytest.mark.parametrize('output, expected', BASIC_OUTPUT_CASES + [ + (TEST_OUTPUT % ('Process', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('File', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Fifo', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Filesystem', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Directory', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Remote host', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('System', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Program', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Network', 'processX', 'OK'), monit.Status.OK), + (TEST_OUTPUT % ('Unsupported', 'processX', 'OK'), monit.Status.MISSING), +]) +def test_parse_status_supports_all_services(output, expected): + status = monit.Monit(None, '', 'processX', 0)._parse_status(output, '') + assert status == expected + + @pytest.mark.parametrize('output, expected', [ ('This is monit version 5.18.1', '5.18.1'), ('This is monit version 12.18', '12.18'),