zabbix: New module zabbix mediatype (#57488)

Co-Authored-By: Dusan Matejka <D3DeFi@users.noreply.github.com>
This commit is contained in:
Ruben Tsirunyan 2019-06-17 01:16:58 +04:00 committed by René Moser
parent 7f536630eb
commit 9e225fbb1e

View file

@ -0,0 +1,688 @@
#!/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_mediatype
short_description: Create/Update/Delete Zabbix media types
description:
- This module allows you to create, modify and delete Zabbix media types.
version_added: "2.9"
author:
- Ruben Tsirunyan (@rubentsirunyan)
requirements:
- zabbix-api
options:
name:
type: 'str'
description:
- Name of the media type.
required: true
state:
type: 'str'
description:
- Desired state of the mediatype.
- On C(present), it will create a medatype if it does not exist or update the mediatype if the associated data is different.
- On C(absent), it will remove the mediatype if it exists.
choices:
- present
- absent
default: 'present'
required: true
type:
type: 'str'
description:
- Type of the media type.
choices:
- email
- script
- sms
- jabber
- ez_texting
required: true
status:
type: 'str'
description:
- Whether the media type is enabled or no.
choices:
- enabled
- disabled
default: 'enabled'
max_sessions:
type: 'int'
description:
- The maximum number of alerts that can be processed in parallel.
- Possible value is 1 when I(type=sms) and 0-100 otherwise.
default: 1
max_attempts:
type: 'int'
description:
- The maximum number of attempts to send an alert.
- Possible range is 0-10
default: 3
attempt_interval:
type: 'int'
description:
- The interval between retry attempts.
- Possible range is 0-60
default: 10
script_name:
type: 'str'
description:
- The name of the executed script.
- Required when I(type=script).
script_params:
type: 'list'
description:
- List of script parameters.
- Required when I(type=script).
gsm_modem:
type: 'str'
description:
- Serial device name of the gsm modem.
- Required when I(type=sms).
username:
type: 'str'
description:
- Username or Jabber identifier.
- Required when I(type=jabber) or I(type=ez_texting).
- Required when I(type=email) and I(smtp_authentication=true).
password:
type: 'str'
description:
- Authentication password.
- Required when I(type=jabber) or I(type=ez_texting).
- Required when I(type=email) and I(smtp_authentication=true).
smtp_server:
type: 'str'
description:
- SMTP server host.
- Required when I(type=email).
default: 'localhost'
smtp_server_port:
type: 'int'
description:
- SMTP server port.
- Required when I(type=email).
default: 25
smtp_helo:
type: 'str'
description:
- SMTP HELO.
- Required when I(type=email).
default: 'localhost'
smtp_email:
type: 'str'
description:
- Email address from which notifications will be sent.
- Required when I(type=email).
smtp_authentication:
type: 'bool'
description:
- Whether SMTP authetication with username and password should be enabled or not.
- If set to C(true), C(username) and C(password) should be specified.
default: false
smtp_security:
type: 'str'
description:
- SMTP connection security level to use.
choices:
- None
- STARTTLS
- SSL/TLS
smtp_verify_host:
type: 'bool'
description:
- SSL verify host for SMTP.
- Can be specified when I(smtp_security=STARTTLS) or I(smtp_security=SSL/TLS)
default: false
smtp_verify_peer:
type: 'bool'
description:
- SSL verify peer for SMTP.
- Can be specified when I(smtp_security=STARTTLS) or I(smtp_security=SSL/TLS)
default: false
message_text_limit:
type: 'str'
description:
- The message text limit.
- Required when I(type=ez_texting).
- 160 characters for USA and 136 characters for Canada.
choices:
- USA
- Canada
extends_documentation_fragment:
- zabbix
'''
RETURN = '''
'''
EXAMPLES = '''
- name: 'Create an email mediatype with SMTP authentication'
zabbix_mediatype:
name: "Ops email"
server_url: "http://example.com/zabbix/"
login_user: Admin
login_password: "zabbix"
type: 'email'
smtp_server: 'example.com'
smtp_server_port: 2000
smtp_email: 'ops@example.com'
smtp_authentication: true
username: 'smtp_user'
password: 'smtp_pass'
- name: 'Create a script mediatype'
zabbix_mediatype:
name: "my script"
server_url: "http://example.com/zabbix/"
login_user: Admin
login_password: "zabbix"
type: 'script'
script_name: 'my_script.py'
script_params:
- 'arg1'
- 'arg2'
- name: 'Create a jabber mediatype'
zabbix_mediatype:
name: "My jabber"
server_url: "http://example.com/zabbix/"
login_user: Admin
login_password: "zabbix"
type: 'jabber'
username: 'jabber_id'
password: 'jabber_pass'
- name: 'Create an SMS mediatype'
zabbix_mediatype:
name: "My SMS Mediatype"
server_url: "http://example.com/zabbix/"
login_user: Admin
login_password: "zabbix"
type: 'sms'
gsm_modem: '/dev/ttyS0'
'''
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.common.text.converters import container_to_bytes
try:
from zabbix_api import ZabbixAPI
HAS_ZABBIX_API = True
except ImportError:
ZBX_IMP_ERR = traceback.format_exc()
HAS_ZABBIX_API = False
def to_numeric_value(value, strs):
return strs.get(value)
def validate_params(module, params):
"""Validates arguments that are required together.
Fails the module with the message that shows the missing
requirements if there are some.
Args:
module: AnsibleModule object.
params (list): Each element of this list
is a list like
['argument_key', 'argument_value', ['required_arg_1',
'required_arg_2']].
Format is the same as `required_if` parameter of AnsibleModule.
"""
for param in params:
if module.params[param[0]] == param[1]:
if None in [module.params[i] for i in param[2]]:
module.fail_json(
msg="Following arguments are required when {key} is {value}: {arguments}".format(
key=param[0],
value=param[1],
arguments=', '.join(param[2])
)
)
def construct_parameters(**kwargs):
"""Translates data to a format suitable for Zabbix API and filters
the ones that are related to the specified mediatype type.
Args:
**kwargs: Arguments passed to the module.
Returns:
A dictionary of arguments that are related to kwargs['transport_type'],
and are in a format that is understandable by Zabbix API.
"""
if kwargs['transport_type'] == 'email':
return dict(
description=kwargs['name'],
status=to_numeric_value(kwargs['status'],
{'enabled': '0',
'disabled': '1'}),
type=to_numeric_value(kwargs['transport_type'],
{'email': '0',
'script': '1',
'sms': '2',
'jabber': '3',
'ez_texting': '100'}),
maxsessions=str(kwargs['max_sessions']),
maxattempts=str(kwargs['max_attempts']),
attempt_interval=str(kwargs['attempt_interval']),
smtp_server=kwargs['smtp_server'],
smtp_port=str(kwargs['smtp_server_port']),
smtp_helo=kwargs['smtp_helo'],
smtp_email=kwargs['smtp_email'],
smtp_security=to_numeric_value(str(kwargs['smtp_security']),
{'None': '0',
'STARTTLS': '1',
'SSL/TLS': '2'}),
smtp_authentication=to_numeric_value(str(kwargs['smtp_authentication']),
{'False': '0',
'True': '1'}),
smtp_verify_host=to_numeric_value(str(kwargs['smtp_verify_host']),
{'False': '0',
'True': '1'}),
smtp_verify_peer=to_numeric_value(str(kwargs['smtp_verify_peer']),
{'False': '0',
'True': '1'}),
username=kwargs['username'],
passwd=kwargs['password']
)
elif kwargs['transport_type'] == 'script':
if kwargs['script_params'] is None:
_script_params = '' # ZBX-15706
else:
_script_params = '\n'.join(str(i) for i in kwargs['script_params']) + '\n'
return dict(
description=kwargs['name'],
status=to_numeric_value(kwargs['status'],
{'enabled': '0',
'disabled': '1'}),
type=to_numeric_value(kwargs['transport_type'],
{'email': '0',
'script': '1',
'sms': '2',
'jabber': '3',
'ez_texting': '100'}),
maxsessions=str(kwargs['max_sessions']),
maxattempts=str(kwargs['max_attempts']),
attempt_interval=str(kwargs['attempt_interval']),
exec_path=kwargs['script_name'],
exec_params=_script_params
)
elif kwargs['transport_type'] == 'sms':
return dict(
description=kwargs['name'],
status=to_numeric_value(kwargs['status'],
{'enabled': '0',
'disabled': '1'}),
type=to_numeric_value(kwargs['transport_type'],
{'email': '0',
'script': '1',
'sms': '2',
'jabber': '3',
'ez_texting': '100'}),
maxsessions=str(kwargs['max_sessions']),
maxattempts=str(kwargs['max_attempts']),
attempt_interval=str(kwargs['attempt_interval']),
gsm_modem=kwargs['gsm_modem']
)
elif kwargs['transport_type'] == 'jabber':
return dict(
description=kwargs['name'],
status=to_numeric_value(kwargs['status'],
{'enabled': '0',
'disabled': '1'}),
type=to_numeric_value(kwargs['transport_type'],
{'email': '0',
'script': '1',
'sms': '2',
'jabber': '3',
'ez_texting': '100'}),
maxsessions=str(kwargs['max_sessions']),
maxattempts=str(kwargs['max_attempts']),
attempt_interval=str(kwargs['attempt_interval']),
username=kwargs['username'],
passwd=kwargs['password']
)
elif kwargs['transport_type'] == 'ez_texting':
return dict(
description=kwargs['name'],
status=to_numeric_value(kwargs['status'],
{'enabled': '0',
'disabled': '1'}),
type=to_numeric_value(kwargs['transport_type'],
{'email': '0',
'script': '1',
'sms': '2',
'jabber': '3',
'ez_texting': '100'}),
maxsessions=str(kwargs['max_sessions']),
maxattempts=str(kwargs['max_attempts']),
attempt_interval=str(kwargs['attempt_interval']),
username=kwargs['username'],
passwd=kwargs['password'],
exec_path=to_numeric_value(kwargs['message_text_limit'],
{'USA': '0',
'Canada': '1'}),
)
def check_if_mediatype_exists(module, zbx, name):
"""Checks if mediatype exists.
Args:
module: AnsibleModule object
zbx: ZabbixAPI object
name: Zabbix mediatype name
Returns:
Tuple of (True, `id of the mediatype`) if mediatype exists, (False, None) otherwise
"""
try:
mediatype_list = zbx.mediatype.get({
'output': 'extend',
'filter': {'description': [name]}
})
if len(mediatype_list) < 1:
return False, None
else:
return True, mediatype_list[0]['mediatypeid']
except Exception as e:
module.fail_json(msg="Failed to get ID of the mediatype '{name}': {e}".format(name=name, e=e))
def diff(existing, new):
"""Constructs the diff for Ansible's --diff option.
Args:
existing (dict): Existing mediatype data.
new (dict): New mediatype data.
Returns:
A dictionary like {'before': existing, 'after': new}
with filtered empty values.
"""
before = {}
after = {}
for key in new:
before[key] = existing[key]
if new[key] is None:
after[key] = ''
else:
after[key] = new[key]
return {'before': before, 'after': after}
def get_update_params(module, zbx, mediatype_id, **kwargs):
"""Filters only the parameters that are different and need to be updated.
Args:
module: AnsibleModule object.
zbx: ZabbixAPI object.
mediatype_id (int): ID of the mediatype to be updated.
**kwargs: Parameters for the new mediatype.
Returns:
A tuple where the first element is a dictionary of parameters
that need to be updated and the second one is a dictionary
returned by diff() function with
existing mediatype data and new params passed to it.
"""
existing_mediatype = container_to_bytes(zbx.mediatype.get({
'output': 'extend',
'mediatypeids': [mediatype_id]
})[0])
if existing_mediatype['type'] != kwargs['type']:
return kwargs, diff(existing_mediatype, kwargs)
else:
params_to_update = {}
for key in kwargs:
if (not (kwargs[key] is None and existing_mediatype[key] == '')) and kwargs[key] != existing_mediatype[key]:
params_to_update[key] = kwargs[key]
return params_to_update, diff(existing_mediatype, kwargs)
def delete_mediatype(module, zbx, mediatype_id):
try:
return zbx.mediatype.delete([mediatype_id])
except Exception as e:
module.fail_json(msg="Failed to delete mediatype '{_id}': {e}".format(_id=mediatype_id, e=e))
def update_mediatype(module, zbx, **kwargs):
try:
pass
mediatype_id = zbx.mediatype.update(kwargs)
except Exception as e:
module.fail_json(msg="Failed to update mediatype '{_id}': {e}".format(_id=kwargs['mediatypeid'], e=e))
def create_mediatype(module, zbx, **kwargs):
try:
mediatype_id = zbx.mediatype.create(kwargs)
except Exception as e:
module.fail_json(msg="Failed to create mediatype '{name}': {e}".format(name=kwargs['description'], e=e))
def main():
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), timeout=dict(type='int', default=10),
name=dict(type='str', required=True),
state=dict(type='str', default='present', choices=['present', 'absent']),
type=dict(type='str', choices=['email', 'script', 'sms', 'jabber', 'ez_texting'], required=True),
status=dict(type='str', default='enabled', choices=['enabled', 'disabled'], required=False),
max_sessions=dict(type='int', default=1, required=False),
max_attempts=dict(type='int', default=3, required=False),
attempt_interval=dict(type='int', default=10, required=False),
# Script
script_name=dict(type='str', required=False),
script_params=dict(type='list', required=False),
# SMS
gsm_modem=dict(type='str', required=False),
# Jabber
username=dict(type='str', required=False),
password=dict(type='str', required=False, no_log=True),
# Email
smtp_server=dict(type='str', default='localhost', required=False),
smtp_server_port=dict(type='int', default=25, required=False),
smtp_helo=dict(type='str', default='localhost', required=False),
smtp_email=dict(type='str', required=False),
smtp_security=dict(type='str', required=False, choices=['None', 'STARTTLS', 'SSL/TLS']),
smtp_authentication=dict(type='bool', default=False, required=False),
smtp_verify_host=dict(type='bool', default=False, required=False),
smtp_verify_peer=dict(type='bool', default=False, required=False),
# EZ Text
message_text_limit=dict(type='str', required=False, choices=['USA', 'Canada'])
)
required_params = [
['type', 'email', ['smtp_email']],
['type', 'script', ['script_name']],
['type', 'sms', ['gsm_modem']],
['type', 'jabber', ['username', 'password']],
['type', 'ez_texting', ['username', 'password', 'message_text_limit']],
['smtp_authentication', True, ['username', 'password']]
]
module = AnsibleModule(
argument_spec=argument_spec,
supports_check_mode=True
)
if module.params['state'] == 'present':
validate_params(module, required_params)
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']
state = module.params['state']
timeout = module.params['timeout']
name = module.params['name']
transport_type = module.params['type']
status = module.params['status']
max_sessions = module.params['max_sessions']
max_attempts = module.params['max_attempts']
attempt_interval = module.params['attempt_interval']
# Script
script_name = module.params['script_name']
script_params = module.params['script_params']
# SMS
gsm_modem = module.params['gsm_modem']
# Jabber
username = module.params['username']
password = module.params['password']
# Email
smtp_server = module.params['smtp_server']
smtp_server_port = module.params['smtp_server_port']
smtp_helo = module.params['smtp_helo']
smtp_email = module.params['smtp_email']
smtp_security = module.params['smtp_security']
smtp_authentication = module.params['smtp_authentication']
smtp_verify_host = module.params['smtp_verify_host']
smtp_verify_peer = module.params['smtp_verify_peer']
# EZ Text
message_text_limit = module.params['message_text_limit']
zbx = None
# login to zabbix
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)
except Exception as e:
module.fail_json(msg="Failed to connect to Zabbix server: %s" % e)
mediatype_exists, mediatype_id = check_if_mediatype_exists(module, zbx, name)
parameters = construct_parameters(
name=name,
transport_type=transport_type,
status=status,
max_sessions=max_sessions,
max_attempts=max_attempts,
attempt_interval=attempt_interval,
script_name=script_name,
script_params=script_params,
gsm_modem=gsm_modem,
username=username,
password=password,
smtp_server=smtp_server,
smtp_server_port=smtp_server_port,
smtp_helo=smtp_helo,
smtp_email=smtp_email,
smtp_security=smtp_security,
smtp_authentication=smtp_authentication,
smtp_verify_host=smtp_verify_host,
smtp_verify_peer=smtp_verify_peer,
message_text_limit=message_text_limit
)
if mediatype_exists:
if state == 'absent':
if module.check_mode:
module.exit_json(
changed=True,
msg="Mediatype would have been deleted. Name: {name}, ID: {_id}".format(
name=name,
_id=mediatype_id
)
)
mediatype_id = delete_mediatype(module, zbx, mediatype_id)
module.exit_json(
changed=True,
msg="Mediatype deleted. Name: {name}, ID: {_id}".format(
name=name,
_id=mediatype_id
)
)
else:
params_to_update, diff = get_update_params(module, zbx, mediatype_id, **parameters)
if params_to_update == {}:
module.exit_json(
changed=False,
msg="Mediatype is up to date: {name}".format(name=name)
)
else:
if module.check_mode:
module.exit_json(
changed=True,
diff=diff,
msg="Mediatype would have been updated. Name: {name}, ID: {_id}".format(
name=name,
_id=mediatype_id
)
)
mediatype_id = update_mediatype(
module, zbx,
mediatypeid=mediatype_id,
**params_to_update
)
module.exit_json(
changed=True,
diff=diff,
msg="Mediatype updated. Name: {name}, ID: {_id}".format(
name=name,
_id=mediatype_id
)
)
else:
if state == "absent":
module.exit_json(changed=False)
else:
if module.check_mode:
module.exit_json(
changed=True,
msg="Mediatype would have been created. Name: {name}, ID: {_id}".format(
name=name,
_id=mediatype_id
)
)
mediatype_id = create_mediatype(module, zbx, **parameters)
module.exit_json(
changed=True,
msg="Mediatype created: {name}, ID: {_id}".format(
name=name,
_id=mediatype_id
)
)
if __name__ == '__main__':
main()