mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
663 lines
24 KiB
Python
663 lines
24 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright: (c) 2019, sky-joker
|
|
# 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 = r'''
|
|
module: zabbix_user
|
|
short_description: Create/update/delete Zabbix users
|
|
author:
|
|
- sky-joker (@sky-joker)
|
|
description:
|
|
- This module allows you to create, modify and delete Zabbix users.
|
|
requirements:
|
|
- "python >= 2.6"
|
|
- "zabbix-api >= 0.5.4"
|
|
options:
|
|
alias:
|
|
description:
|
|
- Name of the user alias in Zabbix.
|
|
- alias is the unique identifier used and cannot be updated using this module.
|
|
required: true
|
|
type: str
|
|
name:
|
|
description:
|
|
- Name of the user.
|
|
default: ''
|
|
type: str
|
|
surname:
|
|
description:
|
|
- Surname of the user.
|
|
default: ''
|
|
type: str
|
|
usrgrps:
|
|
description:
|
|
- User groups to add the user to.
|
|
required: true
|
|
type: list
|
|
elements: str
|
|
passwd:
|
|
description:
|
|
- User's password.
|
|
required: true
|
|
type: str
|
|
override_passwd:
|
|
description:
|
|
- Override password.
|
|
default: no
|
|
type: bool
|
|
lang:
|
|
description:
|
|
- Language code of the user's language.
|
|
default: 'en_GB'
|
|
choices:
|
|
- 'en_GB'
|
|
- 'en_US'
|
|
- 'zh_CN'
|
|
- 'cs_CZ'
|
|
- 'fr_FR'
|
|
- 'he_IL'
|
|
- 'it_IT'
|
|
- 'ko_KR'
|
|
- 'ja_JP'
|
|
- 'nb_NO'
|
|
- 'pl_PL'
|
|
- 'pt_BR'
|
|
- 'pt_PT'
|
|
- 'ru_RU'
|
|
- 'sk_SK'
|
|
- 'tr_TR'
|
|
- 'uk_UA'
|
|
type: str
|
|
theme:
|
|
description:
|
|
- User's theme.
|
|
default: 'default'
|
|
choices:
|
|
- 'default'
|
|
- 'blue-theme'
|
|
- 'dark-theme'
|
|
type: str
|
|
autologin:
|
|
description:
|
|
- Whether to enable auto-login.
|
|
- If enable autologin, cannot enable autologout.
|
|
default: false
|
|
type: bool
|
|
autologout:
|
|
description:
|
|
- User session life time in seconds. If set to 0, the session will never expire.
|
|
- If enable autologout, cannot enable autologin.
|
|
default: '0'
|
|
type: str
|
|
refresh:
|
|
description:
|
|
- Automatic refresh period in seconds.
|
|
default: '30'
|
|
type: str
|
|
rows_per_page:
|
|
description:
|
|
- Amount of object rows to show per page.
|
|
default: '50'
|
|
type: str
|
|
after_login_url:
|
|
description:
|
|
- URL of the page to redirect the user to after logging in.
|
|
default: ''
|
|
type: str
|
|
user_medias:
|
|
description:
|
|
- Set the user's media.
|
|
default: []
|
|
suboptions:
|
|
mediatype:
|
|
description:
|
|
- Media type name to set.
|
|
default: 'Email'
|
|
type: str
|
|
sendto:
|
|
description:
|
|
- Address, user name or other identifier of the recipient.
|
|
required: true
|
|
type: str
|
|
period:
|
|
description:
|
|
- Time when the notifications can be sent as a time period or user macros separated by a semicolon.
|
|
- Please review the documentation for more information on the supported time period.
|
|
- https://www.zabbix.com/documentation/4.0/manual/appendix/time_period
|
|
default: '1-7,00:00-24:00'
|
|
type: str
|
|
severity:
|
|
description:
|
|
- Trigger severities to send notifications about.
|
|
suboptions:
|
|
not_classified:
|
|
description:
|
|
- severity not_classified enable/disable.
|
|
default: True
|
|
type: bool
|
|
information:
|
|
description:
|
|
- severity information enable/disable.
|
|
default: True
|
|
type: bool
|
|
warning:
|
|
description:
|
|
- severity warning enable/disable.
|
|
default: True
|
|
type: bool
|
|
average:
|
|
description:
|
|
- severity average enable/disable.
|
|
default: True
|
|
type: bool
|
|
high:
|
|
description:
|
|
- severity high enable/disable.
|
|
default: True
|
|
type: bool
|
|
disaster:
|
|
description:
|
|
- severity disaster enable/disable.
|
|
default: True
|
|
type: bool
|
|
default:
|
|
not_classified: True
|
|
information: True
|
|
warning: True
|
|
average: True
|
|
high: True
|
|
disaster: True
|
|
type: dict
|
|
active:
|
|
description:
|
|
- Whether the media is enabled.
|
|
default: true
|
|
type: bool
|
|
type: list
|
|
elements: dict
|
|
type:
|
|
description:
|
|
- Type of the user.
|
|
default: 'Zabbix user'
|
|
choices:
|
|
- 'Zabbix user'
|
|
- 'Zabbix admin'
|
|
- 'Zabbix super admin'
|
|
type: str
|
|
state:
|
|
description:
|
|
- State of the user.
|
|
- On C(present), it will create if user does not exist or update the user if the associated data is different.
|
|
- On C(absent) will remove a user if it exists.
|
|
default: 'present'
|
|
choices: ['present', 'absent']
|
|
type: str
|
|
extends_documentation_fragment:
|
|
- community.general.zabbix
|
|
|
|
'''
|
|
|
|
EXAMPLES = r'''
|
|
- name: create of zabbix user.
|
|
zabbix_user:
|
|
server_url: "http://zabbix.example.com/zabbix/"
|
|
login_user: Admin
|
|
login_password: secret
|
|
alias: example
|
|
name: user name
|
|
surname: user surname
|
|
usrgrps:
|
|
- Guests
|
|
- Disabled
|
|
passwd: password
|
|
lang: en_GB
|
|
theme: blue-theme
|
|
autologin: no
|
|
autologout: '0'
|
|
refresh: '30'
|
|
rows_per_page: '200'
|
|
after_login_url: ''
|
|
user_medias:
|
|
- mediatype: Email
|
|
sendto: example@example.com
|
|
period: 1-7,00:00-24:00
|
|
severity:
|
|
not_classified: no
|
|
information: yes
|
|
warning: yes
|
|
average: yes
|
|
high: yes
|
|
disaster: yes
|
|
active: no
|
|
type: Zabbix super admin
|
|
state: present
|
|
|
|
- name: delete of zabbix user.
|
|
zabbix_user:
|
|
server_url: "http://zabbix.example.com/zabbix/"
|
|
login_user: admin
|
|
login_password: secret
|
|
alias: example
|
|
usrgrps:
|
|
- Guests
|
|
passwd: password
|
|
user_medias:
|
|
- sendto: example@example.com
|
|
state: absent
|
|
'''
|
|
|
|
RETURN = r'''
|
|
user_ids:
|
|
description: User id created or changed
|
|
returned: success
|
|
type: dict
|
|
sample: { "userids": [ "5" ] }
|
|
'''
|
|
|
|
import atexit
|
|
import traceback
|
|
|
|
try:
|
|
from zabbix_api import ZabbixAPI
|
|
from zabbix_api import Already_Exists
|
|
|
|
HAS_ZABBIX_API = True
|
|
except ImportError:
|
|
ZBX_IMP_ERR = traceback.format_exc()
|
|
HAS_ZABBIX_API = False
|
|
|
|
from distutils.version import LooseVersion
|
|
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
|
import copy
|
|
|
|
|
|
class User(object):
|
|
def __init__(self, module, zbx):
|
|
self._module = module
|
|
self._zapi = zbx
|
|
self._zbx_api_version = zbx.api_version()[:3]
|
|
|
|
def get_usergroupid_by_user_group_name(self, usrgrps):
|
|
user_group_ids = []
|
|
for user_group_name in usrgrps:
|
|
user_group = self._zapi.usergroup.get({'output': 'extend', 'filter': {'name': user_group_name}})
|
|
if user_group:
|
|
user_group_ids.append({'usrgrpid': user_group[0]['usrgrpid']})
|
|
else:
|
|
self._module.fail_json(msg="User group not found: %s" % user_group_name)
|
|
return user_group_ids
|
|
|
|
def check_user_exist(self, alias):
|
|
zbx_user = self._zapi.user.get({'output': 'extend', 'filter': {'alias': alias},
|
|
'getAccess': True, 'selectMedias': 'extend',
|
|
'selectUsrgrps': 'extend'})
|
|
|
|
return zbx_user
|
|
|
|
def convert_user_medias_parameter_types(self, user_medias):
|
|
copy_user_medias = copy.deepcopy(user_medias)
|
|
for user_media in copy_user_medias:
|
|
media_types = self._zapi.mediatype.get({'output': 'extend'})
|
|
for media_type in media_types:
|
|
if LooseVersion(self._zbx_api_version) < LooseVersion('4.4'):
|
|
if media_type['description'] == user_media['mediatype']:
|
|
user_media['mediatypeid'] = media_type['mediatypeid']
|
|
break
|
|
else:
|
|
if media_type['name'] == user_media['mediatype']:
|
|
user_media['mediatypeid'] = media_type['mediatypeid']
|
|
break
|
|
|
|
if 'mediatypeid' not in user_media:
|
|
self._module.fail_json(msg="Media type not found: %s" % user_media['mediatype'])
|
|
else:
|
|
del user_media['mediatype']
|
|
|
|
severity_binary_number = ''
|
|
for severity_key in 'disaster', 'high', 'average', 'warning', 'information', 'not_classified':
|
|
if user_media['severity'][severity_key]:
|
|
severity_binary_number = severity_binary_number + '1'
|
|
else:
|
|
severity_binary_number = severity_binary_number + '0'
|
|
user_media['severity'] = str(int(severity_binary_number, 2))
|
|
|
|
if user_media['active']:
|
|
user_media['active'] = '0'
|
|
else:
|
|
user_media['active'] = '1'
|
|
|
|
return copy_user_medias
|
|
|
|
def user_parameter_difference_check(self, zbx_user, alias, name, surname, user_group_ids, passwd, lang, theme,
|
|
autologin, autologout, refresh, rows_per_page, url, user_medias, user_type,
|
|
override_passwd):
|
|
|
|
user_medias = self.convert_user_medias_parameter_types(user_medias)
|
|
|
|
# existing data
|
|
existing_data = copy.deepcopy(zbx_user[0])
|
|
usrgrpids = []
|
|
for usrgrp in existing_data['usrgrps']:
|
|
usrgrpids.append({'usrgrpid': usrgrp['usrgrpid']})
|
|
|
|
existing_data['usrgrps'] = sorted(usrgrpids, key=lambda x: x['usrgrpid'])
|
|
|
|
# Processing for zabbix 4.0 and above.
|
|
# In zabbix 4.0 and above, Email sendto is of type list.
|
|
# This module, one media supports only one Email sendto.
|
|
# Therefore following processing extract one Email from list.
|
|
if LooseVersion(self._zbx_api_version) >= LooseVersion('4.0'):
|
|
for media in existing_data['medias']:
|
|
if isinstance(media['sendto'], list):
|
|
media['sendto'] = media['sendto'][0]
|
|
|
|
existing_data['user_medias'] = sorted(existing_data['medias'], key=lambda x: x['sendto'])
|
|
for del_key in ['medias', 'attempt_clock', 'attempt_failed', 'attempt_ip', 'debug_mode', 'users_status',
|
|
'gui_access']:
|
|
del existing_data[del_key]
|
|
|
|
for user_media in existing_data['user_medias']:
|
|
for del_key in ['mediaid', 'userid']:
|
|
del user_media[del_key]
|
|
|
|
# request data
|
|
request_data = {
|
|
'userid': zbx_user[0]['userid'],
|
|
'alias': alias,
|
|
'name': name,
|
|
'surname': surname,
|
|
'usrgrps': sorted(user_group_ids, key=lambda x: x['usrgrpid']),
|
|
'lang': lang,
|
|
'theme': theme,
|
|
'autologin': autologin,
|
|
'autologout': autologout,
|
|
'refresh': refresh,
|
|
'rows_per_page': rows_per_page,
|
|
'url': url,
|
|
'user_medias': sorted(user_medias, key=lambda x: x['sendto']),
|
|
'type': user_type
|
|
}
|
|
|
|
if override_passwd:
|
|
request_data['passwd'] = passwd
|
|
|
|
user_parameter_difference_check_result = True
|
|
if existing_data == request_data:
|
|
user_parameter_difference_check_result = False
|
|
|
|
diff_params = {
|
|
"before": existing_data,
|
|
"after": request_data
|
|
}
|
|
|
|
return user_parameter_difference_check_result, diff_params
|
|
|
|
def add_user(self, alias, name, surname, user_group_ids, passwd, lang, theme, autologin, autologout, refresh,
|
|
rows_per_page, url, user_medias, user_type):
|
|
|
|
user_medias = self.convert_user_medias_parameter_types(user_medias)
|
|
|
|
user_ids = {}
|
|
|
|
request_data = {
|
|
'alias': alias,
|
|
'name': name,
|
|
'surname': surname,
|
|
'usrgrps': user_group_ids,
|
|
'passwd': passwd,
|
|
'lang': lang,
|
|
'theme': theme,
|
|
'autologin': autologin,
|
|
'autologout': autologout,
|
|
'refresh': refresh,
|
|
'rows_per_page': rows_per_page,
|
|
'url': url,
|
|
'user_medias': user_medias,
|
|
'type': user_type
|
|
}
|
|
|
|
diff_params = {}
|
|
if not self._module.check_mode:
|
|
try:
|
|
user_ids = self._zapi.user.create(request_data)
|
|
except Exception as e:
|
|
self._module.fail_json(msg="Failed to create user %s: %s" % (alias, e))
|
|
else:
|
|
diff_params = {
|
|
"before": "",
|
|
"after": request_data
|
|
}
|
|
|
|
return user_ids, diff_params
|
|
|
|
def update_user(self, zbx_user, alias, name, surname, user_group_ids, passwd, lang, theme, autologin, autologout,
|
|
refresh, rows_per_page, url, user_medias, user_type, override_passwd):
|
|
|
|
user_medias = self.convert_user_medias_parameter_types(user_medias)
|
|
|
|
user_ids = {}
|
|
|
|
request_data = {
|
|
'userid': zbx_user[0]['userid'],
|
|
'alias': alias,
|
|
'name': name,
|
|
'surname': surname,
|
|
'usrgrps': user_group_ids,
|
|
'lang': lang,
|
|
'theme': theme,
|
|
'autologin': autologin,
|
|
'autologout': autologout,
|
|
'refresh': refresh,
|
|
'rows_per_page': rows_per_page,
|
|
'url': url,
|
|
'type': user_type
|
|
}
|
|
|
|
if override_passwd:
|
|
request_data['passwd'] = passwd
|
|
|
|
# In the case of zabbix 3.2 or less, it is necessary to use updatemedia method to update media.
|
|
if LooseVersion(self._zbx_api_version) <= LooseVersion('3.2'):
|
|
try:
|
|
user_ids = self._zapi.user.update(request_data)
|
|
except Exception as e:
|
|
self._module.fail_json(msg="Failed to update user %s: %s" % (alias, e))
|
|
|
|
try:
|
|
user_ids = self._zapi.user.updatemedia({
|
|
'users': [{'userid': zbx_user[0]['userid']}],
|
|
'medias': user_medias
|
|
})
|
|
except Exception as e:
|
|
self._module.fail_json(msg="Failed to update user medias %s: %s" % (alias, e))
|
|
|
|
if LooseVersion(self._zbx_api_version) >= LooseVersion('3.4'):
|
|
try:
|
|
request_data['user_medias'] = user_medias
|
|
user_ids = self._zapi.user.update(request_data)
|
|
except Exception as e:
|
|
self._module.fail_json(msg="Failed to update user %s: %s" % (alias, e))
|
|
|
|
return user_ids
|
|
|
|
def delete_user(self, zbx_user, alias):
|
|
user_ids = {}
|
|
diff_params = {}
|
|
|
|
if not self._module.check_mode:
|
|
try:
|
|
user_ids = self._zapi.user.delete([zbx_user[0]['userid']])
|
|
except Exception as e:
|
|
self._module.fail_json(msg="Failed to delete user %s: %s" % (alias, e))
|
|
else:
|
|
diff_params = {
|
|
"before": zbx_user[0],
|
|
"after": ""
|
|
}
|
|
|
|
return user_ids, diff_params
|
|
|
|
|
|
def main():
|
|
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),
|
|
alias=dict(type='str', required=True),
|
|
name=dict(type='str', default=''),
|
|
surname=dict(type='str', default=''),
|
|
usrgrps=dict(type='list', required=True),
|
|
passwd=dict(type='str', required=True, no_log=True),
|
|
override_passwd=dict(type='bool', required=False, default=False),
|
|
lang=dict(type='str', default='en_GB', choices=['en_GB', 'en_US', 'zh_CN', 'cs_CZ', 'fr_FR',
|
|
'he_IL', 'it_IT', 'ko_KR', 'ja_JP', 'nb_NO',
|
|
'pl_PL', 'pt_BR', 'pt_PT', 'ru_RU', 'sk_SK',
|
|
'tr_TR', 'uk_UA']),
|
|
theme=dict(type='str', default='default', choices=['default', 'blue-theme', 'dark-theme']),
|
|
autologin=dict(type='bool', default=False),
|
|
autologout=dict(type='str', default='0'),
|
|
refresh=dict(type='str', default='30'),
|
|
rows_per_page=dict(type='str', default='50'),
|
|
after_login_url=dict(type='str', default=''),
|
|
user_medias=dict(type='list', default=[],
|
|
elements='dict',
|
|
options=dict(
|
|
mediatype=dict(type='str', default='Email'),
|
|
sendto=dict(type='str', required=True),
|
|
period=dict(type='str', default='1-7,00:00-24:00'),
|
|
severity=dict(type='dict',
|
|
options=dict(
|
|
not_classified=dict(type='bool', default=True),
|
|
information=dict(type='bool', default=True),
|
|
warning=dict(type='bool', default=True),
|
|
average=dict(type='bool', default=True),
|
|
high=dict(type='bool', default=True),
|
|
disaster=dict(type='bool', default=True)),
|
|
default=dict(
|
|
not_classified=True,
|
|
information=True,
|
|
warning=True,
|
|
average=True,
|
|
high=True,
|
|
disaster=True
|
|
)),
|
|
active=dict(type='bool', default=True)
|
|
)),
|
|
type=dict(type='str', default='Zabbix user', choices=['Zabbix user', 'Zabbix admin', 'Zabbix super admin']),
|
|
state=dict(type='str', default="present", choices=['present', 'absent']),
|
|
timeout=dict(type='int', default=10)
|
|
),
|
|
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']
|
|
alias = module.params['alias']
|
|
name = module.params['name']
|
|
surname = module.params['surname']
|
|
usrgrps = module.params['usrgrps']
|
|
passwd = module.params['passwd']
|
|
override_passwd = module.params['override_passwd']
|
|
lang = module.params['lang']
|
|
theme = module.params['theme']
|
|
autologin = module.params['autologin']
|
|
autologout = module.params['autologout']
|
|
refresh = module.params['refresh']
|
|
rows_per_page = module.params['rows_per_page']
|
|
after_login_url = module.params['after_login_url']
|
|
user_medias = module.params['user_medias']
|
|
user_type = module.params['type']
|
|
state = module.params['state']
|
|
timeout = module.params['timeout']
|
|
|
|
if autologin:
|
|
autologin = '1'
|
|
else:
|
|
autologin = '0'
|
|
|
|
user_type_dict = {
|
|
'Zabbix user': '1',
|
|
'Zabbix admin': '2',
|
|
'Zabbix super admin': '3'
|
|
}
|
|
user_type = user_type_dict[user_type]
|
|
|
|
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)
|
|
atexit.register(zbx.logout)
|
|
except Exception as e:
|
|
module.fail_json(msg="Failed to connect to Zabbix server: %s" % e)
|
|
|
|
user = User(module, zbx)
|
|
|
|
user_ids = {}
|
|
zbx_user = user.check_user_exist(alias)
|
|
if state == 'present':
|
|
user_group_ids = user.get_usergroupid_by_user_group_name(usrgrps)
|
|
if zbx_user:
|
|
diff_check_result, diff_params = user.user_parameter_difference_check(zbx_user, alias, name, surname,
|
|
user_group_ids, passwd, lang, theme,
|
|
autologin, autologout, refresh,
|
|
rows_per_page, after_login_url,
|
|
user_medias, user_type,
|
|
override_passwd)
|
|
|
|
if not module.check_mode and diff_check_result:
|
|
user_ids = user.update_user(zbx_user, alias, name, surname, user_group_ids, passwd, lang,
|
|
theme, autologin, autologout, refresh, rows_per_page, after_login_url,
|
|
user_medias, user_type, override_passwd)
|
|
else:
|
|
diff_check_result = True
|
|
user_ids, diff_params = user.add_user(alias, name, surname, user_group_ids, passwd, lang, theme, autologin,
|
|
autologout, refresh, rows_per_page, after_login_url, user_medias,
|
|
user_type)
|
|
|
|
if state == 'absent':
|
|
if zbx_user:
|
|
diff_check_result = True
|
|
user_ids, diff_params = user.delete_user(zbx_user, alias)
|
|
else:
|
|
diff_check_result = False
|
|
diff_params = {}
|
|
|
|
if not module.check_mode:
|
|
if user_ids:
|
|
module.exit_json(changed=True, user_ids=user_ids)
|
|
else:
|
|
module.exit_json(changed=False)
|
|
else:
|
|
if diff_check_result:
|
|
module.exit_json(changed=True, diff=diff_params)
|
|
else:
|
|
module.exit_json(changed=False, diff=diff_params)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|