Added zabbix module zabbix_user (#56815)

This pull request adds a module to manage Zabbix users.
Tested with Zabbix Server(3.0, 4.0, 4.2).
pull/62156/head
sky-joker 5 years ago committed by Gonéri Le Bouder
parent 9d67bfa31b
commit c0ea9f021b

@ -0,0 +1,654 @@
#!/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 = '''
module: zabbix_user
short_description: Create/update/delete Zabbix users
author:
- sky-joker (@sky-joker)
version_added: '2.10'
description:
- This module allows you to create, modify and delete Zabbix users.
requirements:
- python >= 2.6
- zabbix-api
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.
type: list
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
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:
- zabbix
'''
EXAMPLES = '''
- 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 = '''
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
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 media_type['description'] == user_media['mediatype']:
user_media['mediatypeid'] = media_type['mediatypeid']
del user_media['mediatype']
break
if 'mediatypeid' not in user_media:
self._module.fail_json(msg="Media type not found: %s" % 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,
zbx_api_version, 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(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, zbx_api_version, 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(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(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_api_version = zbx.api_version()[:3]
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,
zbx_api_version, 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, zbx_api_version, 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()
Loading…
Cancel
Save