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()
+