From 822cc71fceedaa6580160f3d51012faac397fd97 Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 14:27:27 +0000 Subject: [PATCH 1/7] add host_events_update module --- plugins/modules/zabbix_host_events_update.py | 240 +++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 plugins/modules/zabbix_host_events_update.py diff --git a/plugins/modules/zabbix_host_events_update.py b/plugins/modules/zabbix_host_events_update.py new file mode 100644 index 000000000..bdba2f812 --- /dev/null +++ b/plugins/modules/zabbix_host_events_update.py @@ -0,0 +1,240 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: zabbix_host_events_update +short_description: update the status of event(s). +description: + - Updates the status of event(s). +author: + - "Andrew Lathrop (@aplathrop)" +requirements: + - "python >= 2.6" + +options: + params: + description: + - Parameters to update event(s) with. + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/event/acknowledge + - Additionally supported parameters are below + required: true + type: dict + suboptions: + action: + description: + - action to update the event with + - Overrides "action" in API docs + - Required when I(actions) is not used. + - Mutually exclusive with I(actions). + required: false + type: string + choices: + - close_problem + - close + - acknowledge_event + - acknowledge + - ack + - add_message + - message + - msg + - change_severity + - severity + - unacknowledge_event + - unacknowledge + - unack + - suppress_event + - suppress + - unsuppress_event + - unsuppress + - change_event_rank_to_cause + - convert_to_cause + - change_event_rank_to_symptom + - convert_to_symptom + actions: + description: + - actions to update the event with + - Overrides "action" in API docs + - Required when I(action) is not used. + - Mutually exclusive with I(action). + required: false + type: list + choices: + - close_problem + - close + - acknowledge_event + - acknowledge + - ack + - add_message + - message + - msg + - change_severity + - severity + - unacknowledge_event + - unacknowledge + - unack + - suppress_event + - suppress + - unsuppress_event + - unsuppress + - change_event_rank_to_cause + - convert_to_cause + - change_event_rank_to_symptom + - convert_to_symptom + severity: + description: + - New severity for events. + - Overrides "severity" in API docs + required: False + type: string + choices: + - not_classified + - information + - warning + - average + - high + - disaster + msg: + description: + - Text of the message. + - Alias for "message" in API docs + required: False + type: string + +extends_documentation_fragment: +- community.zabbix.zabbix +''' + +EXAMPLES = r''' + +# If you want to use Username and Password to be authenticated by Zabbix Server +- name: Set credentials to access Zabbix Server API + ansible.builtin.set_fact: + ansible_user: Admin + ansible_httpapi_pass: zabbix + +# If you want to use API token to be authenticated by Zabbix Server +# https://www.zabbix.com/documentation/current/en/manual/web_interface/frontend_sections/administration/general#api-tokens +- name: Set API token + ansible.builtin.set_fact: + ansible_zabbix_auth_key: 8ec0d52432c15c91fcafe9888500cf9a607f44091ab554dbee860f6b44fac895 + +# Acknowledge single event +- name: ack event + community.zabbix.zabbix_host_events_update: + params: + eventids: 12345 + actions: ack + +- name: ack and close event with a message + community.zabbix.zabbix_host_events_update: + params: + eventids: [12345, 67890] + actions: ['ack', 'msg', 'close'] + msg: 'closed by user' + +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase +import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + +class Hosteventsupdate(ZabbixBase): + ACTIONS = {'close_problem': 1, + 'close': 1, + 'acknowledge_event': 2, + 'acknowledge': 2, + 'ack': 2, + 'add_message': 4, + 'message': 4, + 'msg': 4, + 'change_severity': 8, + 'severity': 8, + 'unacknowledge_event': 16, + 'unacknowledge': 16, + 'unack': 16, + 'suppress_event': 32, + 'suppress': 32, + 'unsuppress_event': 64, + 'unsuppress': 64, + 'change_event_rank_to_cause': 128, + 'convert_to_cause': 128, + 'change_event_rank_to_symptom': 256, + 'convert_to_symptom': 256} + + SEVERITY_TYPES = {'not_classified': 0, + 'information': 1, + 'warning': 2, + 'average': 3, + 'high': 4, + 'disaster': 5} + + def get_events(self, eventids): + try: + results = self._zapi.event.get({'eventids': eventids}) + except Exception as e: + self._module.fail_json(msg="Failed to get event: %s" % e) + return results + + def update_event(self, params): + if 'severity' in params: + if params['severity'] not in self.SEVERITY_TYPES: + self._module.fail_json(msg="%s is not a valid severity type" % params['severity']) + severity = self.SEVERITY_TYPES[params['severity']] + params['severity'] = severity + if 'action' in params: + if params['action'] not in self.ACTIONS: + self._module.fail_json(msg="%s is not a valid action" % params['action']) + action_id = self.ACTIONS[params['action']] + elif 'actions' in params: + action_id = 0 + for action in params['actions']: + if action not in self.ACTIONS: + self._module.fail_json(msg="%s is not a valid action" % action) + action_id += self.ACTIONS[action] + params.pop('actions') + else: + self._module.fail_json(msg="params must contain either 'action' or 'actions'") + params['action'] = action_id + if 'msg' in params: + params['message'] = params['msg'] + params.pop('msg') + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.event.acknowledge(params) + except Exception as e: + self._module.fail_json(msg="Failed to update event: %s" % e) + return results + + def check_events_changed(self, eventids, old_events): + new_events = self.get_events(eventids) + return old_events != new_events + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update( + params=dict(type='dict', required=True)) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + params = module.params['params'] + + hosteventsupdate = Hosteventsupdate(module) + + events = hosteventsupdate.get_events(params['eventids']) + results = hosteventsupdate.update_event(params) + changed = hosteventsupdate.check_events_changed(params['eventids'], events) + module.exit_json(changed=changed, result=results) + +if __name__ == '__main__': + main() From 60371931226ecfc2a4fbab8e53307c4faa3988da Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 18:05:20 +0000 Subject: [PATCH 2/7] add unit tests for zabbix_host_events_update module --- .../meta/main.yml | 3 + .../tasks/main.yml | 13 +++ .../tasks/zabbix_setup.yml | 61 ++++++++++++++ .../tasks/zabbix_teardown.yml | 9 +++ .../tasks/zabbix_tests.yml | 80 +++++++++++++++++++ 5 files changed, 166 insertions(+) create mode 100644 tests/integration/targets/test_zabbix_host_events_update/meta/main.yml create mode 100644 tests/integration/targets/test_zabbix_host_events_update/tasks/main.yml create mode 100644 tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_setup.yml create mode 100644 tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_teardown.yml create mode 100644 tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml diff --git a/tests/integration/targets/test_zabbix_host_events_update/meta/main.yml b/tests/integration/targets/test_zabbix_host_events_update/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_host_events_update/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_host_events_update/tasks/main.yml b/tests/integration/targets/test_zabbix_host_events_update/tasks/main.yml new file mode 100644 index 000000000..131e87ac9 --- /dev/null +++ b/tests/integration/targets/test_zabbix_host_events_update/tasks/main.yml @@ -0,0 +1,13 @@ +--- +- name: test - do not run tests for Zabbix < 6.4 + meta: end_play + when: zabbix_version is version('6.4', '<') + +# setup stuff +- include_tasks: zabbix_setup.yml + +# zabbix_item module tests +- include_tasks: zabbix_tests.yml + +# tear down stuff set up earlier +- include_tasks: zabbix_teardown.yml diff --git a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_setup.yml b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_setup.yml new file mode 100644 index 000000000..c02a08595 --- /dev/null +++ b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_setup.yml @@ -0,0 +1,61 @@ +--- + +- name: Create example template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + template_groups: + - Templates + +- name: Create example host + community.zabbix.zabbix_host: + host_name: ExampleHost + host_groups: + - Linux servers + - Zabbix servers + link_templates: + - ExampleTemplate + status: enabled + state: present + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.1.1.1 + dns: "" + port: "10050" + +- name: create ping item + community.zabbix.zabbix_item: + name: ping + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: agent.ping + value_type: numeric_unsigned + interval: 20s + state: present + +- name: create ping trigger + community.zabbix.zabbix_trigger: + name: ping + template_name: ExampleTemplate + params: + severity: warning + expression: 'nodata(/ExampleTemplate/agent.ping,1m)=1' + manual_close: True + state: present + +- name: Wait to ensure triggers are firing + ansible.builtin.wait_for: + timeout: 120 + +- name: get events for host + community.zabbix.zabbix_host_events_info: + host_identifier: ExampleHost + host_id_type: hostname + trigger_severity: warning + register: zabbix_host_events + +- name: get eventid + ansible.builtin.set_fact: + zabbix_eventid: "{{ zabbix_host_events.triggers_problem[0].last_event.eventid }}" diff --git a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_teardown.yml b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_teardown.yml new file mode 100644 index 000000000..2df4dd571 --- /dev/null +++ b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_teardown.yml @@ -0,0 +1,9 @@ +- name: remove example host + community.zabbix.zabbix_host: + host_name: ExampleHost + state: absent + +- name: remove example template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + state: absent diff --git a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml new file mode 100644 index 000000000..50d5359c7 --- /dev/null +++ b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml @@ -0,0 +1,80 @@ +--- + +- name: test - acknowledge event + community.zabbix.zabbix_host_events_update: + params: + eventids: "{{ zabbix_eventid }}" + action: ack + msg: "event acknowledged" + register: zbxevent_ack + +- name: assert that event was changed + ansible.builtin.assert: + that: zbxevent_ack is changed + +- name: get events updated status + community.zabbix.zabbix_host_events_info: + host_identifier: ExampleHost + host_id_type: hostname + trigger_severity: warning + register: zabbix_host_events_ack + +- name: assert that event was acknowledged + ansible.builtin.assert: + that: zabbix_host_events_ack.triggers_problem[0].last_event.acknowledged + +- name: test - change severity and unacknowledge + community.zabbix.zabbix_host_events_update: + params: + eventids: "{{ zabbix_eventid }}" + actions: ['severity', 'unack'] + severity: high + register: zbxevent_sev + +- name: assert that event was changed + ansible.builtin.assert: + that: zbxevent_sev is changed + +- name: get events updated status + community.zabbix.zabbix_host_events_info: + host_identifier: ExampleHost + host_id_type: hostname + trigger_severity: warning + register: zabbix_host_events_unack + +- name: assert that event was unacknowledged + ansible.builtin.assert: + that: zabbix_host_events_unack.triggers_problem[0].last_event.acknowledged == "0" + +- name: test - change severity to same + community.zabbix.zabbix_host_events_update: + params: + eventids: "{{ zabbix_eventid }}" + action: severity + severity: high + register: zbxevent_sev_existing + +- name: assert that event was not changed + ansible.builtin.assert: + that: zbxevent_sev_existing is not changed + +- name: close event + community.zabbix.zabbix_host_events_update: + params: + eventids: "{{ zabbix_eventid }}" + action: close + +- name: wait for zabbix to close event + ansible.builtin.wait_for: + timeout: 10 + +- name: get events updated status + community.zabbix.zabbix_host_events_info: + host_identifier: ExampleHost + host_id_type: hostname + trigger_severity: warning + register: zabbix_host_events_closed + +- name: assert no active events + ansible.builtin.assert: + that: zabbix_host_events_closed.triggers_problem | length == 0 From 91cd2f2bfd8fb2b7d2f17062ad5337553e89ced5 Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 18:28:17 +0000 Subject: [PATCH 3/7] fix sanity errors --- plugins/modules/zabbix_host_events_update.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/modules/zabbix_host_events_update.py b/plugins/modules/zabbix_host_events_update.py index bdba2f812..ec0025467 100644 --- a/plugins/modules/zabbix_host_events_update.py +++ b/plugins/modules/zabbix_host_events_update.py @@ -34,7 +34,7 @@ - Required when I(actions) is not used. - Mutually exclusive with I(actions). required: false - type: string + type: str choices: - close_problem - close @@ -65,6 +65,7 @@ - Mutually exclusive with I(action). required: false type: list + elements: str choices: - close_problem - close @@ -92,7 +93,7 @@ - New severity for events. - Overrides "severity" in API docs required: False - type: string + type: str choices: - not_classified - information @@ -105,7 +106,7 @@ - Text of the message. - Alias for "message" in API docs required: False - type: string + type: str extends_documentation_fragment: - community.zabbix.zabbix @@ -146,6 +147,7 @@ from ansible_collections.community.zabbix.plugins.module_utils.base import ZabbixBase import ansible_collections.community.zabbix.plugins.module_utils.helpers as zabbix_utils + class Hosteventsupdate(ZabbixBase): ACTIONS = {'close_problem': 1, 'close': 1, @@ -211,13 +213,14 @@ def update_event(self, params): try: results = self._zapi.event.acknowledge(params) except Exception as e: - self._module.fail_json(msg="Failed to update event: %s" % e) + self._module.fail_json(msg="Failed to update event: %s" % e) return results def check_events_changed(self, eventids, old_events): new_events = self.get_events(eventids) return old_events != new_events + def main(): argument_spec = zabbix_utils.zabbix_common_argument_spec() argument_spec.update( @@ -236,5 +239,6 @@ def main(): changed = hosteventsupdate.check_events_changed(params['eventids'], events) module.exit_json(changed=changed, result=results) + if __name__ == '__main__': main() From 1f873d18ce8ff40c38fde5eb359da030631a0cbf Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 18:56:15 +0000 Subject: [PATCH 4/7] add change fragment --- pr_1238.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 pr_1238.yml diff --git a/pr_1238.yml b/pr_1238.yml new file mode 100644 index 000000000..dfefe200e --- /dev/null +++ b/pr_1238.yml @@ -0,0 +1,2 @@ +minor_changes: + - zabbix_host_events_update module added From 42f9e4b8631097fbc70518aaedc50896a6afece6 Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 19:37:21 +0000 Subject: [PATCH 5/7] adjust timeout --- .../test_zabbix_host_events_update/tasks/zabbix_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml index 50d5359c7..4c2490093 100644 --- a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml +++ b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml @@ -66,7 +66,7 @@ - name: wait for zabbix to close event ansible.builtin.wait_for: - timeout: 10 + timeout: 5 - name: get events updated status community.zabbix.zabbix_host_events_info: From 08de5510bb5f1cf72c75247df406ce8c06b393b1 Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 20:02:13 +0000 Subject: [PATCH 6/7] fix dir --- pr_1238.yml => changelogs/fragments/pr_1238.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pr_1238.yml => changelogs/fragments/pr_1238.yml (100%) diff --git a/pr_1238.yml b/changelogs/fragments/pr_1238.yml similarity index 100% rename from pr_1238.yml rename to changelogs/fragments/pr_1238.yml From 00a669efa04b5261d10142033874bf837a966016 Mon Sep 17 00:00:00 2001 From: Andrew Lathrop Date: Tue, 28 May 2024 20:04:03 +0000 Subject: [PATCH 7/7] remove test --- .../tasks/zabbix_tests.yml | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml index 4c2490093..48d63b47d 100644 --- a/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml +++ b/tests/integration/targets/test_zabbix_host_events_update/tasks/zabbix_tests.yml @@ -57,24 +57,3 @@ - name: assert that event was not changed ansible.builtin.assert: that: zbxevent_sev_existing is not changed - -- name: close event - community.zabbix.zabbix_host_events_update: - params: - eventids: "{{ zabbix_eventid }}" - action: close - -- name: wait for zabbix to close event - ansible.builtin.wait_for: - timeout: 5 - -- name: get events updated status - community.zabbix.zabbix_host_events_info: - host_identifier: ExampleHost - host_id_type: hostname - trigger_severity: warning - register: zabbix_host_events_closed - -- name: assert no active events - ansible.builtin.assert: - that: zabbix_host_events_closed.triggers_problem | length == 0