diff --git a/changelogs/fragments/pr_1222.yml b/changelogs/fragments/pr_1222.yml new file mode 100644 index 000000000..b83746dca --- /dev/null +++ b/changelogs/fragments/pr_1222.yml @@ -0,0 +1,6 @@ +minor_changes: + - zabbix_item module added + - zabbix_trigger module added + - zabbix_discoveryrule module added + - zabbix_itemprototype module added + - zabbix_triggerprototype module added diff --git a/plugins/modules/zabbix_discoveryrule.py b/plugins/modules/zabbix_discoveryrule.py new file mode 100644 index 000000000..725fd43e3 --- /dev/null +++ b/plugins/modules/zabbix_discoveryrule.py @@ -0,0 +1,460 @@ +#!/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_discoveryrule +short_description: Create/delete Zabbix discovery rules +description: + - Create discoveryrules if they do not exist. + - Delete existing discoveryrules if they exist. +author: + - "Andrew Lathrop (@aplathrop)" +requirements: + - "python >= 2.6" + +options: + state: + description: + - Create or delete discovery rule. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + name: + description: + - Name of discovery rule to create or delete. + required: true + type: str + host_name: + description: + - Name of host to add discovery rule to. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template to add discovery rule to. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + params: + description: + - Parameters to create/update discovery rule with. + - Required if state is "present". + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/discoveryrule/object + - Additionally supported parameters are below + required: false + type: dict + suboptions: + key: + description: + - LLD rule key. + - Alias for "key_" in API docs + required: false + type: str + interval: + description: + - Update interval of the LLD rule. + - Alias for "delay" in API docs + required: false + type: str + status: + description: + - Status of the LLD rule. + required: false + type: str + choices: [ "enabled", "disabled" ] + enabled: + description: + - Status of the LLD rule. + - Overrides "status" in API docs + required: false + type: bool + type: + description: + - Type of the LLD rule. + - Required if state is "present". + required: false + type: str + choices: + - zabbix_agent + - zabbix_trapper + - simple_check + - zabbix_internal + - zabbix_agent_active + - web_item + - external_check + - database_monitor + - ipmi_agent + - ssh_agent + - telnet_agent + - calculated + - jmx_agent + - snmp_trap + - dependent_item + - http_agent + - snmp_agent + - script + preprocessing: + description: + - discovery rules preprocessing options. + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/discoveryrule/object#lld-rule-preprocessing + - Additionally supported parameters are below + required: false + type: list + elements: dict + suboptions: + type: + description: + - The preprocessing option type. + required: true + type: str + choices: + - xml_xpath + - jsonpath + - does_not_match_regular_expression + - not_match_regex + - check_for_error_in_json + - check_for_json_error + - check_for_error_in_xml + - check_for_xml_error + - discard_unchanged_with_heartbeat + - javascript + - prometheus_to_json + - csv_to_json + - replace + - xml_to_json + - snmp_walk_value + - snmp_walk_to_json + error_handler: + description: + - Action type used in case of preprocessing step failure. + required: false + type: str + choices: + - zabbix_server + - discard + - set_custom_value + - set_custom_error_message + +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 + +# Create LLD rule on example_host +- name: create rule + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discoveryrule: + name: mounted_filesystem_discovery + host_name: example_host + params: + type: zabbix_agent + key: 'vfs.fs.discovery' + interval: 1h + enabled: True + state: present + +# Create LLD rule on example_template +- name: create rule + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discoveryrule: + name: mounted_filesystem_discovery + template_name: example_template + params: + type: zabbix_agent + key: 'vfs.fs.discovery' + interval: 1h + enabled: True + state: present + +# Add tags to the existing Zabbix LLD rule +- name: update rule + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discoveryrule: + name: mounted_filesystem_discovery + template_name: example_template + params: + type: zabbix_agent + key: 'vfs.fs.discovery' + interval: 1h + enabled: True + tags: + - tag: class + value: application + state: present + +# Delete LLD rule +- name: delete rule + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_discoveryrule: + name: mounted_filesystem_discovery + template_name: example_template + state: absent +''' + +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 Discoveryrule(ZabbixBase): + ITEM_TYPES = {'zabbix_agent': 0, + 'zabbix_trapper': 2, + 'simple_check': 3, + 'zabbix_internal': 5, + 'zabbix_agent_active': 7, + 'web_item': 9, + 'external_check': 10, + 'database_monitor': 11, + 'ipmi_agent': 12, + 'ssh_agent': 13, + 'telnet_agent': 14, + 'calculated': 15, + 'jmx_agent': 16, + 'snmp_trap': 17, + 'dependent_item': 18, + 'http_agent': 19, + 'snmp_agent': 20, + 'script': 21} + + PREPROCESSING_TYPES = {'regex': 5, + 'xml_xpath': 11, + 'jsonpath': 12, + 'does_not_match_regular_expression': 15, + 'not_match_regex': 15, + 'check_for_error_in_json': 16, + 'check_for_json_error': 16, + 'check_for_error_in_xml': 17, + 'check_for_xml_error': 17, + 'discard_unchanged_with_heartbeat': 20, + 'javascript': 21, + 'prometheus_to_json': 23, + 'csv_to_json': 24, + 'replace': 25, + 'xml_to_json': 27, + 'snmp_walk_value': 28, + 'snmp_walk_to_json': 29} + + PREPROCESSING_ERROR_HANDLERS = {'zabbix_server': 0, + 'discard': 1, + 'set_custom_value': 2, + 'set_custom_error_message': 3} + + def get_hosts_templates(self, host_name, template_name): + if host_name is not None: + try: + return self._zapi.host.get({"filter": {"host": host_name}}) + except Exception as e: + self._module.fail_json(msg="Failed to get host: %s" % e) + else: + try: + return self._zapi.template.get({"filter": {"host": template_name}}) + except Exception as e: + self._module.fail_json(msg="Failed to get template: %s" % e) + + def get_discoveryrules(self, discoveryrule_name, host_name, template_name): + if host_name is not None: + host = host_name + else: + host = template_name + discoveryrules = [] + try: + discoveryrules = self._zapi.discoveryrule.get({'filter': {'name': discoveryrule_name, 'host': host}}) + except Exception as e: + self._module.fail_json(msg="Failed to get discovery rules: %s" % e) + return discoveryrules + + def sanitize_params(self, name, params): + params['name'] = name + if 'key' in params: + params['key_'] = params['key'] + params.pop("key") + if 'type' in params: + item_type_int = self.ITEM_TYPES[params['type']] + params['type'] = item_type_int + if 'interval' in params: + params['delay'] = params['interval'] + params.pop("interval") + if 'enabled' in params: + if params['enabled']: + params['status'] = 'enabled' + else: + params['status'] = 'disabled' + params.pop("enabled") + if 'status' in params: + status = params['status'] + if status == 'enabled': + params['status'] = 0 + elif status == 'disabled': + params['status'] = 1 + else: + self._module.fail_json(msg="Status must be 'enabled' or 'disabled', got %s" % status) + if 'preprocessing' in params: + for param in params['preprocessing']: + preprocess_type_int = self.PREPROCESSING_TYPES[param['type']] + param['type'] = preprocess_type_int + if 'error_handler' in param: + error_handler_int = self.PREPROCESSING_ERROR_HANDLERS[param['error_handler']] + param['error_handler'] = error_handler_int + + def add_discoveryrule(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.discoveryrule.create(params) + except Exception as e: + self._module.fail_json(msg="Failed to create discoveryrule: %s" % e) + return results + + def update_discoveryrule(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.discoveryrule.update(params) + except Exception as e: + self._module.fail_json(msg="Failed to update discoveryrule: %s" % e) + return results + + def check_discoveryrule_changed(self, old_discoveryrule): + try: + new_discoveryrule = self._zapi.discoveryrule.get({'itemids': "%s" % old_discoveryrule['itemid']})[0] + except Exception as e: + self._module.fail_json(msg="Failed to get discoveryrule: %s" % e) + return old_discoveryrule != new_discoveryrule + + def delete_discoveryrule(self, discoveryrule_id): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.discoveryrule.delete(discoveryrule_id) + except Exception as e: + self._module.fail_json(msg="Failed to delete discoveryrule: %s" % e) + return results + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + host_name=dict(type='str', required=False), + template_name=dict(type='str', required=False), + params=dict(type='dict', required=False), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['host_name', 'template_name'] + ], + mutually_exclusive=[ + ['host_name', 'template_name'] + ], + required_if=[ + ['state', 'present', ['params']] + ], + supports_check_mode=True + ) + + name = module.params['name'] + host_name = module.params['host_name'] + template_name = module.params['template_name'] + params = module.params['params'] + state = module.params['state'] + + discoveryrule = Discoveryrule(module) + + if state == "absent": + discoveryrules = discoveryrule.get_discoveryrules(name, host_name, template_name) + if len(discoveryrules) == 0: + module.exit_json(changed=False, result="No discoveryrule to delete.") + else: + delete_ids = [] + for d in discoveryrules: + delete_ids.append(d['itemid']) + results = discoveryrule.delete_discoveryrule(delete_ids) + module.exit_json(changed=True, result=results) + + elif state == "present": + discoveryrule.sanitize_params(name, params) + discoveryrules = discoveryrule.get_discoveryrules(name, host_name, template_name) + results = [] + if len(discoveryrules) == 0: + hosts_templates = discoveryrule.get_hosts_templates(host_name, template_name) + for host_template in hosts_templates: + if 'hostid' in host_template: + params['hostid'] = host_template['hostid'] + elif 'templateid' in host_template: + params['hostid'] = host_template['templateid'] + else: + module.fail_json(msg="host/template did not return id") + results.append(discoveryrule.add_discoveryrule(params)) + module.exit_json(changed=True, result=results) + else: + changed = False + for d in discoveryrules: + params['itemid'] = d['itemid'] + results.append(discoveryrule.update_discoveryrule(params)) + changed_rule = discoveryrule.check_discoveryrule_changed(d) + if changed_rule: + changed = True + module.exit_json(changed=changed, result=results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/zabbix_item.py b/plugins/modules/zabbix_item.py new file mode 100644 index 000000000..845eac85d --- /dev/null +++ b/plugins/modules/zabbix_item.py @@ -0,0 +1,516 @@ +#!/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_item +short_description: Create/delete Zabbix items +description: + - Create items if they do not exist. + - Delete existing items if they exist. +author: + - "Andrew Lathrop (@aplathrop)" +requirements: + - "python >= 2.6" + +options: + state: + description: + - Create or delete item. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + name: + description: + - Name of item to create or delete. + required: true + type: str + host_name: + description: + - Name of host to add item to. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template to add item to. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + params: + description: + - Parameters to create/update item with. + - Required if state is "present". + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/item/object + - Additionally supported parameters are below + required: false + type: dict + suboptions: + key: + description: + - Item key. + - Alias for "key_" in API docs + required: false + type: str + interval: + description: + - Update interval of the item. + - Alias for "delay" in API docs + required: false + type: str + status: + description: + - Status of the item. + required: false + type: str + choices: [ "enabled", "disabled" ] + enabled: + description: + - Status of the item. + - Overrides "status" in API docs + required: false + type: bool + type: + description: + - Type of the item. + - Required if state is "present". + required: false + type: str + choices: + - zabbix_agent + - zabbix_trapper + - simple_check + - zabbix_internal + - zabbix_agent_active + - web_item + - external_check + - database_monitor + - ipmi_agent + - ssh_agent + - telnet_agent + - calculated + - jmx_agent + - snmp_trap + - dependent_item + - http_agent + - snmp_agent + - script + value_type: + description: + - Type of information of the item. + - Required if state is "present". + required: false + type: str + choices: + - numeric_float + - character + - log + - numeric_unsigned + - text + preprocessing: + description: + - Item preprocessing options. + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/item/object#item-preprocessing + - Additionally supported parameters are below + required: false + type: list + elements: dict + suboptions: + type: + description: + - The preprocessing option type. + required: true + type: str + choices: + - custom_multiplier + - right_trim + - left_trim + - trim + - regular_expressions + - regex + - boolean_to_decimal + - octal_to_decimal + - hexadecimal_to_decimal + - simple_change + - change_per_second + - xml_xpath + - jsonpath + - in_range + - matches_regular_expression + - matches_regex + - does_not_match_regular_expression + - not_match_regex + - check_for_error_in_json + - check_for_json_error + - check_for_error_in_xml + - check_for_xml_error + - check_for_error_using_regular_expression + - check_for_error_regex + - discard_unchanged + - discard_unchanged_with_heartbeat + - javascript + - prometheus_pattern + - prometheus_to_json + - csv_to_json + - replace + - check_unsupported + - xml_to_json + - snmp_walk_value + - snmp_walk_to_json + error_handler: + description: + - Action type used in case of preprocessing step failure. + required: false + type: str + choices: + - zabbix_server + - discard + - set_custom_value + - set_custom_error_message + +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 + +# Create ping item on example_host +- name: create ping item + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_item: + name: agent_ping + host_name: example_host + params: + type: zabbix_agent + key: agent.ping + value_type: numeric_unsigned + interval: 1m + state: present + +# Create ping item on example_template +- name: create ping item + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_item: + name: agent_ping + template_name: example_template + params: + type: zabbix_agent + key: agent.ping + value_type: numeric_unsigned + interval: 1m + state: present + +- name: Add tags to the existing Zabbix item + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_item: + name: agent_ping + template_name: example_template + params: + type: zabbix_agent + key: agent.ping + value_type: numeric_unsigned + interval: 1m + tags: + - tag: class + value: application + state: present + +- name: Delete Zabbix item + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: "zabbixeu" # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_item: + name: agent_ping + template_name: example_template + state: absent +''' + +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 Item(ZabbixBase): + ITEM_TYPES = {'zabbix_agent': 0, + 'zabbix_trapper': 2, + 'simple_check': 3, + 'zabbix_internal': 5, + 'zabbix_agent_active': 7, + 'web_item': 9, + 'external_check': 10, + 'database_monitor': 11, + 'ipmi_agent': 12, + 'ssh_agent': 13, + 'telnet_agent': 14, + 'calculated': 15, + 'jmx_agent': 16, + 'snmp_trap': 17, + 'dependent_item': 18, + 'http_agent': 19, + 'snmp_agent': 20, + 'script': 21} + + VALUE_TYPES = {'numeric_float': 0, + 'character': 1, + 'log': 2, + 'numeric_unsigned': 3, + 'text': 4} + + PREPROCESSING_TYPES = {'custom_multiplier': 1, + 'right_trim': 2, + 'left_trim': 3, + 'trim': 4, + 'regular_expressions': 5, + 'regex': 5, + 'boolean_to_decimal': 6, + 'octal_to_decimal': 7, + 'hexadecimal_to_decimal': 8, + 'simple_change': 9, + 'change_per_second': 10, + 'xml_xpath': 11, + 'jsonpath': 12, + 'in_range': 13, + 'matches_regular_expression': 14, + 'matches_regex': 14, + 'does_not_match_regular_expression': 15, + 'not_match_regex': 15, + 'check_for_error_in_json': 16, + 'check_for_json_error': 16, + 'check_for_error_in_xml': 17, + 'check_for_xml_error': 17, + 'check_for_error_using_regular_expression': 18, + 'check_for_error_regex': 18, + 'discard_unchanged': 19, + 'discard_unchanged_with_heartbeat': 20, + 'javascript': 21, + 'prometheus_pattern': 22, + 'prometheus_to_json': 23, + 'csv_to_json': 24, + 'replace': 25, + 'check_unsupported': 26, + 'xml_to_json': 27, + 'snmp_walk_value': 28, + 'snmp_walk_to_json': 29} + + PREPROCESSING_ERROR_HANDLERS = {'zabbix_server': 0, + 'discard': 1, + 'set_custom_value': 2, + 'set_custom_error_message': 3} + + def get_hosts_templates(self, host_name, template_name): + if host_name is not None: + try: + return self._zapi.host.get({"filter": {"host": host_name}}) + except Exception as e: + self._module.fail_json(msg="Failed to get host: %s" % e) + else: + try: + return self._zapi.template.get({"filter": {"host": template_name}}) + except Exception as e: + self._module.fail_json(msg="Failed to get template: %s" % e) + + def get_items(self, item_name, host_name, template_name): + if host_name is not None: + host = host_name + else: + host = template_name + items = [] + try: + items = self._zapi.item.get({'filter': {'name': item_name, 'host': host}}) + except Exception as e: + self._module.fail_json(msg="Failed to get item: %s" % e) + return items + + def sanitize_params(self, name, params): + params['name'] = name + if 'key' in params: + params['key_'] = params['key'] + params.pop("key") + if 'type' in params: + item_type_int = self.ITEM_TYPES[params['type']] + params['type'] = item_type_int + if 'value_type' in params: + value_type_int = self.VALUE_TYPES[params['value_type']] + params['value_type'] = value_type_int + if 'interval' in params: + params['delay'] = params['interval'] + params.pop("interval") + if 'enabled' in params: + if params['enabled']: + params['status'] = 'enabled' + else: + params['status'] = 'disabled' + params.pop("enabled") + if 'status' in params: + status = params['status'] + if status == 'enabled': + params['status'] = 0 + elif status == 'disabled': + params['status'] = 1 + else: + self._module.fail_json(msg="Status must be 'enabled' or 'disabled', got %s" % status) + if 'preprocessing' in params: + for param in params['preprocessing']: + preprocess_type_int = self.PREPROCESSING_TYPES[param['type']] + param['type'] = preprocess_type_int + if 'error_handler' in param: + error_handler_int = self.PREPROCESSING_ERROR_HANDLERS[param['error_handler']] + param['error_handler'] = error_handler_int + + def add_item(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.item.create(params) + except Exception as e: + self._module.fail_json(msg="Failed to create item: %s" % e) + return results + + def update_item(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.item.update(params) + except Exception as e: + self._module.fail_json(msg="Failed to update item: %s" % e) + return results + + def check_item_changed(self, old_item): + try: + new_item = self._zapi.item.get({'itemids': "%s" % old_item['itemid']})[0] + except Exception as e: + self._module.fail_json(msg="Failed to get item: %s" % e) + return old_item != new_item + + def delete_item(self, item_id): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.item.delete(item_id) + except Exception as e: + self._module.fail_json(msg="Failed to delete item: %s" % e) + return results + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + host_name=dict(type='str', required=False), + template_name=dict(type='str', required=False), + params=dict(type='dict', required=False), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['host_name', 'template_name'] + ], + mutually_exclusive=[ + ['host_name', 'template_name'] + ], + required_if=[ + ['state', 'present', ['params']] + ], + supports_check_mode=True + ) + + name = module.params['name'] + host_name = module.params['host_name'] + template_name = module.params['template_name'] + params = module.params['params'] + state = module.params['state'] + + item = Item(module) + + if state == "absent": + items = item.get_items(name, host_name, template_name) + if len(items) == 0: + module.exit_json(changed=False, result="No item to delete.") + else: + delete_ids = [] + for i in items: + delete_ids.append(i['itemid']) + results = item.delete_item(delete_ids) + module.exit_json(changed=True, result=results) + + elif state == "present": + item.sanitize_params(name, params) + items = item.get_items(name, host_name, template_name) + results = [] + if len(items) == 0: + hosts_templates = item.get_hosts_templates(host_name, template_name) + for host_template in hosts_templates: + if 'hostid' in host_template: + params['hostid'] = host_template['hostid'] + elif 'templateid' in host_template: + params['hostid'] = host_template['templateid'] + else: + module.fail_json(msg="host/template did not return id") + results.append(item.add_item(params)) + module.exit_json(changed=True, result=results) + else: + changed = False + for i in items: + params['itemid'] = i['itemid'] + results.append(item.update_item(params)) + changed_item = item.check_item_changed(i) + if changed_item: + changed = True + module.exit_json(changed=changed, result=results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/zabbix_itemprototype.py b/plugins/modules/zabbix_itemprototype.py new file mode 100644 index 000000000..66e756ed4 --- /dev/null +++ b/plugins/modules/zabbix_itemprototype.py @@ -0,0 +1,541 @@ +#!/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_itemprototype +short_description: Create/delete Zabbix item prototypes +description: + - Create item prototypes if they do not exist. + - Delete existing item prototypes if they exist. +author: + - "Andrew Lathrop (@aplathrop)" +requirements: + - "python >= 2.6" + +options: + state: + description: + - Create or delete item prototype. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + name: + description: + - Name of item prototype to create or delete. + required: true + type: str + host_name: + description: + - Name of host to add item prototype to. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template to add item prototype to. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + discoveryrule_name: + description: + - Name of the LLD rule that the item belongs to. + required: true + type: str + params: + description: + - Parameters to create/update item prototype with. + - Required if state is "present". + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/itemprototype/object + - Additionally supported parameters are below + required: false + type: dict + suboptions: + key: + description: + - Item prototype key. + - Alias for "key_" in API docs + required: false + type: str + interval: + description: + - Update interval of the item prototype. + - Alias for "delay" in API docs + required: false + type: str + status: + description: + - Status of the item prototype. + required: false + type: str + choices: [ "enabled", "disabled" ] + enabled: + description: + - Status of the item prototype. + - Overrides "status" in API docs + required: false + type: bool + type: + description: + - Type of the item prototype. + - Required if state is "present". + required: false + type: str + choices: + - zabbix_agent + - zabbix_trapper + - simple_check + - zabbix_internal + - zabbix_agent_active + - web_item + - external_check + - database_monitor + - ipmi_agent + - ssh_agent + - telnet_agent + - calculated + - jmx_agent + - snmp_trap + - dependent_item + - http_agent + - snmp_agent + - script + value_type: + description: + - Type of information of the item prototype. + - Required if state is "present". + required: false + type: str + choices: + - numeric_float + - character + - log + - numeric_unsigned + - text + preprocessing: + description: + - Item preprocessing options. + - Parameters as defined at + - https://www.zabbix.com/documentation/current/en/manual/api/reference/itemprototype/object#item-prototype-preprocessing + - Additionally supported parameters are below + required: false + type: list + elements: dict + suboptions: + type: + description: + - The preprocessing option type. + required: true + type: str + choices: + - custom_multiplier + - right_trim + - left_trim + - trim + - regular_expressions + - regex + - boolean_to_decimal + - octal_to_decimal + - hexadecimal_to_decimal + - simple_change + - change_per_second + - xml_xpath + - jsonpath + - in_range + - matches_regular_expression + - matches_regex + - does_not_match_regular_expression + - not_match_regex + - check_for_error_in_json + - check_for_json_error + - check_for_error_in_xml + - check_for_xml_error + - check_for_error_using_regular_expression + - check_for_error_regex + - discard_unchanged + - discard_unchanged_with_heartbeat + - javascript + - prometheus_pattern + - prometheus_to_json + - csv_to_json + - replace + - check_unsupported + - xml_to_json + - snmp_walk_value + - snmp_walk_to_json + error_handler: + description: + - Action type used in case of preprocessing step failure. + required: false + type: str + choices: + - zabbix_server + - discard + - set_custom_value + - set_custom_error_message + +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 + +# Create item prototype on example_host using example_rule +- name: create item prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:Used space{% endraw %}' + discoveryrule_name: example_rule + host_name: example_host + params: + type: zabbix_agent + key: "{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}" + value_type: numeric_unsigned + interval: 1m + state: present + +# Create item prototype on example_template using example_rule +- name: create item prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:Used space{% endraw %}' + discoveryrule_name: example_rule + template_name: example_template + params: + type: zabbix_agent + key: "{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}" + value_type: numeric_unsigned + interval: 1m + state: present + + +# Add tags to the existing Zabbix item prototype +- name: update item prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:Used space{% endraw %}' + discoveryrule_name: example_rule + template_name: example_template + params: + type: zabbix_agent + key: "{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}" + value_type: numeric_unsigned + interval: 1m + tags: + - tag: class + value: application + state: present + +- name: Delete Zabbix item prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:Used space{% endraw %}' + discoveryrule_name: example_rule + template_name: example_template + state: absent +''' + +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 Itemprototype(ZabbixBase): + ITEM_TYPES = {'zabbix_agent': 0, + 'zabbix_trapper': 2, + 'simple_check': 3, + 'zabbix_internal': 5, + 'zabbix_agent_active': 7, + 'web_item': 9, + 'external_check': 10, + 'database_monitor': 11, + 'ipmi_agent': 12, + 'ssh_agent': 13, + 'telnet_agent': 14, + 'calculated': 15, + 'jmx_agent': 16, + 'snmp_trap': 17, + 'dependent_item': 18, + 'http_agent': 19, + 'snmp_agent': 20, + 'script': 21} + + VALUE_TYPES = {'numeric_float': 0, + 'character': 1, + 'log': 2, + 'numeric_unsigned': 3, + 'text': 4} + + PREPROCESSING_TYPES = {'custom_multiplier': 1, + 'right_trim': 2, + 'left_trim': 3, + 'trim': 4, + 'regular_expressions': 5, + 'regex': 5, + 'boolean_to_decimal': 6, + 'octal_to_decimal': 7, + 'hexadecimal_to_decimal': 8, + 'simple_change': 9, + 'change_per_second': 10, + 'xml_xpath': 11, + 'jsonpath': 12, + 'in_range': 13, + 'matches_regular_expression': 14, + 'matches_regex': 14, + 'does_not_match_regular_expression': 15, + 'not_match_regex': 15, + 'check_for_error_in_json': 16, + 'check_for_json_error': 16, + 'check_for_error_in_xml': 17, + 'check_for_xml_error': 17, + 'check_for_error_using_regular_expression': 18, + 'check_for_error_regex': 18, + 'discard_unchanged': 19, + 'discard_unchanged_with_heartbeat': 20, + 'javascript': 21, + 'prometheus_pattern': 22, + 'prometheus_to_json': 23, + 'csv_to_json': 24, + 'replace': 25, + 'check_unsupported': 26, + 'xml_to_json': 27, + 'snmp_walk_value': 28, + 'snmp_walk_to_json': 29} + + PREPROCESSING_ERROR_HANDLERS = {'zabbix_server': 0, + 'discard': 1, + 'set_custom_value': 2, + 'set_custom_error_message': 3} + + def get_hosts_templates(self, host_name, template_name): + if host_name is not None: + try: + return self._zapi.host.get({"filter": {"host": host_name}}) + except Exception as e: + self._module.fail_json(msg="Failed to get host: %s" % e) + else: + try: + return self._zapi.template.get({"filter": {"host": template_name}}) + except Exception as e: + self._module.fail_json(msg="Failed to get template: %s" % e) + + def get_discoveryrules(self, discoveryrule_name, host_name, template_name): + if host_name is not None: + host = host_name + else: + host = template_name + discoveryrules = [] + try: + discoveryrules = self._zapi.discoveryrule.get({'filter': {'name': discoveryrule_name, 'host': host}}) + except Exception as e: + self._module.fail_json(msg="Failed to get discovery rules: %s" % e) + return discoveryrules + + def get_itemprototypes(self, itemprototype_name, discoveryrule_name, host_name, template_name): + if host_name is not None: + host = host_name + else: + host = template_name + discoveryrules = self.get_discoveryrules(discoveryrule_name, host_name, template_name) + rule_ids = [] + for d in discoveryrules: + rule_ids.append(d['itemid']) + itemprototypes = [] + try: + itemprototypes = self._zapi.itemprototype.get({'filter': {'name': itemprototype_name, 'host': host, 'discoveryids': rule_ids}}) + except Exception as e: + self._module.fail_json(msg="Failed to get item: %s" % e) + return itemprototypes + + def sanitize_params(self, name, discoveryrule_name, params, host_name=None, template_name=None): + params['name'] = name + if 'key' in params: + params['key_'] = params['key'] + params.pop("key") + rules = self.get_discoveryrules(discoveryrule_name, host_name, template_name) + if len(rules) == 0: + self._module.fail_json(msg="Failed to get discoveryrule: %s" % discoveryrule_name) + params['ruleid'] = self.get_discoveryrules(discoveryrule_name, host_name, template_name)[0]['itemid'] + if 'type' in params: + item_type_int = self.ITEM_TYPES[params['type']] + params['type'] = item_type_int + if 'value_type' in params: + value_type_int = self.VALUE_TYPES[params['value_type']] + params['value_type'] = value_type_int + if 'interval' in params: + params['delay'] = params['interval'] + params.pop("interval") + if 'enabled' in params: + params['status'] = params['enabled'] + params.pop('enabled') + if 'preprocessing' in params: + for param in params['preprocessing']: + preprocess_type_int = self.PREPROCESSING_TYPES[param['type']] + param['type'] = preprocess_type_int + if 'error_handler' in param: + error_handler_int = self.PREPROCESSING_ERROR_HANDLERS[param['error_handler']] + param['error_handler'] = error_handler_int + + def add_itemprototype(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.itemprototype.create(params) + except Exception as e: + self._module.fail_json(msg="Failed to create itemprototype: %s" % e) + return results + + def update_itemprototype(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.itemprototype.update(params) + except Exception as e: + self._module.fail_json(msg="Failed to update itemprototype: %s" % e) + return results + + def check_itemprototype_changed(self, old_itemprototype): + try: + new_itemprototype = self._zapi.itemprototype.get({'itemids': '%s' % old_itemprototype['itemid']})[0] + except Exception as e: + self._module.fail_json(msg="Failed to get itemprototype: %s" % e) + return old_itemprototype != new_itemprototype + + def delete_itemprototype(self, itemprototype_id): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.itemprototype.delete(itemprototype_id) + except Exception as e: + self._module.fail_json(msg="Failed to delete itemprototype: %s" % e) + return results + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + discoveryrule_name=dict(type='str', required=True), + host_name=dict(type='str', required=False), + template_name=dict(type='str', required=False), + params=dict(type='dict', required=False), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['host_name', 'template_name'] + ], + mutually_exclusive=[ + ['host_name', 'template_name'] + ], + required_if=[ + ['state', 'present', ['params']] + ], + supports_check_mode=True + ) + + name = module.params['name'] + discoveryrule_name = module.params['discoveryrule_name'] + host_name = module.params['host_name'] + template_name = module.params['template_name'] + params = module.params['params'] + state = module.params['state'] + + itemprototype = Itemprototype(module) + + if state == "absent": + itemprototypes = itemprototype.get_itemprototypes(name, discoveryrule_name, host_name, template_name) + if len(itemprototypes) == 0: + module.exit_json(changed=False, result="No itemprototype to delete.") + else: + delete_ids = [] + for i in itemprototypes: + delete_ids.append(i['itemid']) + results = itemprototype.delete_itemprototype(delete_ids) + module.exit_json(changed=True, result=results) + + elif state == "present": + itemprototype.sanitize_params(name, discoveryrule_name, params, host_name, template_name) + itemprototypes = itemprototype.get_itemprototypes(name, discoveryrule_name, host_name, template_name) + results = [] + if len(itemprototypes) == 0: + hosts_templates = itemprototype.get_hosts_templates(host_name, template_name) + for host_template in hosts_templates: + if 'hostid' in host_template: + params['hostid'] = host_template['hostid'] + elif 'templateid' in host_template: + params['hostid'] = host_template['templateid'] + else: + module.fail_json(msg="host/template did not return id") + results.append(itemprototype.add_itemprototype(params)) + module.exit_json(changed=True, result=results) + else: + changed = False + params.pop('ruleid') + for i in itemprototypes: + params['itemid'] = i['itemid'] + results.append(itemprototype.update_itemprototype(params)) + changed_item = itemprototype.check_itemprototype_changed(i) + if changed_item: + changed = True + module.exit_json(changed=changed, result=results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/zabbix_trigger.py b/plugins/modules/zabbix_trigger.py new file mode 100644 index 000000000..9a84448c6 --- /dev/null +++ b/plugins/modules/zabbix_trigger.py @@ -0,0 +1,444 @@ +#!/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_trigger +short_description: Create/delete Zabbix triggers +description: + - Create triggers if they do not exist. + - Delete existing triggers if they exist. +author: + - "Andrew Lathrop (@aplathrop)" +requirements: + - "python >= 2.6" + +options: + state: + description: + - Create or delete trigger. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + name: + description: + - Name of trigger to create or delete. + - Overrides "description" in API docs. + - Cannot be changed. If a trigger's name needs to be changed, it needs to deleted and recreated + required: true + type: str + host_name: + description: + - Name of host to add trigger to. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template to add trigger to. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + desc: + description: + - Additional description of the trigger. + - Overrides "comments" in API docs. + required: false + type: str + aliases: [ "description" ] + dependencies: + description: + - list of triggers that this trigger is dependent on + required: false + type: list + elements: dict + suboptions: + name: + description: + - Name of dependent trigger. + required: true + type: str + host_name: + description: + - Name of host containing dependent trigger. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template containing dependent trigger. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + params: + description: + - Parameters to create/update trigger with. + - Required if state is "present". + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/trigger/object + - Additionally supported parameters are below. + required: false + type: dict + suboptions: + severity: + description: + - Severity of the trigger. + - Alias for "priority" in API docs. + required: false + type: str + aliases: [ "priority" ] + choices: + - not_classified + - information + - warning + - average + - high + - disaster + status: + description: + - Status of the trigger. + required: false + type: str + choices: [ "enabled", "disabled" ] + enabled: + description: + - Status of the trigger. + - Overrides "status" in API docs. + required: false + type: bool + generate_multiple_events: + description: + - Whether the trigger can generate multiple problem events. + - Alias for "type" in API docs. + required: false + type: bool + recovery_mode: + description: + - OK event generation mode. + - Overrides "recovery_mode" in API docs. + required: false + type: str + choices: + - expression + - recovery_expression + - none + correlation_mode: + description: + - OK event closes. + - Overrides "correlation_mode" in API docs. + required: false + type: str + choices: [ "all", "tag" ] + manual_close: + description: + - Allow manual close. + - Overrides "manual_close" in API docs. + required: false + type: bool + +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 + +# Create ping trigger on example_host +- name: create ping trigger + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_trigger: + name: agent_ping + host_name: example_host + params: + severity: high + expression: 'nodata(/example_host/agent.ping,1m)=1' + manual_close: True + enabled: True + state: present + +# Create ping trigger on example_template +- name: create ping trigger + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_trigger: + name: agent_ping + host_name: example_template + params: + severity: high + expression: 'nodata(/example_template/agent.ping,1m)=1' + manual_close: True + enabled: True + state: present + +# Add tags to the existing Zabbix trigger +- name: update ping trigger + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_trigger: + name: agent_ping + host_name: example_template + params: + severity: high + expression: 'nodata(/example_template/agent.ping,1m)=1' + manual_close: True + enabled: True + tags: + - tag: class + value: application + state: present + +# delete Zabbix trigger +- name: delete ping trigger + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_trigger: + name: agent_ping + host_name: example_template + state: absent +''' + +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 Trigger(ZabbixBase): + + PRIORITY_TYPES = {'not_classified': 0, + 'information': 1, + 'warning': 2, + 'average': 3, + 'high': 4, + 'disaster': 5} + + RECOVERY_MODES = {'expression': 0, + 'recovery_expression': 1, + 'none': 2} + + def get_triggers(self, trigger_name, host_name, template_name): + if host_name is not None: + host = host_name + else: + host = template_name + triggers = [] + try: + triggers = self._zapi.trigger.get({'filter': {'description': trigger_name, 'host': host}}) + except Exception as e: + self._module.fail_json(msg="Failed to get trigger: %s" % e) + return triggers + + def sanitize_params(self, name, params, desc=None, dependencies=None): + params['description'] = name + if desc is not None: + params['comments'] = desc + if 'severity' in params: + params['priority'] = params['severity'] + params.pop("severity") + if 'priority' in params: + priority_id = self.PRIORITY_TYPES[params['priority']] + params['priority'] = priority_id + if 'enabled' in params: + if params['enabled']: + params['status'] = 'enabled' + else: + params['status'] = 'disabled' + params.pop("enabled") + if 'status' in params: + status = params['status'] + if status == 'enabled': + params['status'] = 0 + elif status == 'disabled': + params['status'] = 1 + else: + self._module.fail_json(msg="Status must be 'enabled' or 'disabled', got %s" % status) + if 'generate_multiple_events' in params: + multiple_event_type = params['generate_multiple_events'] + if multiple_event_type: + params['type'] = 1 + else: + params['type'] = 0 + if 'recovery_mode' in params: + recovery_mode_id = self.RECOVERY_MODES[params['recovery_mode']] + params['recovery_mode'] = recovery_mode_id + if 'correlation_mode' in params: + correlation_mode = params['correlation_mode'] + if correlation_mode == 'all': + params['correlation_mode'] = 0 + elif correlation_mode == 'tag': + params['correlation_mode'] = 1 + else: + self._module.fail_json(msg="correlation_mode must be all or tag, got %s" % correlation_mode) + if 'manual_close' in params: + manual_close = params['manual_close'] + if manual_close: + params['manual_close'] = 1 + else: + params['manual_close'] = 0 + if dependencies is not None: + params['dependencies'] = [] + for dependency in dependencies: + host_name = None + template_name = None + if 'host_name' in dependency: + host_name = dependency + elif 'template_name' in dependency: + template_name = dependency + else: + self._module.fail_json(msg="Each dependency must contain either the host_name or the template_name") + triggers = self.get_triggers(dependency['name'], host_name, template_name) + for trigger in triggers: + params['dependencies'].append({'triggerid': trigger['triggerid']}) + + def add_trigger(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.trigger.create(params) + except Exception as e: + self._module.fail_json(msg="Failed to create trigger: %s" % e) + return results + + def update_trigger(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.trigger.update(params) + except Exception as e: + self._module.fail_json(msg="Failed to update trigger: %s" % e) + return results + + def check_trigger_changed(self, old_trigger): + try: + new_trigger = self._zapi.trigger.get({"triggerids": "%s" % old_trigger['triggerid']})[0] + except Exception as e: + self._module.fail_json(msg="Failed to get trigger: %s" % e) + return old_trigger != new_trigger + + def delete_trigger(self, trigger_id): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.trigger.delete(trigger_id) + except Exception as e: + self._module.fail_json(msg="Failed to delete trigger: %s" % e) + return results + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + host_name=dict(type='str', required=False), + template_name=dict(type='str', required=False), + params=dict(type='dict', required=False), + desc=dict(type='str', required=False, aliases=['description']), + dependencies=dict(type='list', elements='dict', required=False), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['host_name', 'template_name'] + ], + mutually_exclusive=[ + ['host_name', 'template_name'] + ], + required_if=[ + ['state', 'present', ['params']] + ], + supports_check_mode=True + ) + + name = module.params['name'] + host_name = module.params['host_name'] + template_name = module.params['template_name'] + params = module.params['params'] + desc = module.params['desc'] + dependencies = module.params['dependencies'] + state = module.params['state'] + + trigger = Trigger(module) + + if state == "absent": + triggers = trigger.get_triggers(name, host_name, template_name) + if len(triggers) == 0: + module.exit_json(changed=False, result="No trigger to delete.") + else: + delete_ids = [] + for t in triggers: + delete_ids.append(t['triggerid']) + results = trigger.delete_trigger(delete_ids) + module.exit_json(changed=True, result=results) + + elif state == "present": + trigger.sanitize_params(name, params, desc, dependencies) + triggers = trigger.get_triggers(name, host_name, template_name) + if len(triggers) == 0: + results = trigger.add_trigger(params) + module.exit_json(changed=True, result=results) + else: + results = [] + changed = False + for t in triggers: + params['triggerid'] = t['triggerid'] + params.pop('description') + results.append(trigger.update_trigger(params)) + changed_trigger = trigger.check_trigger_changed(t) + if changed_trigger: + changed = True + module.exit_json(changed=changed, result=results) + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/zabbix_triggerprototype.py b/plugins/modules/zabbix_triggerprototype.py new file mode 100644 index 000000000..410955be9 --- /dev/null +++ b/plugins/modules/zabbix_triggerprototype.py @@ -0,0 +1,448 @@ +#!/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_triggerprototype +short_description: Create/delete Zabbix triggerprototypes +description: + - Create triggerprototypes if they do not exist. + - Delete existing triggerprototypes if they exist. +author: + - "Andrew Lathrop (@aplathrop)" +requirements: + - "python >= 2.6" + +options: + state: + description: + - Create or delete trigger prototype. + required: false + type: str + default: "present" + choices: [ "present", "absent" ] + name: + description: + - Name of trigger prototype to create or delete. + - Overrides "description" in API docs. + - Cannot be changed. If a trigger prototype's name needs to be changed, it needs to deleted and recreated + required: true + type: str + host_name: + description: + - Name of host to add trigger prototype to. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template to add trigger prototype to. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + desc: + description: + - Additional description of the trigger prototype. + - Overrides "comments" in API docs. + required: false + type: str + aliases: [ "description" ] + dependencies: + description: + - list of trigger prototypes that this trigger prototype is dependent on + required: false + type: list + elements: dict + suboptions: + name: + description: + - Name of dependent trigger. + required: true + type: str + host_name: + description: + - Name of host containing dependent trigger. + - Required when I(template_name) is not used. + - Mutually exclusive with I(template_name). + required: false + type: str + template_name: + description: + - Name of template containing dependent trigger. + - Required when I(host_name) is not used. + - Mutually exclusive with I(host_name). + required: false + type: str + + params: + description: + - Parameters to create/update trigger prototype with. + - Required if state is "present". + - Parameters as defined at https://www.zabbix.com/documentation/current/en/manual/api/reference/triggerprototype/object + - Additionally supported parameters are below. + required: false + type: dict + suboptions: + severity: + description: + - Severity of the trigger prototype. + - Alias for "priority" in API docs. + required: false + type: str + aliases: [ "priority" ] + choices: + - not_classified + - information + - warning + - average + - high + - disaster + status: + description: + - Status of the trigger prototype. + required: false + type: str + choices: [ "enabled", "disabled" ] + enabled: + description: + - Status of the trigger prototype. + - Overrides "status" in API docs. + required: false + type: bool + generate_multiple_events: + description: + - Whether the trigger prototype can generate multiple problem events. + - Alias for "type" in API docs. + required: false + type: bool + recovery_mode: + description: + - OK event generation mode. + - Overrides "recovery_mode" in API docs. + required: false + type: str + choices: + - expression + - recovery_expression + - none + correlation_mode: + description: + - OK event closes. + - Overrides "correlation_mode" in API docs. + required: false + type: str + choices: [ "all", "tag" ] + manual_close: + description: + - Allow manual close. + - Overrides "manual_close" in API docs. + required: false + type: bool + +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 + +# Create trigger prototype on example_host using example_rule +- name: create trigger prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + host_name: example_host + params: + severity: high + expression: "{% raw %}last(/example_host/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}" + recovery_mode: none + manual_close: True + enabled: True + state: present + +# Create trigger prototype on example_template using example_rule +- name: create trigger prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: example_template + params: + severity: high + expression: "{% raw %}last(/example_host/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}" + recovery_mode: none + manual_close: True + enabled: True + state: present + +# Add tags to the existing Zabbix trigger prototype +- name: update trigger prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: example_template + params: + severity: high + expression: "{% raw %}last(/example_host/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}" + recovery_mode: none + manual_close: True + enabled: True + tags: + - tag: class + value: application + state: present + +# Delete Zabbix trigger prototype +- name: delete trigger prototype + # set task level variables as we change ansible_connection plugin here + vars: + ansible_network_os: community.zabbix.zabbix + ansible_connection: httpapi + ansible_httpapi_port: 443 + ansible_httpapi_use_ssl: true + ansible_httpapi_validate_certs: false + ansible_zabbix_url_path: 'zabbixeu' # If Zabbix WebUI runs on non-default (zabbix) path ,e.g. http:///zabbixeu + ansible_host: zabbix-example-fqdn.org + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: example_template + state: absent +''' + +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 Triggerprototype(ZabbixBase): + + PRIORITY_TYPES = {'not_classified': 0, + 'information': 1, + 'warning': 2, + 'average': 3, + 'high': 4, + 'disaster': 5} + + RECOVERY_MODES = {'expression': 0, + 'recovery_expression': 1, + 'none': 2} + + def get_triggerprototypes(self, triggerprototype_name, host_name, template_name): + if host_name is not None: + host = host_name + else: + host = template_name + triggerprototypes = [] + try: + triggerprototypes = self._zapi.triggerprototype.get({'filter': {'description': triggerprototype_name, 'host': host}}) + except Exception as e: + self._module.fail_json(msg="Failed to get triggerprototype: %s" % e) + return triggerprototypes + + def sanitize_params(self, name, params, desc=None, dependencies=None): + params['description'] = name + if desc is not None: + params['comments'] = desc + if 'severity' in params: + params['priority'] = params['severity'] + params.pop('severity') + if 'priority' in params: + priority_id = self.PRIORITY_TYPES[params['priority']] + params['priority'] = priority_id + if 'enabled' in params: + if params['enabled']: + params['status'] = 'enabled' + else: + params['status'] = 'disabled' + params.pop('enabled') + if 'status' in params: + status = params['status'] + if status == 'enabled': + params['status'] = 0 + elif status == 'disabled': + params['status'] = 1 + else: + self._module.fail_json(msg="Status must be 'enabled' or 'disabled', got %s" % status) + if 'generate_multiple_events' in params: + multiple_event_type = params['generate_multiple_events'] + if multiple_event_type: + params['type'] = 1 + else: + params['type'] = 0 + if 'recovery_mode' in params: + recovery_mode_id = self.RECOVERY_MODES[params['recovery_mode']] + params['recovery_mode'] = recovery_mode_id + if 'correlation_mode' in params: + correlation_mode = params['correlation_mode'] + if correlation_mode == 'all': + params['correlation_mode'] = 0 + elif correlation_mode == 'tag': + params['correlation_mode'] = 1 + else: + self._module.fail_json(msg="correlation_mode must be all or tag, got %s" % correlation_mode) + if 'manual_close' in params: + manual_close = params['manual_close'] + if manual_close: + params['manual_close'] = 1 + else: + params['manual_close'] = 0 + if dependencies is not None: + params['dependencies'] = [] + for dependency in dependencies: + host_name = None + template_name = None + if 'host_name' in dependency: + host_name = dependency + elif 'template_name' in dependency: + template_name = dependency + else: + self._module.fail_json(msg="Each dependency must contain either the host_name or the template_name") + triggers = self.get_triggerprototypes(dependency['name'], host_name, template_name) + for trigger in triggers: + params['dependencies'].append({'triggerid': trigger['triggerid']}) + + def add_triggerprototype(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.triggerprototype.create(params) + except Exception as e: + self._module.fail_json(msg="Failed to create triggerprototype: %s" % e) + return results + + def update_triggerprototype(self, params): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.triggerprototype.update(params) + except Exception as e: + self._module.fail_json(msg="Failed to update triggerprototype: %s" % e) + return results + + def check_triggerprototype_changed(self, old_triggerprototype): + try: + new_triggerprototype = self._zapi.triggerprototype.get({'triggerids': '%s' % old_triggerprototype['triggerid']})[0] + except Exception as e: + self._module.fail_json(msg="Failed to get triggerprototype: %s" % e) + return old_triggerprototype != new_triggerprototype + + def delete_triggerprototype(self, trigger_id): + if self._module.check_mode: + self._module.exit_json(changed=True) + try: + results = self._zapi.triggerprototype.delete(trigger_id) + except Exception as e: + self._module.fail_json(msg="Failed to delete triggerprototype: %s" % e) + return results + + +def main(): + argument_spec = zabbix_utils.zabbix_common_argument_spec() + argument_spec.update(dict( + name=dict(type='str', required=True), + host_name=dict(type='str', required=False), + template_name=dict(type='str', required=False), + params=dict(type='dict', required=False), + desc=dict(type='str', required=False, aliases=['description']), + dependencies=dict(type='list', elements='dict', required=False), + state=dict(type='str', default="present", choices=['present', 'absent']), + )) + module = AnsibleModule( + argument_spec=argument_spec, + required_one_of=[ + ['host_name', 'template_name'] + ], + mutually_exclusive=[ + ['host_name', 'template_name'] + ], + required_if=[ + ['state', 'present', ['params']] + ], + supports_check_mode=True + ) + + name = module.params['name'] + host_name = module.params['host_name'] + template_name = module.params['template_name'] + params = module.params['params'] + desc = module.params['desc'] + dependencies = module.params['dependencies'] + state = module.params['state'] + + triggerprototype = Triggerprototype(module) + + if state == "absent": + triggerprototypes = triggerprototype.get_triggerprototypes(name, host_name, template_name) + if len(triggerprototypes) == 0: + module.exit_json(changed=False, result="No triggerprototype to delete.") + else: + delete_ids = [] + for t in triggerprototypes: + delete_ids.append(t['triggerid']) + results = triggerprototype.delete_triggerprototype(delete_ids) + module.exit_json(changed=True, result=results) + + elif state == "present": + triggerprototype.sanitize_params(name, params, desc, dependencies) + triggerprototypes = triggerprototype.get_triggerprototypes(name, host_name, template_name) + if len(triggerprototypes) == 0: + results = triggerprototype.add_triggerprototype(params) + module.exit_json(changed=True, result=results) + else: + results = [] + changed = False + for t in triggerprototypes: + params['triggerid'] = t['triggerid'] + params.pop('description') + results.append(triggerprototype.update_triggerprototype(params)) + changed_trigger = triggerprototype.check_triggerprototype_changed(t) + if changed_trigger: + changed = True + module.exit_json(changed=changed, result=results) + + +if __name__ == '__main__': + main() diff --git a/tests/integration/targets/test_zabbix_discoveryrule/meta/main.yml b/tests/integration/targets/test_zabbix_discoveryrule/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_discoveryrule/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_discoveryrule/tasks/main.yml b/tests/integration/targets/test_zabbix_discoveryrule/tasks/main.yml new file mode 100644 index 000000000..8642afe46 --- /dev/null +++ b/tests/integration/targets/test_zabbix_discoveryrule/tasks/main.yml @@ -0,0 +1,29 @@ +--- +- name: test - do not run tests for Zabbix < 6.4 + meta: end_play + when: zabbix_version is version('6.4', '<') + +- block: + # setup stuff + - include_tasks: zabbix_setup.yml + + # zabbix_discoveryrule module tests + - include_tasks: zabbix_tests.yml + + # tear down stuff set up earlier + - include_tasks: zabbix_teardown.yml + + always: + - name: "cleanup discoveryrule if tests failed" + community.zabbix.zabbix_discoveryrule: + host_name: ExampleHost + name: ExampleRule + state: absent + ignore_errors: true + + - name: "cleanup discoveryrule if tests failed" + community.zabbix.zabbix_discoveryrule: + template_name: ExampleTemplate + name: ExampleRule + state: absent + ignore_errors: true diff --git a/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_setup.yml b/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_setup.yml new file mode 100644 index 000000000..4daf66abf --- /dev/null +++ b/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_setup.yml @@ -0,0 +1,25 @@ +--- + +- name: Create test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + template_groups: + - Templates + +- name: Create test 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" diff --git a/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_teardown.yml b/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_teardown.yml new file mode 100644 index 000000000..4a2ec158f --- /dev/null +++ b/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_teardown.yml @@ -0,0 +1,9 @@ +- name: remove test host + community.zabbix.zabbix_host: + host_name: ExampleHost + state: absent + +- name: remove test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + state: absent diff --git a/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_tests.yml new file mode 100644 index 000000000..ffed13e05 --- /dev/null +++ b/tests/integration/targets/test_zabbix_discoveryrule/tasks/zabbix_tests.yml @@ -0,0 +1,147 @@ +--- + +- name: test - create new Zabbix discoveryrule on host with many options set + community.zabbix.zabbix_discoveryrule: + name: TestRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxhostrule_new + +- name: assert that rule was created + ansible.builtin.assert: + that: zbxhostrule_new is changed + +- name: test - create same Zabbix discoveryrule once again + community.zabbix.zabbix_discoveryrule: + name: TestRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxhostrule_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhostrule_existing is changed + +- name: test - update existing zabbix discoveryrule + community.zabbix.zabbix_discoveryrule: + name: TestRule + host_name: ExampleHost + params: + interval: 2m + state: present + register: zbxhostrule_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxhostrule_changed is changed + +- name: test - attempt to delete previously created zabbix discoveryrule + community.zabbix.zabbix_discoveryrule: + name: TestRule + host_name: ExampleHost + state: absent + register: zbxhostrule_existing_delete + +- name: assert that trigger was deleted + ansible.builtin.assert: + that: zbxhostrule_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix discoveryrule + community.zabbix.zabbix_discoveryrule: + name: TestRule + host_name: ExampleHost + state: absent + register: zbxhostrule_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhostrule_missing_delete is changed + +- name: test - create new Zabbix discoveryrule on template with many options set + community.zabbix.zabbix_discoveryrule: + name: TestRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxtemprule_new + +- name: assert that rule was created + ansible.builtin.assert: + that: zbxtemprule_new is changed + +- name: test - create same Zabbix discoveryrule once again + community.zabbix.zabbix_discoveryrule: + name: TestRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxtemprule_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtemprule_existing is changed + +- name: test - update existing zabbix discoveryrule + community.zabbix.zabbix_discoveryrule: + name: TestRule + template_name: ExampleTemplate + params: + interval: 2m + state: present + register: zbxtemprule_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxtemprule_changed is changed + +- name: test - attempt to delete previously created zabbix discoveryrule + community.zabbix.zabbix_discoveryrule: + name: TestRule + template_name: ExampleTemplate + state: absent + register: zbxtemprule_existing_delete + +- name: assert that trigger was deleted + ansible.builtin.assert: + that: zbxtemprule_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix discoveryrule + community.zabbix.zabbix_discoveryrule: + name: TestRule + template_name: ExampleTemplate + state: absent + register: zbxtemprule_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtemprule_missing_delete is changed diff --git a/tests/integration/targets/test_zabbix_item/meta/main.yml b/tests/integration/targets/test_zabbix_item/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_item/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_item/tasks/main.yml b/tests/integration/targets/test_zabbix_item/tasks/main.yml new file mode 100644 index 000000000..531720193 --- /dev/null +++ b/tests/integration/targets/test_zabbix_item/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: test - do not run tests for Zabbix < 6.4 + meta: end_play + when: zabbix_version is version('6.4', '<') + +- block: + # 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 + always: + - name: "cleanup host item if tests failed" + community.zabbix.zabbix_item: + host_name: ExampleHost + name: TestItem + state: absent + ignore_errors: true + + - name: "cleanup template item if tests failed" + community.zabbix.zabbix_item: + template_name: ExampleTemplate + name: TestItem + state: absent + ignore_errors: true diff --git a/tests/integration/targets/test_zabbix_item/tasks/zabbix_setup.yml b/tests/integration/targets/test_zabbix_item/tasks/zabbix_setup.yml new file mode 100644 index 000000000..4daf66abf --- /dev/null +++ b/tests/integration/targets/test_zabbix_item/tasks/zabbix_setup.yml @@ -0,0 +1,25 @@ +--- + +- name: Create test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + template_groups: + - Templates + +- name: Create test 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" diff --git a/tests/integration/targets/test_zabbix_item/tasks/zabbix_teardown.yml b/tests/integration/targets/test_zabbix_item/tasks/zabbix_teardown.yml new file mode 100644 index 000000000..4a2ec158f --- /dev/null +++ b/tests/integration/targets/test_zabbix_item/tasks/zabbix_teardown.yml @@ -0,0 +1,9 @@ +- name: remove test host + community.zabbix.zabbix_host: + host_name: ExampleHost + state: absent + +- name: remove test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + state: absent diff --git a/tests/integration/targets/test_zabbix_item/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_item/tasks/zabbix_tests.yml new file mode 100644 index 000000000..3c6831acd --- /dev/null +++ b/tests/integration/targets/test_zabbix_item/tasks/zabbix_tests.yml @@ -0,0 +1,179 @@ +--- + +- name: test - create new Zabbix item on host with many options set + community.zabbix.zabbix_item: + name: TestItem + host_name: ExampleHost + params: + type: zabbix_agent_active + key: vfs.fs.get + value_type: numeric_float + units: '%' + interval: 1m + preprocessing: + - type: jsonpath + params: '$[?(@.fstype == "ext4")]' + error_handler: zabbix_server + - type: jsonpath + params: "$[*].['bytes', 'inodes'].pused.max()" + error_handler: zabbix_server + tags: + - tag: tag + value: value + state: present + register: zbxhostitem_new + +- name: assert that item was created + ansible.builtin.assert: + that: zbxhostitem_new is changed + +- name: test - create same Zabbix item group once again + community.zabbix.zabbix_item: + name: TestItem + host_name: ExampleHost + params: + type: zabbix_agent_active + key: vfs.fs.get + value_type: numeric_float + units: '%' + interval: 1m + preprocessing: + - type: jsonpath + params: '$[?(@.fstype == "ext4")]' + error_handler: zabbix_server + - type: jsonpath + params: "$[*].['bytes', 'inodes'].pused.max()" + error_handler: zabbix_server + tags: + - tag: tag + value: value + state: present + register: zbxhostitem_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhostitem_existing is changed + +- name: test - update existing zabbix item + community.zabbix.zabbix_item: + name: TestItem + host_name: ExampleHost + params: + interval: 2m + state: present + register: zbxhostitem_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxhostitem_changed is changed + +- name: test - attempt to delete previously created zabbix item + community.zabbix.zabbix_item: + name: TestItem + host_name: ExampleHost + state: absent + register: zbxhostitem_existing_delete + +- name: assert that item was deleted + ansible.builtin.assert: + that: zbxhostitem_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix item + community.zabbix.zabbix_item: + name: TestItem + host_name: ExampleHost + state: absent + register: zbxhostitem_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhostitem_missing_delete is changed + +- name: test - create new Zabbix item on template with many options set + community.zabbix.zabbix_item: + name: TestItem + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: vfs.fs.get + value_type: numeric_float + units: '%' + interval: 1m + preprocessing: + - type: jsonpath + params: '$[?(@.fstype == "ext4")]' + error_handler: zabbix_server + - type: jsonpath + params: "$[*].['bytes', 'inodes'].pused.max()" + error_handler: zabbix_server + tags: + - tag: tag + value: value + state: present + register: zbxtempitem_new + +- name: assert that item was created + ansible.builtin.assert: + that: zbxtempitem_new is changed + +- name: test - create same Zabbix item group once again + community.zabbix.zabbix_item: + name: TestItem + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: vfs.fs.get + value_type: numeric_float + units: '%' + interval: 1m + preprocessing: + - type: jsonpath + params: '$[?(@.fstype == "ext4")]' + error_handler: zabbix_server + - type: jsonpath + params: "$[*].['bytes', 'inodes'].pused.max()" + error_handler: zabbix_server + tags: + - tag: tag + value: value + state: present + register: zbxtempitem_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempitem_existing is changed + +- name: test - update existing zabbix item + community.zabbix.zabbix_item: + name: TestItem + template_name: ExampleTemplate + params: + interval: 2m + state: present + register: zbxtempitem_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxtempitem_changed is changed + +- name: test - attempt to delete previously created zabbix item + community.zabbix.zabbix_item: + name: TestItem + template_name: ExampleTemplate + state: absent + register: zbxtempitem_existing_delete + +- name: assert that item was deleted + ansible.builtin.assert: + that: zbxtempitem_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix item + community.zabbix.zabbix_item: + name: TestItem + template_name: ExampleTemplate + state: absent + register: zbxtempitem_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempitem_missing_delete is changed diff --git a/tests/integration/targets/test_zabbix_itemprototype/meta/main.yml b/tests/integration/targets/test_zabbix_itemprototype/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_itemprototype/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_itemprototype/tasks/main.yml b/tests/integration/targets/test_zabbix_itemprototype/tasks/main.yml new file mode 100644 index 000000000..ed6ca6d62 --- /dev/null +++ b/tests/integration/targets/test_zabbix_itemprototype/tasks/main.yml @@ -0,0 +1,30 @@ +--- +- name: test - do not run tests for Zabbix < 6.4 + meta: end_play + when: zabbix_version is version('6.4', '<') + +- block: + # setup stuff + - include_tasks: zabbix_setup.yml + + # zabbix_itemprototype module tests + - include_tasks: zabbix_tests.yml + + # tear down stuff set up earlier + - include_tasks: zabbix_teardown.yml + always: + - name: "cleanup host item if tests failed" + community.zabbix.zabbix_itemprototype: + host_name: ExampleHost + discoveryrule_name: ExampleHostRule + name: TestItem + state: absent + ignore_errors: true + + - name: "cleanup template item if tests failed" + community.zabbix.zabbix_itemprototype: + template_name: ExampleTemplate + discoveryrule_name: ExampleTemplateRule + name: TestItem + state: absent + ignore_errors: true diff --git a/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_setup.yml b/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_setup.yml new file mode 100644 index 000000000..62d4d5e92 --- /dev/null +++ b/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_setup.yml @@ -0,0 +1,36 @@ +--- + +- name: Create test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + template_groups: + - Templates + +- name: Create test 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 new Zabbix discoveryrule on host + community.zabbix.zabbix_discoveryrule: + name: ExampleHostRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + state: present diff --git a/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_teardown.yml b/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_teardown.yml new file mode 100644 index 000000000..4a2ec158f --- /dev/null +++ b/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_teardown.yml @@ -0,0 +1,9 @@ +- name: remove test host + community.zabbix.zabbix_host: + host_name: ExampleHost + state: absent + +- name: remove test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + state: absent diff --git a/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_tests.yml new file mode 100644 index 000000000..c27506746 --- /dev/null +++ b/tests/integration/targets/test_zabbix_itemprototype/tasks/zabbix_tests.yml @@ -0,0 +1,178 @@ +--- + +- name: test - create new Zabbix item on host with many options set + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleHostRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: '{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}' + value_type: numeric_unsigned + units: GB + interval: 1m + tags: + - tag: tag + value: value + state: present + register: zbxhostitem_new + +- name: assert that item was created + ansible.builtin.assert: + that: zbxhostitem_new is changed + +- name: test - create same Zabbix item group once again + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleHostRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: '{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}' + value_type: numeric_unsigned + units: GB + interval: 1m + tags: + - tag: tag + value: value + state: present + register: zbxhostitem_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhostitem_existing is changed + +- name: test - update existing zabbix item + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleHostRule + host_name: ExampleHost + params: + interval: 2m + state: present + register: zbxhostitem_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxhostitem_changed is changed + +- name: test - attempt to delete previously created zabbix item + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleHostRule + host_name: ExampleHost + state: absent + register: zbxhostitem_existing_delete + +- name: assert that item was deleted + ansible.builtin.assert: + that: zbxhostitem_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix item + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleHostRule + host_name: ExampleHost + state: absent + register: zbxhostitem_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhostitem_missing_delete is changed + +- name: remove host rule + community.zabbix.zabbix_discoveryrule: + name: ExampleHostRule + host_name: ExampleHost + state: absent + +- name: Create new Zabbix discoveryrule on template + community.zabbix.zabbix_discoveryrule: + name: ExampleTemplateRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + state: present + +- name: test - create new Zabbix item on template with many options set + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleTemplateRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: '{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}' + value_type: numeric_unsigned + units: GB + interval: 1m + tags: + - tag: tag + value: value + state: present + register: zbxtempitem_new + +- name: assert that item was created + ansible.builtin.assert: + that: zbxtempitem_new is changed + +- name: test - create same Zabbix item group once again + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleTemplateRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: '{% raw %}vfs.fs.size[{#FSNAME},used]{% endraw %}' + value_type: numeric_unsigned + units: GB + interval: 1m + tags: + - tag: tag + value: value + state: present + register: zbxtempitem_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempitem_existing is changed + +- name: test - update existing zabbix item + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleTemplateRule + template_name: ExampleTemplate + params: + interval: 2m + state: present + register: zbxtempitem_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxtempitem_changed is changed + +- name: test - attempt to delete previously created zabbix item + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleTemplateRule + template_name: ExampleTemplate + state: absent + register: zbxtempitem_existing_delete + +- name: assert that item was deleted + ansible.builtin.assert: + that: zbxtempitem_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix item + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:TestItemPrototype{% endraw %}' + discoveryrule_name: ExampleTemplateRule + template_name: ExampleTemplate + state: absent + register: zbxtempitem_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtempitem_missing_delete is changed diff --git a/tests/integration/targets/test_zabbix_trigger/meta/main.yml b/tests/integration/targets/test_zabbix_trigger/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_trigger/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_trigger/tasks/main.yml b/tests/integration/targets/test_zabbix_trigger/tasks/main.yml new file mode 100644 index 000000000..c410c36da --- /dev/null +++ b/tests/integration/targets/test_zabbix_trigger/tasks/main.yml @@ -0,0 +1,28 @@ +--- +- name: test - do not run tests for Zabbix < 6.4 + meta: end_play + when: zabbix_version is version('6.4', '<') + +- block: + # setup stuff + - include_tasks: zabbix_setup.yml + + # zabbix_trigger module tests + - include_tasks: zabbix_tests.yml + + # tear down stuff set up earlier + - include_tasks: zabbix_teardown.yml + always: + - name: "cleanup host item if tests failed" + community.zabbix.zabbix_item: + host_name: ExampleHost + name: ExampleHostItem + state: absent + ignore_errors: true + + - name: "cleanup template item if tests failed" + community.zabbix.zabbix_item: + template_name: ExampleTemplate + name: ExampleTemplateItem + state: absent + ignore_errors: true diff --git a/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_setup.yml b/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_setup.yml new file mode 100644 index 000000000..de3c7ecf4 --- /dev/null +++ b/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_setup.yml @@ -0,0 +1,47 @@ +--- + +- name: Create test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + template_groups: + - Templates + +- name: Create test 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 test host item + community.zabbix.zabbix_item: + name: ExampleHostItem + host_name: ExampleHost + params: + type: zabbix_agent_active + key: agent.ping + value_type: numeric_unsigned + interval: 1m + state: present + +- name: Create test template item + community.zabbix.zabbix_item: + name: ExampleTemplateItem + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: system.cpu.load[percpu,avg1] + value_type: numeric_float + interval: 1m + state: present diff --git a/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_teardown.yml b/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_teardown.yml new file mode 100644 index 000000000..305484842 --- /dev/null +++ b/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_teardown.yml @@ -0,0 +1,21 @@ +- name: remove test host item + community.zabbix.zabbix_item: + name: ExampleHostItem + host_name: ExampleHost + state: absent + +- name: remove test template item + community.zabbix.zabbix_item: + name: ExampleTemplateItem + template_name: ExampleTemplate + state: absent + +- name: remove test host + community.zabbix.zabbix_host: + host_name: ExampleHost + state: absent + +- name: remove test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + state: absent diff --git a/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_tests.yml new file mode 100644 index 000000000..c87bd28b6 --- /dev/null +++ b/tests/integration/targets/test_zabbix_trigger/tasks/zabbix_tests.yml @@ -0,0 +1,159 @@ +--- + +- name: test - create new Zabbix trigger on host with many options set + community.zabbix.zabbix_trigger: + name: TestTrigger + host_name: ExampleHost + description: test host trigger + params: + severity: warning + expression: 'nodata(/ExampleHost/agent.ping,2m)=1' + recovery_mode: recovery_expression + recovery_expression: 'nodata(/ExampleHost/agent.ping,2m)=0' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxhosttrigger_new + +- name: assert that trigger was created + ansible.builtin.assert: + that: zbxhosttrigger_new is changed + +- name: test - create same Zabbix trigger once again + community.zabbix.zabbix_trigger: + name: TestTrigger + host_name: ExampleHost + description: test host trigger + params: + severity: warning + expression: 'nodata(/ExampleHost/agent.ping,2m)=1' + recovery_mode: recovery_expression + recovery_expression: 'nodata(/ExampleHost/agent.ping,2m)=0' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxhosttrigger_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhosttrigger_existing is changed + +- name: test - update existing zabbix trigger + community.zabbix.zabbix_trigger: + name: TestTrigger + host_name: ExampleHost + params: + manual_close: False + state: present + register: zbxhosttrigger_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxhosttrigger_changed is changed + +- name: test - attempt to delete previously created zabbix trigger + community.zabbix.zabbix_trigger: + name: TestTrigger + host_name: ExampleHost + state: absent + register: zbxhosttrigger_existing_delete + +- name: assert that trigger was deleted + ansible.builtin.assert: + that: zbxhosttrigger_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix trigger + community.zabbix.zabbix_trigger: + name: TestTrigger + host_name: ExampleHost + state: absent + register: zbxhosttrigger_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhosttrigger_missing_delete is changed + +- name: test - create new Zabbix trigger on template with many options set + community.zabbix.zabbix_trigger: + name: TestTrigger + template_name: ExampleTemplate + description: test template trigger + params: + severity: warning + expression: 'count(/ExampleTemplate/system.cpu.load[percpu,avg1],#2,"gt","1.3")>1' + recovery_mode: recovery_expression + recovery_expression: 'count(/ExampleTemplate/system.cpu.load[percpu,avg1],#2,"lt","1.3")>1' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxtemptrigger_new + +- name: assert that trigger was created + ansible.builtin.assert: + that: zbxtemptrigger_new is changed + +- name: test - create same Zabbix trigger once again + community.zabbix.zabbix_trigger: + name: TestTrigger + template_name: ExampleTemplate + description: test template trigger + params: + severity: warning + expression: 'count(/ExampleTemplate/system.cpu.load[percpu,avg1],#2,"gt","1.3")>1' + recovery_mode: recovery_expression + recovery_expression: 'count(/ExampleTemplate/system.cpu.load[percpu,avg1],#2,"lt","1.3")>1' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxtemptrigger_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtemptrigger_existing is changed + +- name: test - update existing zabbix trigger + community.zabbix.zabbix_trigger: + name: TestTrigger + template_name: ExampleTemplate + params: + manual_close: False + state: present + register: zbxtemptrigger_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxtemptrigger_changed is changed + +- name: test - attempt to delete previously created zabbix trigger + community.zabbix.zabbix_trigger: + name: TestTrigger + template_name: ExampleTemplate + state: absent + register: zbxtemptrigger_existing_delete + +- name: assert that trigger was deleted + ansible.builtin.assert: + that: zbxtemptrigger_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix trigger + community.zabbix.zabbix_trigger: + name: TestTrigger + template_name: ExampleTemplate + state: absent + register: zbxtemptrigger_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtemptrigger_missing_delete is changed diff --git a/tests/integration/targets/test_zabbix_triggerprototype/meta/main.yml b/tests/integration/targets/test_zabbix_triggerprototype/meta/main.yml new file mode 100644 index 000000000..acdb704c8 --- /dev/null +++ b/tests/integration/targets/test_zabbix_triggerprototype/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - setup_zabbix diff --git a/tests/integration/targets/test_zabbix_triggerprototype/tasks/main.yml b/tests/integration/targets/test_zabbix_triggerprototype/tasks/main.yml new file mode 100644 index 000000000..05bcdb724 --- /dev/null +++ b/tests/integration/targets/test_zabbix_triggerprototype/tasks/main.yml @@ -0,0 +1,44 @@ +--- +- name: test - do not run tests for Zabbix < 6.4 + meta: end_play + when: zabbix_version is version('6.4', '<') + +- block: + # setup stuff + - include_tasks: zabbix_setup.yml + + # zabbix_triggerprototype module tests + - include_tasks: zabbix_tests.yml + + # tear down stuff set up earlier + - include_tasks: zabbix_teardown.yml + always: + - name: "cleanup host item if tests failed" + community.zabbix.zabbix_itemprototype: + host_name: ExampleHost + discoveryrule_name: ExampleHostRule + name: ExampleHostItem + state: absent + ignore_errors: true + + - name: "cleanup template item if tests failed" + community.zabbix.zabbix_itemprototype: + template_name: ExampleTemplate + discoveryrule_name: ExampleTemplateRule + name: ExampleTemplateItem + state: absent + ignore_errors: true + + - name: cleanup discovery rule on host if tests failed + community.zabbix.zabbix_discoveryrule: + name: ExampleHostRule + host_name: ExampleHost + state: absent + ignore_errors: true + + - name: cleanup discovery rule on template if tests failed + community.zabbix.zabbix_discoveryrule: + name: ExampleTemplateRule + template_name: ExampleTemplate + state: absent + ignore_errors: true diff --git a/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_setup.yml b/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_setup.yml new file mode 100644 index 000000000..b42134f3a --- /dev/null +++ b/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_setup.yml @@ -0,0 +1,48 @@ +--- + +- name: Create test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + template_groups: + - Templates + +- name: Create test 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 new Zabbix discoveryrule on host + community.zabbix.zabbix_discoveryrule: + name: ExampleHostRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + state: present + +- name: Create host item prototype + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:ExampleItemPrototype{% endraw %}' + discoveryrule_name: ExampleHostRule + host_name: ExampleHost + params: + type: zabbix_agent_active + key: '{% raw %}vfs.fs.size[{#FSNAME}, pused]{% endraw %}' + value_type: numeric_unsigned + interval: 1m + state: present diff --git a/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_teardown.yml b/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_teardown.yml new file mode 100644 index 000000000..ef841de56 --- /dev/null +++ b/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_teardown.yml @@ -0,0 +1,15 @@ +- name: remove test template item + community.zabbix.zabbix_item: + name: ExampleTemplateItem + template_name: ExampleTemplate + state: absent + +- name: remove test host + community.zabbix.zabbix_host: + host_name: ExampleHost + state: absent + +- name: remove test template + community.zabbix.zabbix_template: + template_name: ExampleTemplate + state: absent diff --git a/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_tests.yml b/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_tests.yml new file mode 100644 index 000000000..7975e20c1 --- /dev/null +++ b/tests/integration/targets/test_zabbix_triggerprototype/tasks/zabbix_tests.yml @@ -0,0 +1,180 @@ +--- + +- name: test - create new Zabbix trigger on host with many options set + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + host_name: ExampleHost + description: test host trigger + params: + severity: warning + expression: '{% raw %}last(/ExampleHost/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxhosttrigger_new + +- name: assert that trigger was created + ansible.builtin.assert: + that: zbxhosttrigger_new is changed + +- name: test - create same Zabbix trigger once again + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + host_name: ExampleHost + description: test host trigger + params: + severity: warning + expression: '{% raw %}last(/ExampleHost/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxhosttrigger_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhosttrigger_existing is changed + +- name: test - update existing zabbix trigger + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + host_name: ExampleHost + params: + manual_close: False + state: present + register: zbxhosttrigger_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxhosttrigger_changed is changed + +- name: test - attempt to delete previously created zabbix trigger + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + host_name: ExampleHost + state: absent + register: zbxhosttrigger_existing_delete + +- name: assert that trigger was deleted + ansible.builtin.assert: + that: zbxhosttrigger_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix trigger + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + host_name: ExampleHost + state: absent + register: zbxhosttrigger_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxhosttrigger_missing_delete is changed + +- name: remove host rule + community.zabbix.zabbix_discoveryrule: + name: ExampleHostRule + host_name: ExampleHost + state: absent + +- name: Create new Zabbix discoveryrule on template + community.zabbix.zabbix_discoveryrule: + name: ExampleTemplateRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: 'vfs.fs.discovery' + interval: 1m + enabled: True + state: present + +- name: Create template item prototype + community.zabbix.zabbix_itemprototype: + name: '{% raw %}{#FSNAME}:ExampleItemPrototype{% endraw %}' + discoveryrule_name: ExampleTemplateRule + template_name: ExampleTemplate + params: + type: zabbix_agent_active + key: '{% raw %}vfs.fs.size[{#FSNAME}, pused]{% endraw %}' + value_type: numeric_unsigned + interval: 1m + state: present + +- name: test - create new Zabbix trigger on template with many options set + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: ExampleTemplate + description: test template trigger + params: + severity: warning + expression: '{% raw %}last(/ExampleTemplate/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxtemptrigger_new + +- name: assert that trigger was created + ansible.builtin.assert: + that: zbxtemptrigger_new is changed + +- name: test - create same Zabbix trigger once again + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: ExampleTemplate + description: test template trigger + params: + severity: warning + expression: '{% raw %}last(/ExampleTemplate/vfs.fs.size[{#FSNAME}, pused])>80{% endraw %}' + manual_close: True + enabled: True + tags: + - tag: tag + value: value + state: present + register: zbxtemptrigger_existing + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtemptrigger_existing is changed + +- name: test - update existing zabbix trigger + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: ExampleTemplate + params: + manual_close: False + state: present + register: zbxtemptrigger_changed + +- name: expect to succeed and that things changed + ansible.builtin.assert: + that: zbxtemptrigger_changed is changed + +- name: test - attempt to delete previously created zabbix trigger + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: ExampleTemplate + state: absent + register: zbxtemptrigger_existing_delete + +- name: assert that trigger was deleted + ansible.builtin.assert: + that: zbxtemptrigger_existing_delete is changed + +- name: test - attempt to delete non-existing zabbix trigger + community.zabbix.zabbix_triggerprototype: + name: '{% raw %}Free disk space is less than 20% on volume {#FSNAME}{% endraw %}' + template_name: ExampleTemplate + state: absent + register: zbxtemptrigger_missing_delete + +- name: assert that nothing has been changed + ansible.builtin.assert: + that: not zbxtemptrigger_missing_delete is changed