1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00
community.general/plugins/modules/monitoring/zabbix/zabbix_action.py

2114 lines
77 KiB
Python
Raw Normal View History

2020-03-09 10:11:07 +01:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = '''
---
module: zabbix_action
short_description: Create/Delete/Update Zabbix actions
description:
- This module allows you to create, modify and delete Zabbix actions.
author:
- Ruben Tsirunyan (@rubentsirunyan)
- Ruben Harutyunov (@K-DOT)
requirements:
- "zabbix-api >= 0.5.4"
options:
name:
description:
- Name of the action
required: true
event_source:
description:
- Type of events that the action will handle.
- Required when C(state=present).
required: false
choices: ['trigger', 'discovery', 'auto_registration', 'internal']
state:
description:
- State of the action.
- On C(present), it will create an action if it does not exist or update the action if the associated data is different.
- On C(absent), it will remove the action if it exists.
choices: ['present', 'absent']
default: 'present'
status:
description:
- Status of the action.
choices: ['enabled', 'disabled']
default: 'enabled'
pause_in_maintenance:
description:
- Whether to pause escalation during maintenance periods or not.
- Can be used when I(event_source=trigger).
type: 'bool'
default: true
esc_period:
description:
- Default operation step duration. Must be greater than 60 seconds.
- Accepts only seconds in int for <= Zabbix 3.2
- Accepts seconds, time unit with suffix and user macro since => Zabbix 3.4
- Required when C(state=present).
required: false
conditions:
type: list
description:
- List of dictionaries of conditions to evaluate.
- For more information about suboptions of this option please
check out Zabbix API documentation U(https://www.zabbix.com/documentation/4.0/manual/api/reference/action/object#action_filter_condition)
suboptions:
type:
description:
- Type (label) of the condition.
- 'Possible values when I(event_source=trigger):'
- ' - C(host_group)'
- ' - C(host)'
- ' - C(trigger)'
- ' - C(trigger_name)'
- ' - C(trigger_severity)'
- ' - C(time_period)'
- ' - C(host_template)'
- ' - C(application)'
- ' - C(maintenance_status)'
- ' - C(event_tag)'
- ' - C(event_tag_value)'
- 'Possible values when I(event_source=discovery):'
- ' - C(host_IP)'
- ' - C(discovered_service_type)'
- ' - C(discovered_service_port)'
- ' - C(discovery_status)'
- ' - C(uptime_or_downtime_duration)'
- ' - C(received_value)'
- ' - C(discovery_rule)'
- ' - C(discovery_check)'
- ' - C(proxy)'
- ' - C(discovery_object)'
- 'Possible values when I(event_source=auto_registration):'
- ' - C(proxy)'
- ' - C(host_name)'
- ' - C(host_metadata)'
- 'Possible values when I(event_source=internal):'
- ' - C(host_group)'
- ' - C(host)'
- ' - C(host_template)'
- ' - C(application)'
- ' - C(event_type)'
value:
description:
- Value to compare with.
- 'When I(type=discovery_status), the choices are:'
- ' - C(up)'
- ' - C(down)'
- ' - C(discovered)'
- ' - C(lost)'
- 'When I(type=discovery_object), the choices are:'
- ' - C(host)'
- ' - C(service)'
- 'When I(type=event_type), the choices are:'
- ' - C(item in not supported state)'
- ' - C(item in normal state)'
- ' - C(LLD rule in not supported state)'
- ' - C(LLD rule in normal state)'
- ' - C(trigger in unknown state)'
- ' - C(trigger in normal state)'
- 'When I(type=trigger_severity), the choices are (case-insensitive):'
- ' - C(not classified)'
- ' - C(information)'
- ' - C(warning)'
- ' - C(average)'
- ' - C(high)'
- ' - C(disaster)'
- Irrespective of user-visible names being changed in Zabbix. Defaults to C(not classified) if omitted.
- Besides the above options, this is usually either the name
of the object or a string to compare with.
operator:
description:
- Condition operator.
- When I(type) is set to C(time_period), the choices are C(in), C(not in).
- C(matches), C(does not match), C(Yes) and C(No) condition operators work only with >= Zabbix 4.0
choices:
- '='
- '<>'
- 'like'
- 'not like'
- 'in'
- '>='
- '<='
- 'not in'
- 'matches'
- 'does not match'
- 'Yes'
- 'No'
formulaid:
description:
- Arbitrary unique ID that is used to reference the condition from a custom expression.
- Can only contain upper-case letters.
- Required for custom expression filters.
eval_type:
description:
- Filter condition evaluation method.
- Defaults to C(andor) if conditions are less then 2 or if
I(formula) is not specified.
- Defaults to C(custom_expression) when formula is specified.
choices:
- 'andor'
- 'and'
- 'or'
- 'custom_expression'
formula:
description:
- User-defined expression to be used for evaluating conditions of filters with a custom expression.
- The expression must contain IDs that reference specific filter conditions by its formulaid.
- The IDs used in the expression must exactly match the ones
defined in the filter conditions. No condition can remain unused or omitted.
- Required for custom expression filters.
- Use sequential IDs that start at "A". If non-sequential IDs are used, Zabbix re-indexes them.
This makes each module run notice the difference in IDs and update the action.
default_message:
description:
- Problem message default text.
default_subject:
description:
- Problem message default subject.
recovery_default_message:
description:
- Recovery message text.
- Works only with >= Zabbix 3.2
recovery_default_subject:
description:
- Recovery message subject.
- Works only with >= Zabbix 3.2
acknowledge_default_message:
description:
- Update operation (known as "Acknowledge operation" before Zabbix 4.0) message text.
- Works only with >= Zabbix 3.4
acknowledge_default_subject:
description:
- Update operation (known as "Acknowledge operation" before Zabbix 4.0) message subject.
- Works only with >= Zabbix 3.4
operations:
type: list
description:
- List of action operations
suboptions:
type:
description:
- Type of operation.
choices:
- send_message
- remote_command
- add_host
- remove_host
- add_to_host_group
- remove_from_host_group
- link_to_template
- unlink_from_template
- enable_host
- disable_host
- set_host_inventory_mode
esc_period:
description:
- Duration of an escalation step in seconds.
- Must be greater than 60 seconds.
- Accepts only seconds in int for <= Zabbix 3.2
- Accepts seconds, time unit with suffix and user macro since => Zabbix 3.4
- If set to 0 or 0s, the default action escalation period will be used.
default: 0s
esc_step_from:
description:
- Step to start escalation from.
default: 1
esc_step_to:
description:
- Step to end escalation at.
default: 1
send_to_groups:
type: list
description:
- User groups to send messages to.
send_to_users:
type: list
description:
- Users (usernames or aliases) to send messages to.
message:
description:
- Operation message text.
- Will check the 'default message' and use the text from I(default_message) if this and I(default_subject) are not specified
subject:
description:
- Operation message subject.
- Will check the 'default message' and use the text from I(default_subject) if this and I(default_subject) are not specified
media_type:
description:
- Media type that will be used to send the message.
- Set to C(all) for all media types
default: 'all'
operation_condition:
type: 'str'
description:
- The action operation condition object defines a condition that must be met to perform the current operation.
choices:
- acknowledged
- not_acknowledged
host_groups:
type: list
description:
- List of host groups host should be added to.
- Required when I(type=add_to_host_group) or I(type=remove_from_host_group).
templates:
type: list
description:
- List of templates host should be linked to.
- Required when I(type=link_to_template) or I(type=unlink_from_template).
inventory:
description:
- Host inventory mode.
- Required when I(type=set_host_inventory_mode).
command_type:
description:
- Type of operation command.
- Required when I(type=remote_command).
choices:
- custom_script
- ipmi
- ssh
- telnet
- global_script
command:
description:
- Command to run.
- Required when I(type=remote_command) and I(command_type!=global_script).
execute_on:
description:
- Target on which the custom script operation command will be executed.
- Required when I(type=remote_command) and I(command_type=custom_script).
choices:
- agent
- server
- proxy
run_on_groups:
description:
- Host groups to run remote commands on.
- Required when I(type=remote_command) if I(run_on_hosts) is not set.
run_on_hosts:
description:
- Hosts to run remote commands on.
- Required when I(type=remote_command) if I(run_on_groups) is not set.
- If set to 0 the command will be run on the current host.
ssh_auth_type:
description:
- Authentication method used for SSH commands.
- Required when I(type=remote_command) and I(command_type=ssh).
choices:
- password
- public_key
ssh_privatekey_file:
description:
- Name of the private key file used for SSH commands with public key authentication.
- Required when I(type=remote_command) and I(command_type=ssh).
ssh_publickey_file:
description:
- Name of the public key file used for SSH commands with public key authentication.
- Required when I(type=remote_command) and I(command_type=ssh).
username:
description:
- User name used for authentication.
- Required when I(type=remote_command) and I(command_type in [ssh, telnet]).
password:
description:
- Password used for authentication.
- Required when I(type=remote_command) and I(command_type in [ssh, telnet]).
port:
description:
- Port number used for authentication.
- Required when I(type=remote_command) and I(command_type in [ssh, telnet]).
script_name:
description:
- The name of script used for global script commands.
- Required when I(type=remote_command) and I(command_type=global_script).
recovery_operations:
type: list
description:
- List of recovery operations.
- C(Suboptions) are the same as for I(operations).
- Works only with >= Zabbix 3.2
acknowledge_operations:
type: list
description:
- List of acknowledge operations.
- C(Suboptions) are the same as for I(operations).
- Works only with >= Zabbix 3.4
notes:
- Only Zabbix >= 3.0 is supported.
extends_documentation_fragment:
- community.general.zabbix
'''
EXAMPLES = '''
# Trigger action with only one condition
- name: Deploy trigger action
zabbix_action:
server_url: "http://zabbix.example.com/zabbix/"
login_user: Admin
login_password: secret
name: "Send alerts to Admin"
event_source: 'trigger'
state: present
status: enabled
esc_period: 60
conditions:
- type: 'trigger_severity'
operator: '>='
value: 'Information'
operations:
- type: send_message
subject: "Something bad is happening"
message: "Come on, guys do something"
media_type: 'Email'
send_to_users:
- 'Admin'
# Trigger action with multiple conditions and operations
- name: Deploy trigger action
zabbix_action:
server_url: "http://zabbix.example.com/zabbix/"
login_user: Admin
login_password: secret
name: "Send alerts to Admin"
event_source: 'trigger'
state: present
status: enabled
esc_period: 1m
conditions:
- type: 'trigger_name'
operator: 'like'
value: 'Zabbix agent is unreachable'
formulaid: A
- type: 'trigger_severity'
operator: '>='
value: 'disaster'
formulaid: B
formula: A or B
operations:
- type: send_message
media_type: 'Email'
send_to_users:
- 'Admin'
- type: remote_command
command: 'systemctl restart zabbix-agent'
command_type: custom_script
execute_on: server
run_on_hosts:
- 0
# Trigger action with recovery and acknowledge operations
- name: Deploy trigger action
zabbix_action:
server_url: "http://zabbix.example.com/zabbix/"
login_user: Admin
login_password: secret
name: "Send alerts to Admin"
event_source: 'trigger'
state: present
status: enabled
esc_period: 1h
conditions:
- type: 'trigger_severity'
operator: '>='
value: 'Information'
operations:
- type: send_message
subject: "Something bad is happening"
message: "Come on, guys do something"
media_type: 'Email'
send_to_users:
- 'Admin'
recovery_operations:
- type: send_message
subject: "Host is down"
message: "Come on, guys do something"
media_type: 'Email'
send_to_users:
- 'Admin'
acknowledge_operations:
- type: send_message
media_type: 'Email'
send_to_users:
- 'Admin'
'''
RETURN = '''
msg:
description: The result of the operation
returned: success
type: str
sample: 'Action Deleted: Register webservers, ID: 0001'
'''
import atexit
import traceback
try:
from zabbix_api import ZabbixAPI
HAS_ZABBIX_API = True
except ImportError:
ZBX_IMP_ERR = traceback.format_exc()
HAS_ZABBIX_API = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
class Zapi(object):
"""
A simple wrapper over the Zabbix API
"""
def __init__(self, module, zbx):
self._module = module
self._zapi = zbx
def check_if_action_exists(self, name):
"""Check if action exists.
Args:
name: Name of the action.
Returns:
The return value. True for success, False otherwise.
"""
try:
_action = self._zapi.action.get({
"selectOperations": "extend",
"selectRecoveryOperations": "extend",
"selectAcknowledgeOperations": "extend",
"selectFilter": "extend",
'selectInventory': 'extend',
'filter': {'name': [name]}
})
if len(_action) > 0:
_action[0]['recovery_operations'] = _action[0].pop('recoveryOperations', [])
_action[0]['acknowledge_operations'] = _action[0].pop('acknowledgeOperations', [])
return _action
except Exception as e:
self._module.fail_json(msg="Failed to check if action '%s' exists: %s" % (name, e))
def get_action_by_name(self, name):
"""Get action by name
Args:
name: Name of the action.
Returns:
dict: Zabbix action
"""
try:
action_list = self._zapi.action.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'name': [name]}
})
if len(action_list) < 1:
self._module.fail_json(msg="Action not found: " % name)
else:
return action_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get ID of '%s': %s" % (name, e))
def get_host_by_host_name(self, host_name):
"""Get host by host name
Args:
host_name: host name.
Returns:
host matching host name
"""
try:
host_list = self._zapi.host.get({
'output': 'extend',
'selectInventory': '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]
except Exception as e:
self._module.fail_json(msg="Failed to get host '%s': %s" % (host_name, e))
def get_hostgroup_by_hostgroup_name(self, hostgroup_name):
"""Get host group by host group name
Args:
hostgroup_name: host group name.
Returns:
host group matching host group name
"""
try:
hostgroup_list = self._zapi.hostgroup.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'name': [hostgroup_name]}
})
if len(hostgroup_list) < 1:
self._module.fail_json(msg="Host group not found: %s" % hostgroup_name)
else:
return hostgroup_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get host group '%s': %s" % (hostgroup_name, e))
def get_template_by_template_name(self, template_name):
"""Get template by template name
Args:
template_name: template name.
Returns:
template matching template name
"""
try:
template_list = self._zapi.template.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'host': [template_name]}
})
if len(template_list) < 1:
self._module.fail_json(msg="Template not found: %s" % template_name)
else:
return template_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get template '%s': %s" % (template_name, e))
def get_trigger_by_trigger_name(self, trigger_name):
"""Get trigger by trigger name
Args:
trigger_name: trigger name.
Returns:
trigger matching trigger name
"""
try:
trigger_list = self._zapi.trigger.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'description': [trigger_name]}
})
if len(trigger_list) < 1:
self._module.fail_json(msg="Trigger not found: %s" % trigger_name)
else:
return trigger_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get trigger '%s': %s" % (trigger_name, e))
def get_discovery_rule_by_discovery_rule_name(self, discovery_rule_name):
"""Get discovery rule by discovery rule name
Args:
discovery_rule_name: discovery rule name.
Returns:
discovery rule matching discovery rule name
"""
try:
discovery_rule_list = self._zapi.drule.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'name': [discovery_rule_name]}
})
if len(discovery_rule_list) < 1:
self._module.fail_json(msg="Discovery rule not found: %s" % discovery_rule_name)
else:
return discovery_rule_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get discovery rule '%s': %s" % (discovery_rule_name, e))
def get_discovery_check_by_discovery_check_name(self, discovery_check_name):
"""Get discovery check by discovery check name
Args:
discovery_check_name: discovery check name.
Returns:
discovery check matching discovery check name
"""
try:
discovery_check_list = self._zapi.dcheck.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'name': [discovery_check_name]}
})
if len(discovery_check_list) < 1:
self._module.fail_json(msg="Discovery check not found: %s" % discovery_check_name)
else:
return discovery_check_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get discovery check '%s': %s" % (discovery_check_name, e))
def get_proxy_by_proxy_name(self, proxy_name):
"""Get proxy by proxy name
Args:
proxy_name: proxy name.
Returns:
proxy matching proxy name
"""
try:
proxy_list = self._zapi.proxy.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'host': [proxy_name]}
})
if len(proxy_list) < 1:
self._module.fail_json(msg="Proxy not found: %s" % proxy_name)
else:
return proxy_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get proxy '%s': %s" % (proxy_name, e))
def get_mediatype_by_mediatype_name(self, mediatype_name):
"""Get mediatype by mediatype name
Args:
mediatype_name: mediatype name
Returns:
mediatype matching mediatype name
"""
try:
if str(mediatype_name).lower() == 'all':
return '0'
mediatype_list = self._zapi.mediatype.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'description': [mediatype_name]}
})
if len(mediatype_list) < 1:
self._module.fail_json(msg="Media type not found: %s" % mediatype_name)
else:
return mediatype_list[0]['mediatypeid']
except Exception as e:
self._module.fail_json(msg="Failed to get mediatype '%s': %s" % (mediatype_name, e))
def get_user_by_user_name(self, user_name):
"""Get user by user name
Args:
user_name: user name
Returns:
user matching user name
"""
try:
user_list = self._zapi.user.get({
'output': 'extend',
'selectInventory':
'extend', 'filter': {'alias': [user_name]}
})
if len(user_list) < 1:
self._module.fail_json(msg="User not found: %s" % user_name)
else:
return user_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get user '%s': %s" % (user_name, e))
def get_usergroup_by_usergroup_name(self, usergroup_name):
"""Get usergroup by usergroup name
Args:
usergroup_name: usergroup name
Returns:
usergroup matching usergroup name
"""
try:
usergroup_list = self._zapi.usergroup.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'name': [usergroup_name]}
})
if len(usergroup_list) < 1:
self._module.fail_json(msg="User group not found: %s" % usergroup_name)
else:
return usergroup_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get user group '%s': %s" % (usergroup_name, e))
# get script by script name
def get_script_by_script_name(self, script_name):
"""Get script by script name
Args:
script_name: script name
Returns:
script matching script name
"""
try:
if script_name is None:
return {}
script_list = self._zapi.script.get({
'output': 'extend',
'selectInventory': 'extend',
'filter': {'name': [script_name]}
})
if len(script_list) < 1:
self._module.fail_json(msg="Script not found: %s" % script_name)
else:
return script_list[0]
except Exception as e:
self._module.fail_json(msg="Failed to get script '%s': %s" % (script_name, e))
class Action(object):
"""
Restructures the user defined action data to fit the Zabbix API requirements
"""
def __init__(self, module, zbx, zapi_wrapper):
self._module = module
self._zapi = zbx
self._zapi_wrapper = zapi_wrapper
def _construct_parameters(self, **kwargs):
"""Construct parameters.
Args:
**kwargs: Arbitrary keyword parameters.
Returns:
dict: dictionary of specified parameters
"""
_params = {
'name': kwargs['name'],
'eventsource': to_numeric_value([
'trigger',
'discovery',
'auto_registration',
'internal'], kwargs['event_source']),
'esc_period': kwargs.get('esc_period'),
'filter': kwargs['conditions'],
'def_longdata': kwargs['default_message'],
'def_shortdata': kwargs['default_subject'],
'r_longdata': kwargs['recovery_default_message'],
'r_shortdata': kwargs['recovery_default_subject'],
'ack_longdata': kwargs['acknowledge_default_message'],
'ack_shortdata': kwargs['acknowledge_default_subject'],
'operations': kwargs['operations'],
'recovery_operations': kwargs.get('recovery_operations'),
'acknowledge_operations': kwargs.get('acknowledge_operations'),
'status': to_numeric_value([
'enabled',
'disabled'], kwargs['status'])
}
if kwargs['event_source'] == 'trigger':
if float(self._zapi.api_version().rsplit('.', 1)[0]) >= 4.0:
_params['pause_suppressed'] = '1' if kwargs['pause_in_maintenance'] else '0'
else:
_params['maintenance_mode'] = '1' if kwargs['pause_in_maintenance'] else '0'
return _params
def check_difference(self, **kwargs):
"""Check difference between action and user specified parameters.
Args:
**kwargs: Arbitrary keyword parameters.
Returns:
dict: dictionary of differences
"""
existing_action = convert_unicode_to_str(self._zapi_wrapper.check_if_action_exists(kwargs['name'])[0])
parameters = convert_unicode_to_str(self._construct_parameters(**kwargs))
change_parameters = {}
_diff = cleanup_data(compare_dictionaries(parameters, existing_action, change_parameters))
return _diff
def update_action(self, **kwargs):
"""Update action.
Args:
**kwargs: Arbitrary keyword parameters.
Returns:
action: updated action
"""
try:
if self._module.check_mode:
self._module.exit_json(msg="Action would be updated if check mode was not specified: %s" % kwargs, changed=True)
kwargs['actionid'] = kwargs.pop('action_id')
return self._zapi.action.update(kwargs)
except Exception as e:
self._module.fail_json(msg="Failed to update action '%s': %s" % (kwargs['actionid'], e))
def add_action(self, **kwargs):
"""Add action.
Args:
**kwargs: Arbitrary keyword parameters.
Returns:
action: added action
"""
try:
if self._module.check_mode:
self._module.exit_json(msg="Action would be added if check mode was not specified", changed=True)
parameters = self._construct_parameters(**kwargs)
action_list = self._zapi.action.create(parameters)
return action_list['actionids'][0]
except Exception as e:
self._module.fail_json(msg="Failed to create action '%s': %s" % (kwargs['name'], e))
def delete_action(self, action_id):
"""Delete action.
Args:
action_id: Action id
Returns:
action: deleted action
"""
try:
if self._module.check_mode:
self._module.exit_json(msg="Action would be deleted if check mode was not specified", changed=True)
return self._zapi.action.delete([action_id])
except Exception as e:
self._module.fail_json(msg="Failed to delete action '%s': %s" % (action_id, e))
class Operations(object):
"""
Restructures the user defined operation data to fit the Zabbix API requirements
"""
def __init__(self, module, zbx, zapi_wrapper):
self._module = module
# self._zapi = zbx
self._zapi_wrapper = zapi_wrapper
def _construct_operationtype(self, operation):
"""Construct operation type.
Args:
operation: operation to construct
Returns:
str: constructed operation
"""
try:
return to_numeric_value([
"send_message",
"remote_command",
"add_host",
"remove_host",
"add_to_host_group",
"remove_from_host_group",
"link_to_template",
"unlink_from_template",
"enable_host",
"disable_host",
"set_host_inventory_mode"], operation['type']
)
except Exception as e:
self._module.fail_json(msg="Unsupported value '%s' for operation type." % operation['type'])
def _construct_opmessage(self, operation):
"""Construct operation message.
Args:
operation: operation to construct the message
Returns:
dict: constructed operation message
"""
try:
return {
'default_msg': '0' if operation.get('message') is not None or operation.get('subject')is not None else '1',
'mediatypeid': self._zapi_wrapper.get_mediatype_by_mediatype_name(
operation.get('media_type')
) if operation.get('media_type') is not None else '0',
'message': operation.get('message'),
'subject': operation.get('subject'),
}
except Exception as e:
self._module.fail_json(msg="Failed to construct operation message. The error was: %s" % e)
def _construct_opmessage_usr(self, operation):
"""Construct operation message user.
Args:
operation: operation to construct the message user
Returns:
list: constructed operation message user or None if operation not found
"""
if operation.get('send_to_users') is None:
return None
return [{
'userid': self._zapi_wrapper.get_user_by_user_name(_user)['userid']
} for _user in operation.get('send_to_users')]
def _construct_opmessage_grp(self, operation):
"""Construct operation message group.
Args:
operation: operation to construct the message group
Returns:
list: constructed operation message group or None if operation not found
"""
if operation.get('send_to_groups') is None:
return None
return [{
'usrgrpid': self._zapi_wrapper.get_usergroup_by_usergroup_name(_group)['usrgrpid']
} for _group in operation.get('send_to_groups')]
def _construct_opcommand(self, operation):
"""Construct operation command.
Args:
operation: operation to construct command
Returns:
list: constructed operation command
"""
try:
return {
'type': to_numeric_value([
'custom_script',
'ipmi',
'ssh',
'telnet',
'global_script'], operation.get('command_type', 'custom_script')),
'command': operation.get('command'),
'execute_on': to_numeric_value([
'agent',
'server',
'proxy'], operation.get('execute_on', 'server')),
'scriptid': self._zapi_wrapper.get_script_by_script_name(
operation.get('script_name')
).get('scriptid'),
'authtype': to_numeric_value([
'password',
'private_key'
], operation.get('ssh_auth_type', 'password')),
'privatekey': operation.get('ssh_privatekey_file'),
'publickey': operation.get('ssh_publickey_file'),
'username': operation.get('username'),
'password': operation.get('password'),
'port': operation.get('port')
}
except Exception as e:
self._module.fail_json(msg="Failed to construct operation command. The error was: %s" % e)
def _construct_opcommand_hst(self, operation):
"""Construct operation command host.
Args:
operation: operation to construct command host
Returns:
list: constructed operation command host
"""
if operation.get('run_on_hosts') is None:
return None
return [{
'hostid': self._zapi_wrapper.get_host_by_host_name(_host)['hostid']
} if str(_host) != '0' else {'hostid': '0'} for _host in operation.get('run_on_hosts')]
def _construct_opcommand_grp(self, operation):
"""Construct operation command group.
Args:
operation: operation to construct command group
Returns:
list: constructed operation command group
"""
if operation.get('run_on_groups') is None:
return None
return [{
'groupid': self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)['hostid']
} for _group in operation.get('run_on_groups')]
def _construct_opgroup(self, operation):
"""Construct operation group.
Args:
operation: operation to construct group
Returns:
list: constructed operation group
"""
return [{
'groupid': self._zapi_wrapper.get_hostgroup_by_hostgroup_name(_group)['groupid']
} for _group in operation.get('host_groups', [])]
def _construct_optemplate(self, operation):
"""Construct operation template.
Args:
operation: operation to construct template
Returns:
list: constructed operation template
"""
return [{
'templateid': self._zapi_wrapper.get_template_by_template_name(_template)['templateid']
} for _template in operation.get('templates', [])]
def _construct_opinventory(self, operation):
"""Construct operation inventory.
Args:
operation: operation to construct inventory
Returns:
dict: constructed operation inventory
"""
return {'inventory_mode': operation.get('inventory')}
def _construct_opconditions(self, operation):
"""Construct operation conditions.
Args:
operation: operation to construct the conditions
Returns:
list: constructed operation conditions
"""
_opcond = operation.get('operation_condition')
if _opcond is not None:
if _opcond == 'acknowledged':
_value = '1'
elif _opcond == 'not_acknowledged':
_value = '0'
return [{
'conditiontype': '14',
'operator': '0',
'value': _value
}]
return []
def construct_the_data(self, operations):
"""Construct the operation data using helper methods.
Args:
operation: operation to construct
Returns:
list: constructed operation data
"""
constructed_data = []
for op in operations:
operation_type = self._construct_operationtype(op)
constructed_operation = {
'operationtype': operation_type,
'esc_period': op.get('esc_period'),
'esc_step_from': op.get('esc_step_from'),
'esc_step_to': op.get('esc_step_to')
}
# Send Message type
if constructed_operation['operationtype'] == '0':
constructed_operation['opmessage'] = self._construct_opmessage(op)
constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op)
constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op)
constructed_operation['opconditions'] = self._construct_opconditions(op)
# Send Command type
if constructed_operation['operationtype'] == '1':
constructed_operation['opcommand'] = self._construct_opcommand(op)
constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op)
constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op)
constructed_operation['opconditions'] = self._construct_opconditions(op)
# Add to/Remove from host group
if constructed_operation['operationtype'] in ('4', '5'):
constructed_operation['opgroup'] = self._construct_opgroup(op)
# Link/Unlink template
if constructed_operation['operationtype'] in ('6', '7'):
constructed_operation['optemplate'] = self._construct_optemplate(op)
# Set inventory mode
if constructed_operation['operationtype'] == '10':
constructed_operation['opinventory'] = self._construct_opinventory(op)
constructed_data.append(constructed_operation)
return cleanup_data(constructed_data)
class RecoveryOperations(Operations):
"""
Restructures the user defined recovery operations data to fit the Zabbix API requirements
"""
def _construct_operationtype(self, operation):
"""Construct operation type.
Args:
operation: operation to construct type
Returns:
str: constructed operation type
"""
try:
return to_numeric_value([
"send_message",
"remote_command",
None,
None,
None,
None,
None,
None,
None,
None,
None,
"notify_all_involved"], operation['type']
)
except Exception as e:
self._module.fail_json(msg="Unsupported value '%s' for recovery operation type." % operation['type'])
def construct_the_data(self, operations):
"""Construct the recovery operations data using helper methods.
Args:
operation: operation to construct
Returns:
list: constructed recovery operations data
"""
constructed_data = []
for op in operations:
operation_type = self._construct_operationtype(op)
constructed_operation = {
'operationtype': operation_type,
}
# Send Message type
if constructed_operation['operationtype'] in ('0', '11'):
constructed_operation['opmessage'] = self._construct_opmessage(op)
constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op)
constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op)
# Send Command type
if constructed_operation['operationtype'] == '1':
constructed_operation['opcommand'] = self._construct_opcommand(op)
constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op)
constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op)
constructed_data.append(constructed_operation)
return cleanup_data(constructed_data)
class AcknowledgeOperations(Operations):
"""
Restructures the user defined acknowledge operations data to fit the Zabbix API requirements
"""
def _construct_operationtype(self, operation):
"""Construct operation type.
Args:
operation: operation to construct type
Returns:
str: constructed operation type
"""
try:
return to_numeric_value([
"send_message",
"remote_command",
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
"notify_all_involved"], operation['type']
)
except Exception as e:
self._module.fail_json(msg="Unsupported value '%s' for acknowledge operation type." % operation['type'])
def construct_the_data(self, operations):
"""Construct the acknowledge operations data using helper methods.
Args:
operation: operation to construct
Returns:
list: constructed acknowledge operations data
"""
constructed_data = []
for op in operations:
operation_type = self._construct_operationtype(op)
constructed_operation = {
'operationtype': operation_type,
}
# Send Message type
if constructed_operation['operationtype'] in ('0', '11'):
constructed_operation['opmessage'] = self._construct_opmessage(op)
constructed_operation['opmessage_usr'] = self._construct_opmessage_usr(op)
constructed_operation['opmessage_grp'] = self._construct_opmessage_grp(op)
# Send Command type
if constructed_operation['operationtype'] == '1':
constructed_operation['opcommand'] = self._construct_opcommand(op)
constructed_operation['opcommand_hst'] = self._construct_opcommand_hst(op)
constructed_operation['opcommand_grp'] = self._construct_opcommand_grp(op)
constructed_data.append(constructed_operation)
return cleanup_data(constructed_data)
class Filter(object):
"""
Restructures the user defined filter conditions to fit the Zabbix API requirements
"""
def __init__(self, module, zbx, zapi_wrapper):
self._module = module
self._zapi = zbx
self._zapi_wrapper = zapi_wrapper
def _construct_evaltype(self, _eval_type, _formula, _conditions):
"""Construct the eval type
Args:
_formula: zabbix condition evaluation formula
_conditions: list of conditions to check
Returns:
dict: constructed acknowledge operations data
"""
if len(_conditions) <= 1:
return {
'evaltype': '0',
'formula': None
}
if _eval_type == 'andor':
return {
'evaltype': '0',
'formula': None
}
if _eval_type == 'and':
return {
'evaltype': '1',
'formula': None
}
if _eval_type == 'or':
return {
'evaltype': '2',
'formula': None
}
if _eval_type == 'custom_expression':
if _formula is not None:
return {
'evaltype': '3',
'formula': _formula
}
else:
self._module.fail_json(msg="'formula' is required when 'eval_type' is set to 'custom_expression'")
if _formula is not None:
return {
'evaltype': '3',
'formula': _formula
}
return {
'evaltype': '0',
'formula': None
}
def _construct_conditiontype(self, _condition):
"""Construct the condition type
Args:
_condition: condition to check
Returns:
str: constructed condition type data
"""
try:
return to_numeric_value([
"host_group",
"host",
"trigger",
"trigger_name",
"trigger_severity",
"trigger_value",
"time_period",
"host_ip",
"discovered_service_type",
"discovered_service_port",
"discovery_status",
"uptime_or_downtime_duration",
"received_value",
"host_template",
None,
"application",
"maintenance_status",
None,
"discovery_rule",
"discovery_check",
"proxy",
"discovery_object",
"host_name",
"event_type",
"host_metadata",
"event_tag",
"event_tag_value"], _condition['type']
)
except Exception as e:
self._module.fail_json(msg="Unsupported value '%s' for condition type." % _condition['type'])
def _construct_operator(self, _condition):
"""Construct operator
Args:
_condition: condition to construct
Returns:
str: constructed operator
"""
try:
return to_numeric_value([
"=",
"<>",
"like",
"not like",
"in",
">=",
"<=",
"not in",
"matches",
"does not match",
"Yes",
"No"], _condition['operator']
)
except Exception as e:
self._module.fail_json(msg="Unsupported value '%s' for operator." % _condition['operator'])
def _construct_value(self, conditiontype, value):
"""Construct operator
Args:
conditiontype: type of condition to construct
value: value to construct
Returns:
str: constructed value
"""
try:
# Host group
if conditiontype == '0':
return self._zapi_wrapper.get_hostgroup_by_hostgroup_name(value)['groupid']
# Host
if conditiontype == '1':
return self._zapi_wrapper.get_host_by_host_name(value)['hostid']
# Trigger
if conditiontype == '2':
return self._zapi_wrapper.get_trigger_by_trigger_name(value)['triggerid']
# Trigger name: return as is
# Trigger severity
if conditiontype == '4':
return to_numeric_value([
"not classified",
"information",
"warning",
"average",
"high",
"disaster"], value or "not classified"
)
# Trigger value
if conditiontype == '5':
return to_numeric_value([
"ok",
"problem"], value or "ok"
)
# Time period: return as is
# Host IP: return as is
# Discovered service type
if conditiontype == '8':
return to_numeric_value([
"SSH",
"LDAP",
"SMTP",
"FTP",
"HTTP",
"POP",
"NNTP",
"IMAP",
"TCP",
"Zabbix agent",
"SNMPv1 agent",
"SNMPv2 agent",
"ICMP ping",
"SNMPv3 agent",
"HTTPS",
"Telnet"], value
)
# Discovered service port: return as is
# Discovery status
if conditiontype == '10':
return to_numeric_value([
"up",
"down",
"discovered",
"lost"], value
)
if conditiontype == '13':
return self._zapi_wrapper.get_template_by_template_name(value)['templateid']
if conditiontype == '18':
return self._zapi_wrapper.get_discovery_rule_by_discovery_rule_name(value)['druleid']
if conditiontype == '19':
return self._zapi_wrapper.get_discovery_check_by_discovery_check_name(value)['dcheckid']
if conditiontype == '20':
return self._zapi_wrapper.get_proxy_by_proxy_name(value)['proxyid']
if conditiontype == '21':
return to_numeric_value([
"pchldrfor0",
"host",
"service"], value
)
if conditiontype == '23':
return to_numeric_value([
"item in not supported state",
"item in normal state",
"LLD rule in not supported state",
"LLD rule in normal state",
"trigger in unknown state",
"trigger in normal state"], value
)
return value
except Exception as e:
self._module.fail_json(
msg="""Unsupported value '%s' for specified condition type.
Check out Zabbix API documentation for supported values for
condition type '%s' at
https://www.zabbix.com/documentation/3.4/manual/api/reference/action/object#action_filter_condition""" % (value, conditiontype)
)
def construct_the_data(self, _eval_type, _formula, _conditions):
"""Construct the user defined filter conditions to fit the Zabbix API
requirements operations data using helper methods.
Args:
_formula: zabbix condition evaluation formula
_conditions: conditions to construct
Returns:
dict: user defined filter conditions
"""
if _conditions is None:
return None
constructed_data = {}
constructed_data['conditions'] = []
for cond in _conditions:
condition_type = self._construct_conditiontype(cond)
constructed_data['conditions'].append({
"conditiontype": condition_type,
"value": self._construct_value(condition_type, cond.get("value")),
"value2": cond.get("value2"),
"formulaid": cond.get("formulaid"),
"operator": self._construct_operator(cond)
})
_constructed_evaltype = self._construct_evaltype(
_eval_type,
_formula,
constructed_data['conditions']
)
constructed_data['evaltype'] = _constructed_evaltype['evaltype']
constructed_data['formula'] = _constructed_evaltype['formula']
return cleanup_data(constructed_data)
def convert_unicode_to_str(data):
"""Converts unicode objects to strings in dictionary
args:
data: unicode object
Returns:
dict: strings in dictionary
"""
if isinstance(data, dict):
return dict(map(convert_unicode_to_str, data.items()))
elif isinstance(data, (list, tuple, set)):
return type(data)(map(convert_unicode_to_str, data))
elif data is None:
return data
else:
return str(data)
def to_numeric_value(strs, value):
"""Converts string values to integers
Args:
value: string value
Returns:
int: converted integer
"""
strs = [s.lower() if isinstance(s, str) else s for s in strs]
value = value.lower()
tmp_dict = dict(zip(strs, list(range(len(strs)))))
return str(tmp_dict[value])
def compare_lists(l1, l2, diff_dict):
"""
Compares l1 and l2 lists and adds the items that are different
to the diff_dict dictionary.
Used in recursion with compare_dictionaries() function.
Args:
l1: first list to compare
l2: second list to compare
diff_dict: dictionary to store the difference
Returns:
dict: items that are different
"""
if len(l1) != len(l2):
diff_dict.append(l1)
return diff_dict
for i, item in enumerate(l1):
if isinstance(item, dict):
diff_dict.insert(i, {})
diff_dict[i] = compare_dictionaries(item, l2[i], diff_dict[i])
else:
if item != l2[i]:
diff_dict.append(item)
while {} in diff_dict:
diff_dict.remove({})
return diff_dict
def compare_dictionaries(d1, d2, diff_dict):
"""
Compares d1 and d2 dictionaries and adds the items that are different
to the diff_dict dictionary.
Used in recursion with compare_lists() function.
Args:
d1: first dictionary to compare
d2: second dictionary to compare
diff_dict: dictionary to store the difference
Returns:
dict: items that are different
"""
for k, v in d1.items():
if k not in d2:
diff_dict[k] = v
continue
if isinstance(v, dict):
diff_dict[k] = {}
compare_dictionaries(v, d2[k], diff_dict[k])
if diff_dict[k] == {}:
del diff_dict[k]
else:
diff_dict[k] = v
elif isinstance(v, list):
diff_dict[k] = []
compare_lists(v, d2[k], diff_dict[k])
if diff_dict[k] == []:
del diff_dict[k]
else:
diff_dict[k] = v
else:
if v != d2[k]:
diff_dict[k] = v
return diff_dict
def cleanup_data(obj):
"""Removes the None values from the object and returns the object
Args:
obj: object to cleanup
Returns:
object: cleaned object
"""
if isinstance(obj, (list, tuple, set)):
return type(obj)(cleanup_data(x) for x in obj if x is not None)
elif isinstance(obj, dict):
return type(obj)((cleanup_data(k), cleanup_data(v))
for k, v in obj.items() if k is not None and v is not None)
else:
return obj
def main():
"""Main ansible module function
"""
module = AnsibleModule(
argument_spec=dict(
server_url=dict(type='str', required=True, aliases=['url']),
login_user=dict(type='str', required=True),
login_password=dict(type='str', required=True, no_log=True),
http_login_user=dict(type='str', required=False, default=None),
http_login_password=dict(type='str', required=False, default=None, no_log=True),
validate_certs=dict(type='bool', required=False, default=True),
esc_period=dict(type='str', required=False),
timeout=dict(type='int', default=10),
name=dict(type='str', required=True),
event_source=dict(type='str', required=False, choices=['trigger', 'discovery', 'auto_registration', 'internal']),
state=dict(type='str', required=False, default='present', choices=['present', 'absent']),
status=dict(type='str', required=False, default='enabled', choices=['enabled', 'disabled']),
pause_in_maintenance=dict(type='bool', required=False, default=True),
default_message=dict(type='str', required=False, default=''),
default_subject=dict(type='str', required=False, default=''),
recovery_default_message=dict(type='str', required=False, default=''),
recovery_default_subject=dict(type='str', required=False, default=''),
acknowledge_default_message=dict(type='str', required=False, default=''),
acknowledge_default_subject=dict(type='str', required=False, default=''),
conditions=dict(
type='list',
required=False,
default=[],
elements='dict',
options=dict(
formulaid=dict(type='str', required=False),
operator=dict(type='str', required=True),
type=dict(type='str', required=True),
value=dict(type='str', required=True),
value2=dict(type='str', required=False)
)
),
formula=dict(type='str', required=False, default=None),
eval_type=dict(type='str', required=False, default=None, choices=['andor', 'and', 'or', 'custom_expression']),
operations=dict(
type='list',
required=False,
default=[],
elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=[
'send_message',
'remote_command',
'add_host',
'remove_host',
'add_to_host_group',
'remove_from_host_group',
'link_to_template',
'unlink_from_template',
'enable_host',
'disable_host',
'set_host_inventory_mode',
]
),
esc_period=dict(type='str', required=False),
esc_step_from=dict(type='int', required=False, default=1),
esc_step_to=dict(type='int', required=False, default=1),
operation_condition=dict(
type='str',
required=False,
default=None,
choices=['acknowledged', 'not_acknowledged']
),
# when type is remote_command
command_type=dict(
type='str',
required=False,
choices=[
'custom_script',
'ipmi',
'ssh',
'telnet',
'global_script'
]
),
command=dict(type='str', required=False),
execute_on=dict(
type='str',
required=False,
choices=['agent', 'server', 'proxy']
),
password=dict(type='str', required=False),
port=dict(type='int', required=False),
run_on_groups=dict(type='list', required=False),
run_on_hosts=dict(type='list', required=False),
script_name=dict(type='str', required=False),
ssh_auth_type=dict(
type='str',
required=False,
default='password',
choices=['password', 'public_key']
),
ssh_privatekey_file=dict(type='str', required=False),
ssh_publickey_file=dict(type='str', required=False),
username=dict(type='str', required=False),
# when type is send_message
media_type=dict(type='str', required=False),
subject=dict(type='str', required=False),
message=dict(type='str', required=False),
send_to_groups=dict(type='list', required=False),
send_to_users=dict(type='list', required=False),
# when type is add_to_host_group or remove_from_host_group
host_groups=dict(type='list', required=False),
# when type is set_host_inventory_mode
inventory=dict(type='str', required=False),
# when type is link_to_template or unlink_from_template
templates=dict(type='list', required=False)
),
required_if=[
['type', 'remote_command', ['command_type']],
['type', 'remote_command', ['run_on_groups', 'run_on_hosts'], True],
['command_type', 'custom_script', [
'command',
'execute_on'
]],
['command_type', 'ipmi', ['command']],
['command_type', 'ssh', [
'command',
'password',
'username',
'port',
'ssh_auth_type',
'ssh_privatekey_file',
'ssh_publickey_file'
]],
['command_type', 'telnet', [
'command',
'password',
'username',
'port'
]],
['command_type', 'global_script', ['script_name']],
['type', 'add_to_host_group', ['host_groups']],
['type', 'remove_from_host_group', ['host_groups']],
['type', 'link_to_template', ['templates']],
['type', 'unlink_from_template', ['templates']],
['type', 'set_host_inventory_mode', ['inventory']],
['type', 'send_message', ['send_to_users', 'send_to_groups'], True]
]
),
recovery_operations=dict(
type='list',
required=False,
default=[],
elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=[
'send_message',
'remote_command',
'notify_all_involved'
]
),
# when type is remote_command
command_type=dict(
type='str',
required=False,
choices=[
'custom_script',
'ipmi',
'ssh',
'telnet',
'global_script'
]
),
command=dict(type='str', required=False),
execute_on=dict(
type='str',
required=False,
choices=['agent', 'server', 'proxy']
),
password=dict(type='str', required=False),
port=dict(type='int', required=False),
run_on_groups=dict(type='list', required=False),
run_on_hosts=dict(type='list', required=False),
script_name=dict(type='str', required=False),
ssh_auth_type=dict(
type='str',
required=False,
default='password',
choices=['password', 'public_key']
),
ssh_privatekey_file=dict(type='str', required=False),
ssh_publickey_file=dict(type='str', required=False),
username=dict(type='str', required=False),
# when type is send_message
media_type=dict(type='str', required=False),
subject=dict(type='str', required=False),
message=dict(type='str', required=False),
send_to_groups=dict(type='list', required=False),
send_to_users=dict(type='list', required=False),
),
required_if=[
['type', 'remote_command', ['command_type']],
['type', 'remote_command', [
'run_on_groups',
'run_on_hosts'
], True],
['command_type', 'custom_script', [
'command',
'execute_on'
]],
['command_type', 'ipmi', ['command']],
['command_type', 'ssh', [
'command',
'password',
'username',
'port',
'ssh_auth_type',
'ssh_privatekey_file',
'ssh_publickey_file'
]],
['command_type', 'telnet', [
'command',
'password',
'username',
'port'
]],
['command_type', 'global_script', ['script_name']],
['type', 'send_message', ['send_to_users', 'send_to_groups'], True]
]
),
acknowledge_operations=dict(
type='list',
required=False,
default=[],
elements='dict',
options=dict(
type=dict(
type='str',
required=True,
choices=[
'send_message',
'remote_command',
'notify_all_involved'
]
),
# when type is remote_command
command_type=dict(
type='str',
required=False,
choices=[
'custom_script',
'ipmi',
'ssh',
'telnet',
'global_script'
]
),
command=dict(type='str', required=False),
execute_on=dict(
type='str',
required=False,
choices=['agent', 'server', 'proxy']
),
password=dict(type='str', required=False),
port=dict(type='int', required=False),
run_on_groups=dict(type='list', required=False),
run_on_hosts=dict(type='list', required=False),
script_name=dict(type='str', required=False),
ssh_auth_type=dict(
type='str',
required=False,
default='password',
choices=['password', 'public_key']
),
ssh_privatekey_file=dict(type='str', required=False),
ssh_publickey_file=dict(type='str', required=False),
username=dict(type='str', required=False),
# when type is send_message
media_type=dict(type='str', required=False),
subject=dict(type='str', required=False),
message=dict(type='str', required=False),
send_to_groups=dict(type='list', required=False),
send_to_users=dict(type='list', required=False),
),
required_if=[
['type', 'remote_command', ['command_type']],
['type', 'remote_command', [
'run_on_groups',
'run_on_hosts'
], True],
['command_type', 'custom_script', [
'command',
'execute_on'
]],
['command_type', 'ipmi', ['command']],
['command_type', 'ssh', [
'command',
'password',
'username',
'port',
'ssh_auth_type',
'ssh_privatekey_file',
'ssh_publickey_file'
]],
['command_type', 'telnet', [
'command',
'password',
'username',
'port'
]],
['command_type', 'global_script', ['script_name']],
['type', 'send_message', ['send_to_users', 'send_to_groups'], True]
]
)
),
required_if=[
['state', 'present', [
'esc_period',
'event_source'
]]
],
supports_check_mode=True
)
if not HAS_ZABBIX_API:
module.fail_json(msg=missing_required_lib('zabbix-api', url='https://pypi.org/project/zabbix-api/'), exception=ZBX_IMP_ERR)
server_url = module.params['server_url']
login_user = module.params['login_user']
login_password = module.params['login_password']
http_login_user = module.params['http_login_user']
http_login_password = module.params['http_login_password']
validate_certs = module.params['validate_certs']
timeout = module.params['timeout']
name = module.params['name']
esc_period = module.params['esc_period']
event_source = module.params['event_source']
state = module.params['state']
status = module.params['status']
pause_in_maintenance = module.params['pause_in_maintenance']
default_message = module.params['default_message']
default_subject = module.params['default_subject']
recovery_default_message = module.params['recovery_default_message']
recovery_default_subject = module.params['recovery_default_subject']
acknowledge_default_message = module.params['acknowledge_default_message']
acknowledge_default_subject = module.params['acknowledge_default_subject']
conditions = module.params['conditions']
formula = module.params['formula']
eval_type = module.params['eval_type']
operations = module.params['operations']
recovery_operations = module.params['recovery_operations']
acknowledge_operations = module.params['acknowledge_operations']
try:
zbx = ZabbixAPI(server_url, timeout=timeout, user=http_login_user,
passwd=http_login_password, validate_certs=validate_certs)
zbx.login(login_user, login_password)
atexit.register(zbx.logout)
except Exception as e:
module.fail_json(msg="Failed to connect to Zabbix server: %s" % e)
zapi_wrapper = Zapi(module, zbx)
action = Action(module, zbx, zapi_wrapper)
action_exists = zapi_wrapper.check_if_action_exists(name)
ops = Operations(module, zbx, zapi_wrapper)
recovery_ops = RecoveryOperations(module, zbx, zapi_wrapper)
acknowledge_ops = AcknowledgeOperations(module, zbx, zapi_wrapper)
fltr = Filter(module, zbx, zapi_wrapper)
if action_exists:
action_id = zapi_wrapper.get_action_by_name(name)['actionid']
if state == "absent":
result = action.delete_action(action_id)
module.exit_json(changed=True, msg="Action Deleted: %s, ID: %s" % (name, result))
else:
difference = action.check_difference(
action_id=action_id,
name=name,
event_source=event_source,
esc_period=esc_period,
status=status,
pause_in_maintenance=pause_in_maintenance,
default_message=default_message,
default_subject=default_subject,
recovery_default_message=recovery_default_message,
recovery_default_subject=recovery_default_subject,
acknowledge_default_message=acknowledge_default_message,
acknowledge_default_subject=acknowledge_default_subject,
operations=ops.construct_the_data(operations),
recovery_operations=recovery_ops.construct_the_data(recovery_operations),
acknowledge_operations=acknowledge_ops.construct_the_data(acknowledge_operations),
conditions=fltr.construct_the_data(eval_type, formula, conditions)
)
if difference == {}:
module.exit_json(changed=False, msg="Action is up to date: %s" % (name))
else:
result = action.update_action(
action_id=action_id,
**difference
)
module.exit_json(changed=True, msg="Action Updated: %s, ID: %s" % (name, result))
else:
if state == "absent":
module.exit_json(changed=False)
else:
action_id = action.add_action(
name=name,
event_source=event_source,
esc_period=esc_period,
status=status,
pause_in_maintenance=pause_in_maintenance,
default_message=default_message,
default_subject=default_subject,
recovery_default_message=recovery_default_message,
recovery_default_subject=recovery_default_subject,
acknowledge_default_message=acknowledge_default_message,
acknowledge_default_subject=acknowledge_default_subject,
operations=ops.construct_the_data(operations),
recovery_operations=recovery_ops.construct_the_data(recovery_operations),
acknowledge_operations=acknowledge_ops.construct_the_data(acknowledge_operations),
conditions=fltr.construct_the_data(eval_type, formula, conditions)
)
module.exit_json(changed=True, msg="Action created: %s, ID: %s" % (name, action_id))
if __name__ == '__main__':
main()