diff --git a/monitoring/zabbix_group.py b/monitoring/zabbix_group.py new file mode 100644 index 00000000000..447ad927b0b --- /dev/null +++ b/monitoring/zabbix_group.py @@ -0,0 +1,208 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +DOCUMENTATION = ''' +--- +module: zabbix_group +short_description: Zabbix host groups creates/deletes +description: + - Create host groups if they don't exist. + - Delete existing host groups if they exist. +version_added: "1.9" +author: Tony Minfei Ding, Harrison Gu +requirements: + - zabbix-api python module +options: + server_url: + description: + - Url of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + required: true + default: null + aliases: [ "url" ] + login_user: + description: + - Zabbix user name. + required: true + default: null + login_password: + description: + - Zabbix user password. + required: true + default: null + state: + description: + - Create or delete host group. + - Possible values are: present and absent. + required: false + default: "present" + timeout: + description: + - The timeout of API request(seconds). + default: 10 + host_groups: + description: + - List of host groups to create or delete. + required: true +notes: + - Too many concurrent updates to the same group may cause Zabbix to return errors, see examples for a workaround if needed. +''' + +EXAMPLES = ''' +# Base create host groups example +- name: Create host groups + local_action: + module: zabbix_group + server_url: http://monitor.example.com + login_user: username + login_password: password + state: present + host_groups: + - Example group1 + - Example group2 + +# Limit the Zabbix group creations to one host since Zabbix can return an error when doing concurent updates +- name: Create host groups + local_action: + module: zabbix_group + server_url: http://monitor.example.com + login_user: username + login_password: password + state: present + host_groups: + - Example group1 + - Example group2 + when: inventory_hostname==groups['group_name'][0] +''' + +try: + from zabbix_api import ZabbixAPI, ZabbixAPISubClass + from zabbix_api import Already_Exists + + HAS_ZABBIX_API = True +except ImportError: + HAS_ZABBIX_API = False + + +class HostGroup(object): + def __init__(self, module, zbx): + self._module = module + self._zapi = zbx + + # create host group(s) if not exists + def create_host_group(self, group_names): + try: + group_add_list = [] + for group_name in group_names: + result = self._zapi.hostgroup.exists({'name': group_name}) + if not result: + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.hostgroup.create({'name': group_name}) + group_add_list.append(group_name) + except Already_Exists: + return group_add_list + return group_add_list + except Exception, e: + self._module.fail_json(msg="Failed to create host group(s): %s" % e) + + # delete host group(s) + def delete_host_group(self, group_ids): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.hostgroup.delete(group_ids) + except Exception, e: + self._module.fail_json(msg="Failed to delete host group(s), Exception: %s" % e) + + # get group ids by name + def get_group_ids(self, host_groups): + group_ids = [] + + group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': host_groups}}) + for group in group_list: + group_id = group['groupid'] + group_ids.append(group_id) + return group_ids, group_list + + +def main(): + module = AnsibleModule( + argument_spec=dict( + server_url=dict(required=True, default=None, aliases=['url']), + login_user=dict(required=True), + login_password=dict(required=True), + host_groups=dict(required=True), + state=dict(default="present"), + timeout=dict(default=10) + ), + supports_check_mode=True + ) + + if not HAS_ZABBIX_API: + module.fail_json(msg="Missing requried zabbix-api module (check docs or install with: pip install zabbix-api)") + + server_url = module.params['server_url'] + login_user = module.params['login_user'] + login_password = module.params['login_password'] + host_groups = module.params['host_groups'] + state = module.params['state'] + timeout = module.params['timeout'] + + zbx = None + + # login to zabbix + try: + zbx = ZabbixAPI(server_url, timeout=timeout) + zbx.login(login_user, login_password) + except Exception, e: + module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) + + hostGroup = HostGroup(module, zbx) + + group_ids = [] + group_list = [] + if host_groups: + group_ids, group_list = hostGroup.get_group_ids(host_groups) + + if state == "absent": + # delete host groups + if group_ids: + delete_group_names = [] + hostGroup.delete_host_group(group_ids) + for group in group_list: + delete_group_names.append(group['name']) + module.exit_json(changed=True, + result="Successfully deleted host group(s): %s." % ",".join(delete_group_names)) + else: + module.exit_json(changed=False, result="No host group(s) to delete.") + else: + # create host groups + group_add_list = hostGroup.create_host_group(host_groups) + if len(group_add_list) > 0: + module.exit_json(changed=True, result="Successfully created host group(s): %s" % group_add_list) + else: + module.exit_json(changed=False) + +from ansible.module_utils.basic import * +main() + diff --git a/monitoring/zabbix_host.py b/monitoring/zabbix_host.py new file mode 100644 index 00000000000..7c58b2f0696 --- /dev/null +++ b/monitoring/zabbix_host.py @@ -0,0 +1,457 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +DOCUMENTATION = ''' +--- +module: zabbix_host +short_description: Zabbix host creates/updates/deletes +description: + - When the host does not exists, a new host will be created, added to any host groups and linked to any templates. + - When the host already exists, the host group membership will be updated, along with the template links and interfaces. + - Delete a host from Zabbix if the host exists. +version_added: "1.9" +author: Tony Minfei Ding, Harrison Gu +requirements: + - zabbix-api python module +options: + server_url: + description: + - Url of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + required: true + default: null + aliases: [ "url" ] + login_user: + description: + - Zabbix user name. + required: true + default: null + login_password: + description: + - Zabbix user password. + required: true + default: null + host_name: + description: + - Technical name of the host. + - If the host has already been added, the host name won't be updated. + required: true + host_groups: + description: + - List of host groups to add the host to. + required: false + link_templates: + description: + - List of templates to be linked to the host. + required: false + default: None + status: + description: + - Status and function of the host. + - Possible values are: enabled and disabled + required: false + default: "enabled" + state: + description: + - create/update or delete host. + - Possible values are: present and absent. If the host already exists, and the state is "present", just to update the host. + required: false + default: "present" + timeout: + description: + - The timeout of API request(seconds). + default: 10 + interfaces: + description: + - List of interfaces to be created for the host (see example). + - Available values are: dns, ip, main, port, type and useip. + - Please review the interface documentation for more information on the supported properties: + - https://www.zabbix.com/documentation/2.0/manual/appendix/api/hostinterface/definitions#host_interface + required: false +''' + +EXAMPLES = ''' +- name: Create a new host or update an existing host's info + local_action: + module: zabbix_host + server_url: http://monitor.example.com + login_user: username + login_password: password + host_name: ExampleHost + host_groups: + - Example group1 + - Example group2 + link_templates: + - Example template1 + - Example template2 + status: enabled + state: present + interfaces: + - type: 1 + main: 1 + useip: 1 + ip: 10.xx.xx.xx + dns: "" + port: 10050 + - type: 4 + main: 1 + useip: 1 + ip: 10.xx.xx.xx + dns: "" + port: 12345 +''' + +import logging +import copy + +try: + from zabbix_api import ZabbixAPI, ZabbixAPISubClass + + HAS_ZABBIX_API = True +except ImportError: + HAS_ZABBIX_API = False + + +# Extend the ZabbixAPI +# Since the zabbix-api python module too old (version 1.0, no higher version so far), +# it does not support the 'hostinterface' api calls, +# so we have to inherit the ZabbixAPI class to add 'hostinterface' support. +class ZabbixAPIExtends(ZabbixAPI): + hostinterface = None + + def __init__(self, server, timeout, **kwargs): + ZabbixAPI.__init__(self, server, timeout=timeout) + self.hostinterface = ZabbixAPISubClass(self, dict({"prefix": "hostinterface"}, **kwargs)) + + +class Host(object): + def __init__(self, module, zbx): + self._module = module + self._zapi = zbx + + # exist host + def is_host_exist(self, host_name): + result = self._zapi.host.exists({'host': host_name}) + return result + + # check if host group exists + def check_host_group_exist(self, group_names): + for group_name in group_names: + result = self._zapi.hostgroup.exists({'name': group_name}) + if not result: + self._module.fail_json(msg="Hostgroup not found: %s" % group_name) + return True + + def get_template_ids(self, template_list): + template_ids = [] + if template_list is None or len(template_list) == 0: + return template_ids + for template in template_list: + template_list = self._zapi.template.get({'output': 'extend', 'filter': {'host': template}}) + if len(template_list) < 1: + self._module.fail_json(msg="Template not found: %s" % template) + else: + template_id = template_list[0]['templateid'] + template_ids.append(template_id) + return template_ids + + def add_host(self, host_name, group_ids, status, interfaces): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + host_list = self._zapi.host.create({'host': host_name, 'interfaces': interfaces, 'groups': group_ids, 'status': status}) + if len(host_list) >= 1: + return host_list['hostids'][0] + except Exception, e: + self._module.fail_json(msg="Failed to create host %s: %s" % (host_name, e)) + + def update_host(self, host_name, group_ids, status, host_id, interfaces, exist_interface_list): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.update({'hostid': host_id, 'groups': group_ids, 'status': status}) + interface_list_copy = exist_interface_list + if interfaces: + for interface in interfaces: + flag = False + interface_str = interface + for exist_interface in exist_interface_list: + interface_type = interface['type'] + exist_interface_type = int(exist_interface['type']) + if interface_type == exist_interface_type: + # update + interface_str['interfaceid'] = exist_interface['interfaceid'] + self._zapi.hostinterface.update(interface_str) + flag = True + interface_list_copy.remove(exist_interface) + break + if not flag: + # add + interface_str['hostid'] = host_id + self._zapi.hostinterface.create(interface_str) + # remove + remove_interface_ids = [] + for remove_interface in interface_list_copy: + interface_id = remove_interface['interfaceid'] + remove_interface_ids.append(interface_id) + if len(remove_interface_ids) > 0: + self._zapi.hostinterface.delete(remove_interface_ids) + except Exception, e: + self._module.fail_json(msg="Failed to update host %s: %s" % (host_name, e)) + + def delete_host(self, host_id, host_name): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.delete({'hostid': host_id}) + except Exception, e: + self._module.fail_json(msg="Failed to delete host %s: %s" % (host_name, e)) + + # get host by host name + def get_host_by_host_name(self, host_name): + host_list = self._zapi.host.get({'output': 'extend', 'filter': {'host': [host_name]}}) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + return host_list[0] + + # get group ids by group names + def get_group_ids_by_group_names(self, group_names): + group_ids = [] + if self.check_host_group_exist(group_names): + group_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_names}}) + for group in group_list: + group_id = group['groupid'] + group_ids.append({'groupid': group_id}) + return group_ids + + # get host templates by host id + def get_host_templates_by_host_id(self, host_id): + template_ids = [] + template_list = self._zapi.template.get({'output': 'extend', 'hostids': host_id}) + for template in template_list: + template_ids.append(template['templateid']) + return template_ids + + # get host groups by host id + def get_host_groups_by_host_id(self, host_id): + exist_host_groups = [] + host_groups_list = self._zapi.hostgroup.get({'output': 'extend', 'hostids': host_id}) + + if len(host_groups_list) >= 1: + for host_groups_name in host_groups_list: + exist_host_groups.append(host_groups_name['name']) + return exist_host_groups + + # check the exist_interfaces whether it equals the interfaces or not + def check_interface_properties(self, exist_interface_list, interfaces): + interfaces_port_list = [] + if len(interfaces) >= 1: + for interface in interfaces: + interfaces_port_list.append(int(interface['port'])) + + exist_interface_ports = [] + if len(exist_interface_list) >= 1: + for exist_interface in exist_interface_list: + exist_interface_ports.append(int(exist_interface['port'])) + + if set(interfaces_port_list) != set(exist_interface_ports): + return True + + for exist_interface in exist_interface_list: + exit_interface_port = int(exist_interface['port']) + for interface in interfaces: + interface_port = int(interface['port']) + if interface_port == exit_interface_port: + for key in interface.keys(): + if str(exist_interface[key]) != str(interface[key]): + return True + + return False + + # get the status of host by host + def get_host_status_by_host(self, host): + return host['status'] + + # check all the properties before link or clear template + def check_all_properties(self, host_id, host_groups, status, interfaces, template_ids, + exist_interfaces, host): + # get the existing host's groups + exist_host_groups = self.get_host_groups_by_host_id(host_id) + if set(host_groups) != set(exist_host_groups): + return True + + # get the existing status + exist_status = self.get_host_status_by_host(host) + if int(status) != int(exist_status): + return True + + # check the exist_interfaces whether it equals the interfaces or not + if self.check_interface_properties(exist_interfaces, interfaces): + return True + + # get the existing templates + exist_template_ids = self.get_host_templates_by_host_id(host_id) + if set(list(template_ids)) != set(exist_template_ids): + return True + + return False + + # link or clear template of the host + def link_or_clear_template(self, host_id, template_id_list): + # get host's exist template ids + exist_template_id_list = self.get_host_templates_by_host_id(host_id) + + exist_template_ids = set(exist_template_id_list) + template_ids = set(template_id_list) + template_id_list = list(template_ids) + + # get unlink and clear templates + templates_clear = exist_template_ids.difference(template_ids) + templates_clear_list = list(templates_clear) + request_str = {'hostid': host_id, 'templates': template_id_list, 'templates_clear': templates_clear_list} + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.host.update(request_str) + except Exception, e: + self._module.fail_json(msg="Failed to link template to host: %s" % e) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + server_url=dict(required=True, default=None, aliases=['url']), + login_user=dict(required=True), + login_password=dict(required=True), + host_name=dict(required=True), + host_groups=dict(required=False), + link_templates=dict(required=False), + status=dict(default="enabled"), + state=dict(default="present"), + timeout=dict(default=10), + interfaces=dict(required=False) + ), + supports_check_mode=True + ) + + if not HAS_ZABBIX_API: + module.fail_json(msg="Missing requried zabbix-api module (check docs or install with: pip install zabbix-api)") + + server_url = module.params['server_url'] + login_user = module.params['login_user'] + login_password = module.params['login_password'] + host_name = module.params['host_name'] + host_groups = module.params['host_groups'] + link_templates = module.params['link_templates'] + status = module.params['status'] + state = module.params['state'] + timeout = module.params['timeout'] + interfaces = module.params['interfaces'] + + # convert enabled to 0; disabled to 1 + status = 1 if status == "disabled" else 0 + + zbx = None + # login to zabbix + try: + zbx = ZabbixAPIExtends(server_url, timeout=timeout) + zbx.login(login_user, login_password) + except Exception, e: + module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) + + host = Host(module, zbx) + + template_ids = [] + if link_templates: + template_ids = host.get_template_ids(link_templates) + + group_ids = [] + + if host_groups: + group_ids = host.get_group_ids_by_group_names(host_groups) + + ip = "" + if interfaces: + for interface in interfaces: + if interface['type'] == 1: + ip = interface['ip'] + + # check if host exist + is_host_exist = host.is_host_exist(host_name) + + if is_host_exist: + # get host id by host name + zabbix_host_obj = host.get_host_by_host_name(host_name) + host_id = zabbix_host_obj['hostid'] + + if state == "absent": + # remove host + host.delete_host(host_id, host_name) + module.exit_json(changed=True, result="Successfully delete host %s" % host_name) + else: + if not group_ids: + module.fail_json(msg="Specify at least one group for updating host '%s'." % host_name) + + # get exist host's interfaces + exist_interfaces = host._zapi.hostinterface.get({'output': 'extend', 'hostids': host_id}) + exist_interfaces_copy = copy.deepcopy(exist_interfaces) + + # update host + interfaces_len = len(interfaces) if interfaces else 0 + + if len(exist_interfaces) > interfaces_len: + if host.check_all_properties(host_id, host_groups, status, interfaces, template_ids, + exist_interfaces, zabbix_host_obj): + host.link_or_clear_template(host_id, template_ids) + host.update_host(host_name, group_ids, status, host_id, + interfaces, exist_interfaces) + module.exit_json(changed=True, + result="Successfully update host %s (%s) and linked with template '%s'" + % (host_name, ip, link_templates)) + else: + module.exit_json(changed=False) + else: + if host.check_all_properties(host_id, host_groups, status, interfaces, template_ids, + exist_interfaces_copy, zabbix_host_obj): + host.update_host(host_name, group_ids, status, host_id, interfaces, exist_interfaces) + host.link_or_clear_template(host_id, template_ids) + module.exit_json(changed=True, + result="Successfully update host %s (%s) and linked with template '%s'" + % (host_name, ip, link_templates)) + else: + module.exit_json(changed=False) + else: + if not group_ids: + module.fail_json(msg="Specify at least one group for creating host '%s'." % host_name) + + if not interfaces or (interfaces and len(interfaces) == 0): + module.fail_json(msg="Specify at least one interface for creating host '%s'." % host_name) + + # create host + host_id = host.add_host(host_name, group_ids, status, interfaces) + host.link_or_clear_template(host_id, template_ids) + module.exit_json(changed=True, result="Successfully added host %s (%s) and linked with template '%s'" % ( + host_name, ip, link_templates)) + +from ansible.module_utils.basic import * +main() + diff --git a/monitoring/zabbix_hostmacro.py b/monitoring/zabbix_hostmacro.py new file mode 100644 index 00000000000..4790dda2fd3 --- /dev/null +++ b/monitoring/zabbix_hostmacro.py @@ -0,0 +1,232 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +DOCUMENTATION = ''' +--- +module: zabbix_hostmacro +short_description: Zabbix host macro creates/updates/deletes +description: + - When the host macro does not exists, a new macro will be created, added to specific host. + - When the host macro already exists, the value will be updated. + - Delete a host macro from Zabbix if the macro exists. +version_added: "1.9" +author: Dean Hailin Song +requirements: + - zabbix-api python module +options: + server_url: + description: + - Url of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + required: true + default: null + aliases: [ "url" ] + login_user: + description: + - Zabbix user name. + required: true + default: null + login_password: + description: + - Zabbix user password. + required: true + default: null + host_name: + description: + - Technical name of the host. + - If the host has already been added, the host name won't be updated. + required: true + macro_name: + description: + - Technical name of the host macro. + required: true + macro_value: + description: + - Value of the host macro. + required: true + state: + description: + - create/update or delete macro. + - Possible values are: present and absent. If the macro already exists, and the state is "present", just to update the macro. + required: false + default: "present" + timeout: + description: + - The timeout of API request(seconds). + default: 10 +''' + +EXAMPLES = ''' +- name: Create a new host macro or update an existing macro's value + local_action: + module: zabbix_hostmacro + server_url: http://monitor.example.com + login_user: username + login_password: password + host_name: ExampleHost + macro_name:Example macro + macro_value:Example value + state: present +''' + +import logging +import copy + +try: + from zabbix_api import ZabbixAPI, ZabbixAPISubClass + + HAS_ZABBIX_API = True +except ImportError: + HAS_ZABBIX_API = False + + +# Extend the ZabbixAPI +# Since the zabbix-api python module too old (version 1.0, no higher version so far). +class ZabbixAPIExtends(ZabbixAPI): + def __init__(self, server, timeout, **kwargs): + ZabbixAPI.__init__(self, server, timeout=timeout) + + +class HostMacro(object): + def __init__(self, module, zbx): + self._module = module + self._zapi = zbx + + # exist host + def is_host_exist(self, host_name): + result = self._zapi.host.exists({'host': host_name}) + return result + + # get host id by host name + def get_host_id(self, host_name): + try: + host_list = self._zapi.host.get({'output': 'extend', 'filter': {'host': host_name}}) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + host_id = host_list[0]['hostid'] + return host_id + except Exception, e: + self._module.fail_json(msg="Failed to get the host %s id: %s." % (host_name, e)) + + # get host macro + def get_host_macro(self, macro_name, host_id): + try: + host_macro_list = self._zapi.usermacro.get( + {"output": "extend", "selectSteps": "extend", 'hostids': [host_id], 'filter': {'macro': '{$' + macro_name + '}'}}) + if len(host_macro_list) > 0: + return host_macro_list[0] + return None + except Exception, e: + self._module.fail_json(msg="Failed to get host macro %s: %s" % (macro_name, e)) + + # create host macro + def create_host_macro(self, macro_name, macro_value, host_id): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.create({'hostid': host_id, 'macro': '{$' + macro_name + '}', 'value': macro_value}) + self._module.exit_json(changed=True, result="Successfully added host macro %s " % macro_name) + except Exception, e: + self._module.fail_json(msg="Failed to create host macro %s: %s" % (macro_name, e)) + + # update host macro + def update_host_macro(self, host_macro_obj, macro_name, macro_value): + host_macro_id = host_macro_obj['hostmacroid'] + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.update({'hostmacroid': host_macro_id, 'value': macro_value}) + self._module.exit_json(changed=True, result="Successfully updated host macro %s " % macro_name) + except Exception, e: + self._module.fail_json(msg="Failed to updated host macro %s: %s" % (macro_name, e)) + + # delete host macro + def delete_host_macro(self, host_macro_obj, macro_name): + host_macro_id = host_macro_obj['hostmacroid'] + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.usermacro.delete([host_macro_id]) + self._module.exit_json(changed=True, result="Successfully deleted host macro %s " % macro_name) + except Exception, e: + self._module.fail_json(msg="Failed to delete host macro %s: %s" % (macro_name, e)) + +def main(): + module = AnsibleModule( + argument_spec=dict( + server_url=dict(required=True, default=None, aliases=['url']), + login_user=dict(required=True), + login_password=dict(required=True), + host_name=dict(required=True), + macro_name=dict(required=True), + macro_value=dict(required=True), + state=dict(default="present"), + timeout=dict(default=10) + ), + supports_check_mode=True + ) + + if not HAS_ZABBIX_API: + module.fail_json(msg="Missing requried zabbix-api module (check docs or install with: pip install zabbix-api)") + + server_url = module.params['server_url'] + login_user = module.params['login_user'] + login_password = module.params['login_password'] + host_name = module.params['host_name'] + macro_name = (module.params['macro_name']).upper() + macro_value = module.params['macro_value'] + state = module.params['state'] + timeout = module.params['timeout'] + + zbx = None + # login to zabbix + try: + zbx = ZabbixAPIExtends(server_url, timeout=timeout) + zbx.login(login_user, login_password) + except Exception, e: + module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) + + host_macro_class_obj = HostMacro(module, zbx) + + changed = False + + if host_name: + host_id = host_macro_class_obj.get_host_id(host_name) + host_macro_obj = host_macro_class_obj.get_host_macro(macro_name, host_id) + + if state == 'absent': + if not host_macro_obj: + module.exit_json(changed=False, msg="Host Macro %s does not exist" % macro_name) + else: + # delete a macro + host_macro_class_obj.delete_host_macro(host_macro_obj, macro_name) + else: + if not host_macro_obj: + # create host macro + host_macro_class_obj.create_host_macro(macro_name, macro_value, host_id) + else: + # update host macro + host_macro_class_obj.update_host_macro(host_macro_obj, macro_name, macro_value) + +from ansible.module_utils.basic import * +main() + diff --git a/monitoring/zabbix_screen.py b/monitoring/zabbix_screen.py new file mode 100644 index 00000000000..db65520f723 --- /dev/null +++ b/monitoring/zabbix_screen.py @@ -0,0 +1,422 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + + +DOCUMENTATION = ''' +--- +module: zabbix_screen +short_description: Zabbix screen creates/updates/deletes +description: + - When the screen does not exists, a new screen will be created with any screen items specified. + - When the screen already exists and the graphs have changed, the screen items will be updated. + - When the graph IDs have not changed, the screen items won't be updated unless the graph_width and graph_height have changed. + - Delete screen(s) from Zabbix if the screen(s) exists. +version_added: "1.9" +author: Tony Minfei Ding, Harrison Gu +requirements: + - zabbix-api python module +options: + server_url: + description: + - Url of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + required: true + default: null + aliases: [ "url" ] + login_user: + description: + - Zabbix user name. + required: true + default: null + login_password: + description: + - Zabbix user password. + required: true + default: null + timeout: + description: + - The timeout of API request(seconds). + default: 10 + zabbix_screens: + description: + - List of screens to be created/updated/deleted(see example). + - If the screen(s) already been added, the screen(s) name won't be updated. + - When creating or updating screen(s), the screen_name, host_group are required. + - When deleting screen(s), the screen_name is required. + - The available states are: present(default) and absent. If the screen(s) already exists, and the state is not "absent", the screen(s) will just be updated. + required: true + default: null +notes: + - Too many concurrent updates to the same screen may cause Zabbix to return errors, see examples for a workaround if needed. +''' + +EXAMPLES = ''' +# Create/update a screen. +- name: Create a new screen or update an existing screen's items + local_action: + module: zabbix_screen + server_url: http://monitor.example.com + login_user: username + login_password: password + screens: + - screen_name: ExampleScreen1 + host_group: Example group1 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + +# Create/update multi-screen +- name: Create two of new screens or update the existing screens' items + local_action: + module: zabbix_screen + server_url: http://monitor.example.com + login_user: username + login_password: password + screens: + - screen_name: ExampleScreen1 + host_group: Example group1 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + - screen_name: ExampleScreen2 + host_group: Example group2 + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + +# Limit the Zabbix screen creations to one host since Zabbix can return an error when doing concurent updates +- name: Create a new screen or update an existing screen's items + local_action: + module: zabbix_screen + server_url: http://monitor.example.com + login_user: username + login_password: password + state: present + screens: + - screen_name: ExampleScreen + host_group: Example group + state: present + graph_names: + - Example graph1 + - Example graph2 + graph_width: 200 + graph_height: 100 + when: inventory_hostname==groups['group_name'][0] +''' + +try: + from zabbix_api import ZabbixAPI, ZabbixAPISubClass + from zabbix_api import ZabbixAPIException + from zabbix_api import Already_Exists + HAS_ZABBIX_API = True +except ImportError: + HAS_ZABBIX_API = False + + +# Extend the ZabbixAPI +# Since the zabbix-api python module too old (version 1.0, and there's no higher version so far), it doesn't support the 'screenitem' api call, +# we have to inherit the ZabbixAPI class to add 'screenitem' support. +class ZabbixAPIExtends(ZabbixAPI): + screenitem = None + + def __init__(self, server, timeout, **kwargs): + ZabbixAPI.__init__(self, server, timeout=timeout) + self.screenitem = ZabbixAPISubClass(self, dict({"prefix": "screenitem"}, **kwargs)) + + +class Screen(object): + def __init__(self, module, zbx): + self._module = module + self._zapi = zbx + + # get group id by group name + def get_host_group_id(self, group_name): + if group_name == "": + self._module.fail_json(msg="group_name is required") + hostGroup_list = self._zapi.hostgroup.get({'output': 'extend', 'filter': {'name': group_name}}) + if len(hostGroup_list) < 1: + self._module.fail_json(msg="Host group not found: %s" % group_name) + else: + hostGroup_id = hostGroup_list[0]['groupid'] + return hostGroup_id + + # get monitored host_id by host_group_id + def get_host_ids_by_group_id(self, group_id): + host_list = self._zapi.host.get({'output': 'extend', 'groupids': group_id, 'monitored_hosts': 1}) + if len(host_list) < 1: + self._module.fail_json(msg="No host in the group.") + else: + host_ids = [] + for i in host_list: + host_id = i['hostid'] + host_ids.append(host_id) + return host_ids + + # get screen + def get_screen_id(self, screen_name): + if screen_name == "": + self._module.fail_json(msg="screen_name is required") + try: + screen_id_list = self._zapi.screen.get({'output': 'extend', 'search': {"name": screen_name}}) + if len(screen_id_list) >= 1: + screen_id = screen_id_list[0]['screenid'] + return screen_id + return None + except Exception as e: + self._module.fail_json(msg="Failed to get screen %s from Zabbix: %s" % (screen_name, e)) + + # create screen + def create_screen(self, screen_name, h_size, v_size): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + screen = self._zapi.screen.create({'name': screen_name, 'hsize': h_size, 'vsize': v_size}) + return screen['screenids'][0] + except Exception as e: + self._module.fail_json(msg="Failed to create screen %s: %s" % (screen_name, e)) + + # update screen + def update_screen(self, screen_id, screen_name, h_size, v_size): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.screen.update({'screenid': screen_id, 'hsize': h_size, 'vsize': v_size}) + except Exception as e: + self._module.fail_json(msg="Failed to update screen %s: %s" % (screen_name, e)) + + # delete screen + def delete_screen(self, screen_id, screen_name): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.screen.delete([screen_id]) + except Exception as e: + self._module.fail_json(msg="Failed to delete screen %s: %s" % (screen_name, e)) + + # get graph ids + def get_graph_ids(self, hosts, graph_name_list): + graph_id_lists = [] + vsize = 1 + for host in hosts: + graph_id_list = self.get_graphs_by_host_id(graph_name_list, host) + size = len(graph_id_list) + if size > 0: + graph_id_lists.extend(graph_id_list) + if vsize < size: + vsize = size + return graph_id_lists, vsize + + # getGraphs + def get_graphs_by_host_id(self, graph_name_list, host_id): + graph_ids = [] + for graph_name in graph_name_list: + graphs_list = self._zapi.graph.get({'output': 'extend', 'search': {'name': graph_name}, 'hostids': host_id}) + graph_id_list = [] + if len(graphs_list) > 0: + for graph in graphs_list: + graph_id = graph['graphid'] + graph_id_list.append(graph_id) + if len(graph_id_list) > 0: + graph_ids.extend(graph_id_list) + return graph_ids + + # get screen items + def get_screen_items(self, screen_id): + screen_item_list = self._zapi.screenitem.get({'output': 'extend', 'screenids': screen_id}) + return screen_item_list + + # delete screen items + def delete_screen_items(self, screen_id, screen_item_id_list): + try: + if len(screen_item_id_list) == 0: + return True + screen_item_list = self.get_screen_items(screen_id) + if len(screen_item_list) > 0: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.screenitem.delete(screen_item_id_list) + return True + return False + except ZabbixAPIException: + pass + + # get screen's hsize and vsize + def get_hsize_vsize(self, hosts, v_size): + h_size = len(hosts) + if h_size == 1: + if v_size == 1: + h_size = 1 + elif v_size in range(2, 9): + h_size = 2 + else: + h_size = 3 + v_size = (v_size - 1) / h_size + 1 + return h_size, v_size + + # create screen_items + def create_screen_items(self, screen_id, hosts, graph_name_list, width, height, h_size): + if len(hosts) < 4: + if width is None or width < 0: + width = 500 + else: + if width is None or width < 0: + width = 200 + if height is None or height < 0: + height = 100 + + try: + # when there're only one host, only one row is not good. + if len(hosts) == 1: + graph_id_list = self.get_graphs_by_host_id(graph_name_list, hosts[0]) + for i, graph_id in enumerate(graph_id_list): + if graph_id is not None: + self._zapi.screenitem.create({'screenid': screen_id, 'resourcetype': 0, 'resourceid': graph_id, + 'width': width, 'height': height, + 'x': i % h_size, 'y': i / h_size, 'colspan': 1, 'rowspan': 1, + 'elements': 0, 'valign': 0, 'halign': 0, + 'style': 0, 'dynamic': 0, 'sort_triggers': 0}) + else: + for i, host in enumerate(hosts): + graph_id_list = self.get_graphs_by_host_id(graph_name_list, host) + for j, graph_id in enumerate(graph_id_list): + if graph_id is not None: + self._zapi.screenitem.create({'screenid': screen_id, 'resourcetype': 0, 'resourceid': graph_id, + 'width': width, 'height': height, + 'x': i, 'y': j, 'colspan': 1, 'rowspan': 1, + 'elements': 0, 'valign': 0, 'halign': 0, + 'style': 0, 'dynamic': 0, 'sort_triggers': 0}) + except Already_Exists: + pass + + +def main(): + module = AnsibleModule( + argument_spec=dict( + server_url=dict(required=True, default=None, aliases=['url']), + login_user=dict(required=True), + login_password=dict(required=True), + timeout=dict(default=10), + screens=dict(required=True) + ), + supports_check_mode=True + ) + + if not HAS_ZABBIX_API: + module.fail_json(msg="Missing requried zabbix-api module (check docs or install with: pip install zabbix-api)") + + server_url = module.params['server_url'] + login_user = module.params['login_user'] + login_password = module.params['login_password'] + timeout = module.params['timeout'] + screens = module.params['screens'] + + zbx = None + # login to zabbix + try: + zbx = ZabbixAPIExtends(server_url, timeout=timeout) + zbx.login(login_user, login_password) + except Exception, e: + module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) + + screen = Screen(module, zbx) + created_screens = [] + changed_screens = [] + deleted_screens = [] + + for zabbix_screen in screens: + screen_name = zabbix_screen['screen_name'] + screen_id = screen.get_screen_id(screen_name) + state = "absent" if "state" in zabbix_screen and zabbix_screen['state'] == "absent" else "present" + + if state == "absent": + if screen_id: + screen_item_list = screen.get_screen_items(screen_id) + screen_item_id_list = [] + for screen_item in screen_item_list: + screen_item_id = screen_item['screenitemid'] + screen_item_id_list.append(screen_item_id) + screen.delete_screen_items(screen_id, screen_item_id_list) + screen.delete_screen(screen_id, screen_name) + + deleted_screens.append(screen_name) + else: + host_group = zabbix_screen['host_group'] + graph_names = zabbix_screen['graph_names'] + graph_width = None + if 'graph_width' in zabbix_screen: + graph_width = zabbix_screen['graph_width'] + graph_height = None + if 'graph_height' in zabbix_screen: + graph_height = zabbix_screen['graph_height'] + host_group_id = screen.get_host_group_id(host_group) + hosts = screen.get_host_ids_by_group_id(host_group_id) + + screen_item_id_list = [] + resource_id_list = [] + + graph_ids, v_size = screen.get_graph_ids(hosts, graph_names) + h_size, v_size = screen.get_hsize_vsize(hosts, v_size) + + if not screen_id: + # create screen + screen_id = screen.create_screen(screen_name, h_size, v_size) + screen.create_screen_items(screen_id, hosts, graph_names, graph_width, graph_height, h_size) + created_screens.append(screen_name) + else: + screen_item_list = screen.get_screen_items(screen_id) + + for screen_item in screen_item_list: + screen_item_id = screen_item['screenitemid'] + resource_id = screen_item['resourceid'] + screen_item_id_list.append(screen_item_id) + resource_id_list.append(resource_id) + + # when the screen items changed, then update + if graph_ids != resource_id_list: + deleted = screen.delete_screen_items(screen_id, screen_item_id_list) + if deleted: + screen.update_screen(screen_id, screen_name, h_size, v_size) + screen.create_screen_items(screen_id, hosts, graph_names, graph_width, graph_height, h_size) + changed_screens.append(screen_name) + + if created_screens and changed_screens: + module.exit_json(changed=True, result="Successfully created screen(s): %s, and updated screen(s): %s" % (",".join(created_screens), ",".join(changed_screens))) + elif created_screens: + module.exit_json(changed=True, result="Successfully created screen(s): %s" % ",".join(created_screens)) + elif changed_screens: + module.exit_json(changed=True, result="Successfully updated screen(s): %s" % ",".join(changed_screens)) + elif deleted_screens: + module.exit_json(changed=True, result="Successfully deleted screen(s): %s" % ",".join(deleted_screens)) + else: + module.exit_json(changed=False) + +from ansible.module_utils.basic import * +main() + diff --git a/monitoring/zabbix_webcheck.py b/monitoring/zabbix_webcheck.py new file mode 100644 index 00000000000..c63e49b4ca0 --- /dev/null +++ b/monitoring/zabbix_webcheck.py @@ -0,0 +1,391 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2013-2014, Epic Games, Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +DOCUMENTATION = ''' +--- +module: zabbix_webcheck +short_description: Zabbix web checks creates/updates/deletes +description: + - Creates a web check according to the host and application, the application will also be created if it does not exist. + - When the webcheck already exists and scenario steps are changed, the webcheck will be updated and the steps will be replaced. + - Delete webcheck from Zabbix if the webcheck exists. +version_added: "1.9" +author: Damon Chencheng Kong, Harrison Gu +requirements: + - zabbix-api python module +options: + server_url: + description: + - Url of Zabbix server, with protocol (http or https). + C(url) is an alias for C(server_url). + required: true + default: null + aliases: [ "url" ] + login_user: + description: + - Zabbix user name. + required: true + default: null + login_password: + description: + - Zabbix user password. + required: true + default: null + timeout: + description: + - The timeout of API request(seconds). + default: 10 + web_check: + description: + - List of web check to be created/updated/deleted (see example). + - If the webcheck has already been added, the web_check_name won't be updated. + - Available values: web_check_name(required), application_name(required), host_name(required), agent, authentication, delay, http_password, http_user, macros, nextcheck, status and web_check_steps(required) + - Available scenario step(steps) values are: name(required), number(required), url(required), posts, required, status_codes and timeout + - Please review the web check documentation for more information on the supported web check properties: https://www.zabbix.com/documentation/2.0/manual/appendix/api/webcheck/definitions + required: true + state: + description: + - Create/update/delete a web check. + - Possible values are: present, absent, default create web check. + required: false + default: "present" +''' + +EXAMPLES = ''' +- name: create or update(if exists) a web check + local_action: + module: zabbix_webcheck + server_url: http://monitor.example.com + login_user: username + login_password: password + state: present + web_check: + web_check_name: example Health Check + application_name: example app + host_name: example host name + agent: zabbix web check + steps: + - name: WebSite Check1 + url: http://www.example1.com + number: 1 + status_codes: 200 + - name: WebSite Check2 + url: http://www.example2.com + number: 2 + status_codes: 200 + +- name: delete a web check + local_action: + module: zabbix_webcheck + server_url: http://monitor.example.com + login_user: username + login_password: password + state: absent + web_check: + web_check_name: "example Health Check" +''' + +import json +import base64 +import urllib2 +import random +import time + +try: + from zabbix_api import ZabbixAPI, ZabbixAPISubClass + from zabbix_api import ZabbixAPIException + from zabbix_api import Already_Exists + + HAS_ZABBIX_API = True +except ImportError: + HAS_ZABBIX_API = False + + +class ZabbixAPIExtends(ZabbixAPI): + webcheck = None + + def __init__(self, server, timeout, **kwargs): + ZabbixAPI.__init__(self, server, timeout=timeout) + self.webcheck = ZabbixAPISubClass(self, dict({"prefix": "webcheck"}, **kwargs)) + + +class WebCheck(object): + def __init__(self, module, zbx): + self._module = module + self._zapi = zbx + + self._web_scenario_optional_properties_list = ['agent', 'authentication', 'delay', 'http_password', + 'http_user', 'macros', 'status'] + self._scenario_step_optional_properties_list = ['posts', 'required', 'status_codes', 'timeout'] + + # get host id by host name + def get_host_id(self, host_name): + try: + host_list = self._zapi.host.get({'output': 'extend', 'filter': {'host': host_name}}) + if len(host_list) < 1: + self._module.fail_json(msg="Host not found: %s" % host_name) + else: + host_id = host_list[0]['hostid'] + return host_id + except Exception, e: + self._module.fail_json(msg="Failed to get the host %s id: %s." % (host_name, e)) + + # get application id by application name, host id + def get_application_id(self, host_id, application_name): + application_id = None + try: + application_list = self._zapi.application.get( + {'output': 'extend', 'filter': {'hostid': host_id, "name": application_name}}) + if len(application_list) < 1: + applicationids = self.create_application(host_id, application_name) + if len(applicationids) > 0: + application_id = applicationids['applicationids'][0] + else: + application_id = application_list[0]['applicationid'] + return application_id + except Exception, e: + self._module.fail_json(msg="Failed to get the application '%s' id: %s." % (application_name, e)) + + #get webcheck + def get_web_check(self, web_check_name, host_id): + try: + web_check_list = self._zapi.webcheck.get( + {"output": "extend", "selectSteps": "extend", 'hostids': [host_id], 'filter': {'name': web_check_name}}) + if len(web_check_list) > 0: + return web_check_list[0] + return None + except Exception, e: + self._module.fail_json(msg="Failed to get WebCheck %s: %s" % (web_check_name, e)) + + # get steps + def get_steps(self, web_check_steps): + steps = [] + (name, url, no) = (None, None, None) + if web_check_steps: + for web_check_step in web_check_steps: + if "name" in web_check_step and web_check_step["name"]: + name = web_check_step["name"] + else: + self._module.fail_json(msg="The \"name\" property in scenario steps is required and not null.") + + if "url" in web_check_step and web_check_step["url"]: + url = web_check_step["url"] + else: + self._module.fail_json(msg="The \"url\" property in scenario steps is required and not null.") + + if "number" in web_check_step and web_check_step["number"]: + no = web_check_step["number"] + else: + self._module.fail_json(msg="The \"no\" property in scenario steps is required and not null.") + + optional_step_properties = dict() + for step_optional_property in self._scenario_step_optional_properties_list: + value = self.get_value_by_key(web_check_step, step_optional_property) + if value is not None: + optional_step_properties[step_optional_property] = value + + step = {"name": name, + "url": url, + "no": no} + steps.append(dict(step, **optional_step_properties)) + return steps + else: + self._module.fail_json(msg="The \"steps\" property in scenario is required and not null.") + + def get_replace_steps(self, old_webcheck_steps, new_webcheck_steps, httptestid): + relace_webcheck_steps = [] + + if new_webcheck_steps: + for new_webcheck_step in new_webcheck_steps: + flag = False + for old_webcheck_step in old_webcheck_steps: + new_webcheck_step_url = new_webcheck_step['url'] + old_webcheck_step_url = old_webcheck_step['url'] + if new_webcheck_step_url == old_webcheck_step_url: + # update + new_webcheck_step['webstepid'] = old_webcheck_step['webstepid'] + new_webcheck_step['httptestid'] = httptestid + relace_webcheck_steps.append(new_webcheck_step) + flag = True + break + if not flag: + # add + new_webcheck_step['httptestid'] = httptestid + relace_webcheck_steps.append(new_webcheck_step) + return relace_webcheck_steps + + # get webcheck params + def get_web_check_params(self, web_check_name, host_id, application_id, web_check_steps, optional_scenario_values, + web_check_obj=None, httptestid=None): + steps = self.get_steps(web_check_steps) + if httptestid: + if web_check_obj['steps']: + if type(web_check_obj['steps']) is list: + old_steps = web_check_obj['steps'] + elif type(web_check_obj['steps']) is dict: + old_steps = list(web_check_obj['steps'].values()) + else: + old_steps = None + steps = self.get_replace_steps(old_steps, steps, httptestid) + web_check_params = {"name": web_check_name, + "applicationid": application_id, + "hostid": host_id, + "steps": steps} + if httptestid: + web_check_params['httptestid'] = httptestid + return dict(web_check_params, **optional_scenario_values) + + #create application by application name, host id + def create_application(self, hostId, applicationName): + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + return self._zapi.application.create({'hostid': hostId, 'name': applicationName}) + except Exception, e: + self._module.fail_json(msg="Failed to create Application '%s': %s" % (applicationName, e)) + + # create web check + def create_web_check(self, web_check_name, host_id, application_id, web_check_steps, scenario_optional_properties): + web_check_params = self.get_web_check_params(web_check_name, host_id, application_id, web_check_steps, + scenario_optional_properties) + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.webcheck.create(web_check_params) + self._module.exit_json(changed=True, result="Successfully added WebCheck %s " % web_check_name) + except Exception, e: + self._module.fail_json(msg="Failed to create WebCheck %s: %s" % (web_check_name, e)) + + # update web check + def update_web_check(self, web_check_obj, web_check_name, host_id, application_id, web_check_steps, + scenario_optional_properties): + httptestid = web_check_obj['httptestid'] + web_check_params = self.get_web_check_params(web_check_name, host_id, application_id, web_check_steps, + scenario_optional_properties, web_check_obj, httptestid) + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.webcheck.update(web_check_params) + self._module.exit_json(changed=True, result="Successfully updated WebCheck %s " % web_check_params) + except Exception, e: + self._module.fail_json(msg="Failed to updated WebCheck %s: %s" % (web_check_params, e)) + + # delete web check + def delete_web_check(self, webCheckObj): + webCheckId = webCheckObj['httptestid'] + webCheckName = webCheckObj['name'] + try: + if self._module.check_mode: + self._module.exit_json(changed=True) + self._zapi.webcheck.delete([webCheckId]) + self._module.exit_json(changed=True, result="Successfully deleted WebCheck %s " % webCheckName) + except Exception, e: + self._module.fail_json(msg="Failed to delete WebCheck %s: %s" % (webCheckName, e)) + + def get_value_by_key(self, dict_obj, key): + if key in dict_obj: + value = dict_obj[key] + return value + return None + + +def main(): + module = AnsibleModule( + argument_spec=dict( + server_url=dict(required=True), + login_user=dict(required=True), + login_password=dict(required=True), + state=dict(default="present"), + timeout=dict(default=10), + web_check=dict(required=True), + ), + supports_check_mode=True, + ) + + if not HAS_ZABBIX_API: + module.fail_json(msg="Missing requried zabbix-api module (check docs or install with: pip install zabbix-api)") + + server_url = module.params['server_url'] + login_user = module.params['login_user'] + login_password = module.params['login_password'] + state = module.params['state'] + timeout = module.params['timeout'] + web_check = module.params['web_check'] + + web_check_name = '' + if 'web_check_name' in web_check: + web_check_name = web_check['web_check_name'] + else: + module.fail_json(msg="The \"web_check_name\" property is required and not null.") + + # login to zabbix + zbx = None + try: + zbx = ZabbixAPIExtends(server_url, timeout=timeout) + zbx.login(login_user, login_password) + except Exception, e: + module.fail_json(msg="Failed to connect to Zabbix server: %s" % e) + + # new a WebCheck class object + web_check_class_obj = WebCheck(module, zbx) + + host_name = web_check_class_obj.get_value_by_key(web_check, "host_name") + if not host_name: + module.fail_json(msg="The \"host_name\" property is required.") + host_id = web_check_class_obj.get_host_id(host_name) + + # get webcheck object by name + web_check_obj = web_check_class_obj.get_web_check(web_check_name, host_id) + + if state == 'absent': + if not web_check_obj: + module.exit_json(changed=False, msg="WebCheck %s does not exist" % web_check_name) + else: + # delete a webcheck + web_check_class_obj.delete_web_check(web_check_obj) + else: + application_name = web_check_class_obj.get_value_by_key(web_check, "application_name") + if not application_name: + module.fail_json(msg="The \"application_name\" property is required.") + + host_id = web_check_class_obj.get_host_id(host_name) + application_id = web_check_class_obj.get_application_id(host_id, application_name) + + web_check_steps = web_check_class_obj.get_value_by_key(web_check, "steps") + + scenario_optional_properties = dict() + for optional_property in web_check_class_obj._web_scenario_optional_properties_list: + value = web_check_class_obj.get_value_by_key(web_check, optional_property) + if value is not None: + scenario_optional_properties[optional_property] = value + + if not web_check_obj: + # create webcheck + web_check_class_obj.create_web_check(web_check_name, host_id, application_id, web_check_steps, + scenario_optional_properties) + else: + # update webcheck + web_check_class_obj.update_web_check(web_check_obj, web_check_name, host_id, application_id, + web_check_steps, scenario_optional_properties) + +from ansible.module_utils.basic import * +main() +