blob: 49b66228a69536fc0ffe91b83b031ae1074ec907 [file] [log] [blame]
# -*- coding: utf-8 -*-
'''
Manage RabbitMQ Users
=====================
Example:
.. code-block:: yaml
rabbit_user:
rabbitmq_user.present:
- password: password
- force: True
- tags:
- monitoring
- user
- perms:
- '/':
- '.*'
- '.*'
- '.*'
- runas: rabbitmq
'''
# This file is copy of original /usr/lib/python2.7/dist-packages/salt/states/rabbitmq_user.py
# with fix applied for PROD-35125 - rabbitmq module incompatible with rabbitmq-server 3.8+
# It change module for check_password function.
# Now it uses rabbitmq_custom module instead of rabbitmq for check_password function.
# Import python libs
from __future__ import absolute_import
import logging
# Import salt libs
import salt.utils
import salt.ext.six as six
from salt.exceptions import CommandExecutionError
log = logging.getLogger(__name__)
def __virtual__():
'''
Only load if RabbitMQ is installed.
'''
return salt.utils.which('rabbitmqctl') is not None
def _check_perms_changes(name, newperms, runas=None, existing=None):
'''
Check whether Rabbitmq user's permissions need to be changed.
'''
if not newperms:
return False
if existing is None:
try:
existing = __salt__['rabbitmq.list_user_permissions'](name, runas=runas)
except CommandExecutionError as err:
log.error('Error: {0}'.format(err))
return False
perm_need_change = False
for vhost_perms in newperms:
for vhost, perms in six.iteritems(vhost_perms):
if vhost in existing:
existing_vhost = existing[vhost]
if perms != existing_vhost:
# This checks for setting permissions to nothing in the state,
# when previous state runs have already set permissions to
# nothing. We don't want to report a change in this case.
if existing_vhost == '' and perms == ['', '', '']:
continue
perm_need_change = True
else:
perm_need_change = True
return perm_need_change
def _get_current_tags(name, runas=None):
'''
Whether Rabbitmq user's tags need to be changed
'''
try:
return list(__salt__['rabbitmq.list_users'](runas=runas)[name])
except CommandExecutionError as err:
log.error('Error: {0}'.format(err))
return []
def present(name,
password=None,
force=False,
tags=None,
perms=(),
runas=None):
'''
Ensure the RabbitMQ user exists.
name
User name
password
User's password, if one needs to be set
force
If user exists, forcibly change the password
tags
Optional list of tags for the user
perms
A list of dicts with vhost keys and 3-tuple values
runas
Name of the user to run the command
'''
ret = {'name': name, 'result': False, 'comment': '', 'changes': {}}
try:
user = __salt__['rabbitmq.user_exists'](name, runas=runas)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
passwd_reqs_update = False
if user and password is not None:
try:
# Fix for PROD-35125
# Use rabbitmq_custom module instead of rabbitmq for check_password function
if not __salt__['rabbitmq_custom.check_password'](name,
password, runas=runas):
passwd_reqs_update = True
log.debug('RabbitMQ user %s password update required', name)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
if user and not any((force, perms, tags, passwd_reqs_update)):
log.debug(('RabbitMQ user \'%s\' exists, password is up to'
' date and force is not set.'), name)
ret['comment'] = 'User \'{0}\' is already present.'.format(name)
ret['result'] = True
return ret
if not user:
ret['changes'].update({'user':
{'old': '',
'new': name}})
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'User \'{0}\' is set to be created.'.format(name)
return ret
log.debug(
'RabbitMQ user \'{0}\' doesn\'t exist - Creating.'.format(name))
try:
__salt__['rabbitmq.add_user'](name, password, runas=runas)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
else:
log.debug('RabbitMQ user \'{0}\' exists'.format(name))
if force or passwd_reqs_update:
if password is not None:
if not __opts__['test']:
try:
__salt__['rabbitmq.change_password'](name, password, runas=runas)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
ret['changes'].update({'password':
{'old': '',
'new': 'Set password.'}})
else:
if not __opts__['test']:
log.debug('Password for {0} is not set - Clearing password.'.format(name))
try:
__salt__['rabbitmq.clear_password'](name, runas=runas)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
ret['changes'].update({'password':
{'old': 'Removed password.',
'new': ''}})
if tags is not None:
current_tags = _get_current_tags(name, runas=runas)
if isinstance(tags, str):
tags = tags.split()
# Diff the tags sets. Symmetric difference operator ^ will give us
# any element in one set, but not both
if set(tags) ^ set(current_tags):
if not __opts__['test']:
try:
__salt__['rabbitmq.set_user_tags'](name, tags, runas=runas)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
ret['changes'].update({'tags':
{'old': current_tags,
'new': tags}})
try:
existing_perms = __salt__['rabbitmq.list_user_permissions'](name, runas=runas)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
if _check_perms_changes(name, perms, runas=runas, existing=existing_perms):
for vhost_perm in perms:
for vhost, perm in six.iteritems(vhost_perm):
if not __opts__['test']:
try:
__salt__['rabbitmq.set_permissions'](
vhost, name, perm[0], perm[1], perm[2], runas=runas
)
except CommandExecutionError as err:
ret['comment'] = 'Error: {0}'.format(err)
return ret
new_perms = {vhost: perm}
if existing_perms != new_perms:
if ret['changes'].get('perms') is None:
ret['changes'].update({'perms':
{'old': {},
'new': {}}})
ret['changes']['perms']['old'].update(existing_perms)
ret['changes']['perms']['new'].update(new_perms)
ret['result'] = True
if ret['changes'] == {}:
ret['comment'] = '\'{0}\' is already in the desired state.'.format(name)
return ret
if __opts__['test']:
ret['result'] = None
ret['comment'] = 'Configuration for \'{0}\' will change.'.format(name)
return ret
ret['comment'] = '\'{0}\' was configured.'.format(name)
return ret