Initial commit

This commit is contained in:
Ansible Core Team 2020-03-09 09:11:07 +00:00
commit aebc1b03fd
4861 changed files with 812621 additions and 0 deletions

View file

@ -0,0 +1,297 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2015, Manuel Sousa <manuel.sousa@gmail.com>
# 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: rabbitmq_binding
author: Manuel Sousa (@manuel-sousa)
short_description: Manage rabbitMQ bindings
description:
- This module uses rabbitMQ REST APIs to create / delete bindings.
requirements: [ "requests >= 1.0.0" ]
options:
state:
description:
- Whether the bindings should be present or absent.
choices: [ "present", "absent" ]
default: present
name:
description:
- source exchange to create binding on.
required: true
aliases: [ "src", "source" ]
destination:
description:
- destination exchange or queue for the binding.
required: true
aliases: [ "dst", "dest" ]
destination_type:
description:
- Either queue or exchange.
required: true
choices: [ "queue", "exchange" ]
aliases: [ "type", "dest_type" ]
routing_key:
description:
- routing key for the binding.
default: "#"
arguments:
description:
- extra arguments for exchange. If defined this argument is a key/value dictionary
required: false
default: {}
extends_documentation_fragment:
- community.general.rabbitmq
'''
EXAMPLES = '''
# Bind myQueue to directExchange with routing key info
- rabbitmq_binding:
name: directExchange
destination: myQueue
type: queue
routing_key: info
# Bind directExchange to topicExchange with routing key *.info
- rabbitmq_binding:
name: topicExchange
destination: topicExchange
type: exchange
routing_key: '*.info'
'''
import json
import traceback
REQUESTS_IMP_ERR = None
try:
import requests
HAS_REQUESTS = True
except ImportError:
REQUESTS_IMP_ERR = traceback.format_exc()
HAS_REQUESTS = False
from ansible.module_utils.six.moves.urllib import parse as urllib_parse
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.general.plugins.module_utils.rabbitmq import rabbitmq_argument_spec
class RabbitMqBinding(object):
def __init__(self, module):
"""
:param module:
"""
self.module = module
self.name = self.module.params['name']
self.login_user = self.module.params['login_user']
self.login_password = self.module.params['login_password']
self.login_host = self.module.params['login_host']
self.login_port = self.module.params['login_port']
self.login_protocol = self.module.params['login_protocol']
self.vhost = self.module.params['vhost']
self.destination = self.module.params['destination']
self.destination_type = 'q' if self.module.params['destination_type'] == 'queue' else 'e'
self.routing_key = self.module.params['routing_key']
self.arguments = self.module.params['arguments']
self.verify = self.module.params['ca_cert']
self.cert = self.module.params['client_cert']
self.key = self.module.params['client_key']
self.props = urllib_parse.quote(self.routing_key) if self.routing_key != '' else '~'
self.base_url = '{0}://{1}:{2}/api/bindings'.format(self.login_protocol,
self.login_host,
self.login_port)
self.url = '{0}/{1}/e/{2}/{3}/{4}/{5}'.format(self.base_url,
urllib_parse.quote(self.vhost, safe=''),
urllib_parse.quote(self.name, safe=''),
self.destination_type,
urllib_parse.quote(self.destination, safe=''),
self.props)
self.result = {
'changed': False,
'name': self.module.params['name'],
}
self.authentication = (
self.login_user,
self.login_password
)
self.request = requests
self.http_check_states = {
200: True,
404: False,
}
self.http_actionable_states = {
201: True,
204: True,
}
self.api_result = self.request.get(self.url, auth=self.authentication, verify=self.verify, cert=(self.cert, self.key))
def run(self):
"""
:return:
"""
self.check_presence()
self.check_mode()
self.action_mode()
def check_presence(self):
"""
:return:
"""
if self.check_should_throw_fail():
self.fail()
def change_required(self):
"""
:return:
"""
if self.module.params['state'] == 'present':
if not self.is_present():
return True
elif self.module.params['state'] == 'absent':
if self.is_present():
return True
return False
def is_present(self):
"""
:return:
"""
return self.http_check_states.get(self.api_result.status_code, False)
def check_mode(self):
"""
:return:
"""
if self.module.check_mode:
result = self.result
result['changed'] = self.change_required()
result['details'] = self.api_result.json() if self.is_present() else self.api_result.text
result['arguments'] = self.module.params['arguments']
self.module.exit_json(**result)
def check_reply_is_correct(self):
"""
:return:
"""
if self.api_result.status_code in self.http_check_states:
return True
return False
def check_should_throw_fail(self):
"""
:return:
"""
if not self.is_present():
if not self.check_reply_is_correct():
return True
return False
def action_mode(self):
"""
:return:
"""
result = self.result
if self.change_required():
if self.module.params['state'] == 'present':
self.create()
if self.module.params['state'] == 'absent':
self.remove()
if self.action_should_throw_fail():
self.fail()
result['changed'] = True
result['destination'] = self.module.params['destination']
self.module.exit_json(**result)
else:
result['changed'] = False
self.module.exit_json(**result)
def action_reply_is_correct(self):
"""
:return:
"""
if self.api_result.status_code in self.http_actionable_states:
return True
return False
def action_should_throw_fail(self):
"""
:return:
"""
if not self.action_reply_is_correct():
return True
return False
def create(self):
"""
:return:
"""
self.url = '{0}/{1}/e/{2}/{3}/{4}'.format(self.base_url,
urllib_parse.quote(self.vhost, safe=''),
urllib_parse.quote(self.name, safe=''),
self.destination_type,
urllib_parse.quote(self.destination, safe=''))
self.api_result = self.request.post(self.url,
auth=self.authentication,
verify=self.verify,
cert=(self.cert, self.key),
headers={"content-type": "application/json"},
data=json.dumps({
'routing_key': self.routing_key,
'arguments': self.arguments
}))
def remove(self):
"""
:return:
"""
self.api_result = self.request.delete(self.url, auth=self.authentication, verify=self.verify, cert=(self.cert, self.key))
def fail(self):
"""
:return:
"""
self.module.fail_json(
msg="Unexpected reply from API",
status=self.api_result.status_code,
details=self.api_result.text
)
def main():
argument_spec = rabbitmq_argument_spec()
argument_spec.update(
dict(
state=dict(default='present', choices=['present', 'absent'], type='str'),
name=dict(required=True, aliases=["src", "source"], type='str'),
destination=dict(required=True, aliases=["dst", "dest"], type='str'),
destination_type=dict(required=True, aliases=["type", "dest_type"], choices=["queue", "exchange"],
type='str'),
routing_key=dict(default='#', type='str'),
arguments=dict(default=dict(), type='dict')
)
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
if not HAS_REQUESTS:
module.fail_json(msg=missing_required_lib("requests"), exception=REQUESTS_IMP_ERR)
RabbitMqBinding(module).run()
if __name__ == '__main__':
main()

View file

@ -0,0 +1,208 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2015, Manuel Sousa <manuel.sousa@gmail.com>
# 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: rabbitmq_exchange
author: Manuel Sousa (@manuel-sousa)
short_description: Manage rabbitMQ exchanges
description:
- This module uses rabbitMQ Rest API to create/delete exchanges
requirements: [ "requests >= 1.0.0" ]
options:
name:
description:
- Name of the exchange to create
required: true
state:
description:
- Whether the exchange should be present or absent
choices: [ "present", "absent" ]
required: false
default: present
durable:
description:
- whether exchange is durable or not
required: false
type: bool
default: yes
exchange_type:
description:
- type for the exchange
required: false
choices: [ "fanout", "direct", "headers", "topic" ]
aliases: [ "type" ]
default: direct
auto_delete:
description:
- if the exchange should delete itself after all queues/exchanges unbound from it
required: false
type: bool
default: no
internal:
description:
- exchange is available only for other exchanges
required: false
type: bool
default: no
arguments:
description:
- extra arguments for exchange. If defined this argument is a key/value dictionary
required: false
default: {}
extends_documentation_fragment:
- community.general.rabbitmq
'''
EXAMPLES = '''
# Create direct exchange
- rabbitmq_exchange:
name: directExchange
# Create topic exchange on vhost
- rabbitmq_exchange:
name: topicExchange
type: topic
vhost: myVhost
'''
import json
import traceback
REQUESTS_IMP_ERR = None
try:
import requests
HAS_REQUESTS = True
except ImportError:
REQUESTS_IMP_ERR = traceback.format_exc()
HAS_REQUESTS = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six.moves.urllib import parse as urllib_parse
from ansible_collections.community.general.plugins.module_utils.rabbitmq import rabbitmq_argument_spec
def main():
argument_spec = rabbitmq_argument_spec()
argument_spec.update(
dict(
state=dict(default='present', choices=['present', 'absent'], type='str'),
name=dict(required=True, type='str'),
durable=dict(default=True, type='bool'),
auto_delete=dict(default=False, type='bool'),
internal=dict(default=False, type='bool'),
exchange_type=dict(default='direct', aliases=['type'], type='str'),
arguments=dict(default=dict(), type='dict')
)
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
url = "%s://%s:%s/api/exchanges/%s/%s" % (
module.params['login_protocol'],
module.params['login_host'],
module.params['login_port'],
urllib_parse.quote(module.params['vhost'], ''),
urllib_parse.quote(module.params['name'], '')
)
if not HAS_REQUESTS:
module.fail_json(msg=missing_required_lib("requests"), exception=REQUESTS_IMP_ERR)
result = dict(changed=False, name=module.params['name'])
# Check if exchange already exists
r = requests.get(url, auth=(module.params['login_user'], module.params['login_password']),
verify=module.params['ca_cert'], cert=(module.params['client_cert'], module.params['client_key']))
if r.status_code == 200:
exchange_exists = True
response = r.json()
elif r.status_code == 404:
exchange_exists = False
response = r.text
else:
module.fail_json(
msg="Invalid response from RESTAPI when trying to check if exchange exists",
details=r.text
)
if module.params['state'] == 'present':
change_required = not exchange_exists
else:
change_required = exchange_exists
# Check if attributes change on existing exchange
if not change_required and r.status_code == 200 and module.params['state'] == 'present':
if not (
response['durable'] == module.params['durable'] and
response['auto_delete'] == module.params['auto_delete'] and
response['internal'] == module.params['internal'] and
response['type'] == module.params['exchange_type']
):
module.fail_json(
msg="RabbitMQ RESTAPI doesn't support attribute changes for existing exchanges"
)
# Exit if check_mode
if module.check_mode:
result['changed'] = change_required
result['details'] = response
result['arguments'] = module.params['arguments']
module.exit_json(**result)
# Do changes
if change_required:
if module.params['state'] == 'present':
r = requests.put(
url,
auth=(module.params['login_user'], module.params['login_password']),
headers={"content-type": "application/json"},
data=json.dumps({
"durable": module.params['durable'],
"auto_delete": module.params['auto_delete'],
"internal": module.params['internal'],
"type": module.params['exchange_type'],
"arguments": module.params['arguments']
}),
verify=module.params['ca_cert'],
cert=(module.params['client_cert'], module.params['client_key'])
)
elif module.params['state'] == 'absent':
r = requests.delete(url, auth=(module.params['login_user'], module.params['login_password']),
verify=module.params['ca_cert'], cert=(module.params['client_cert'], module.params['client_key']))
# RabbitMQ 3.6.7 changed this response code from 204 to 201
if r.status_code == 204 or r.status_code == 201:
result['changed'] = True
module.exit_json(**result)
else:
module.fail_json(
msg="Error creating exchange",
status=r.status_code,
details=r.text
)
else:
module.exit_json(
changed=False,
name=module.params['name']
)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,156 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2013, Chatham Financial <oss@chathamfinancial.com>
# Copyright: (c) 2017, Juergen Kirschbaum <jk@jk-itc.de>
# 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: rabbitmq_global_parameter
short_description: Manage RabbitMQ global parameters
description:
- Manage dynamic, cluster-wide global parameters for RabbitMQ
author: "Juergen Kirschbaum (@jgkirschbaum)"
options:
name:
description:
- Name of the global parameter being set
required: true
default: null
value:
description:
- Value of the global parameter, as a JSON term
required: false
default: null
node:
description:
- erlang node name of the rabbit we wish to configure
required: false
default: rabbit
state:
description:
- Specify if user is to be added or removed
required: false
default: present
choices: [ 'present', 'absent']
'''
EXAMPLES = '''
# Set the global parameter 'cluster_name' to a value of 'mq-cluster' (in quotes)
- rabbitmq_global_parameter:
name: cluster_name
value: "{{ 'mq-cluster' | to_json }}"
state: present
'''
RETURN = '''
name:
description: name of the global parameter being set
returned: success
type: str
sample: "cluster_name"
value:
description: value of the global parameter, as a JSON term
returned: changed
type: str
sample: "the-cluster-name"
'''
import json
from ansible.module_utils.basic import AnsibleModule
class RabbitMqGlobalParameter(object):
def __init__(self, module, name, value, node):
self.module = module
self.name = name
self.value = value
self.node = node
self._value = None
self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
def _exec(self, args, run_in_check_mode=False):
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
cmd = [self._rabbitmqctl, '-q', '-n', self.node]
rc, out, err = self.module.run_command(cmd + args, check_rc=True)
return out.splitlines()
return list()
def get(self):
global_parameters = self._exec(['list_global_parameters'], True)
for param_item in global_parameters:
name, value = param_item.split('\t')
if name == self.name:
self._value = json.loads(value)
return True
return False
def set(self):
self._exec(['set_global_parameter',
self.name,
json.dumps(self.value)])
def delete(self):
self._exec(['clear_global_parameter', self.name])
def has_modifications(self):
return self.value != self._value
def main():
arg_spec = dict(
name=dict(type='str', required=True),
value=dict(type='str', default=None),
state=dict(default='present', choices=['present', 'absent']),
node=dict(type='str', default='rabbit')
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
name = module.params['name']
value = module.params['value']
if isinstance(value, str):
value = json.loads(value)
state = module.params['state']
node = module.params['node']
result = dict(changed=False)
rabbitmq_global_parameter = RabbitMqGlobalParameter(module, name, value, node)
if rabbitmq_global_parameter.get():
if state == 'absent':
rabbitmq_global_parameter.delete()
result['changed'] = True
else:
if rabbitmq_global_parameter.has_modifications():
rabbitmq_global_parameter.set()
result['changed'] = True
elif state == 'present':
rabbitmq_global_parameter.set()
result['changed'] = True
result['name'] = name
result['value'] = value
result['state'] = state
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,154 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2013, Chatham Financial <oss@chathamfinancial.com>
# 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: rabbitmq_parameter
short_description: Manage RabbitMQ parameters
description:
- Manage dynamic, cluster-wide parameters for RabbitMQ
author: Chris Hoffman (@chrishoffman)
options:
component:
description:
- Name of the component of which the parameter is being set
required: true
name:
description:
- Name of the parameter being set
required: true
value:
description:
- Value of the parameter, as a JSON term
vhost:
description:
- vhost to apply access privileges.
default: /
node:
description:
- erlang node name of the rabbit we wish to configure
default: rabbit
state:
description:
- Specify if user is to be added or removed
default: present
choices: [ 'present', 'absent']
'''
EXAMPLES = """
# Set the federation parameter 'local_username' to a value of 'guest' (in quotes)
- rabbitmq_parameter:
component: federation
name: local-username
value: '"guest"'
state: present
"""
import json
from ansible.module_utils.basic import AnsibleModule
class RabbitMqParameter(object):
def __init__(self, module, component, name, value, vhost, node):
self.module = module
self.component = component
self.name = name
self.value = value
self.vhost = vhost
self.node = node
self._value = None
self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
def _exec(self, args, run_in_check_mode=False):
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
cmd = [self._rabbitmqctl, '-q', '-n', self.node]
rc, out, err = self.module.run_command(cmd + args, check_rc=True)
return out.strip().splitlines()
return list()
def get(self):
parameters = [param for param in self._exec(['list_parameters', '-p', self.vhost], True) if param.strip()]
for param_item in parameters:
component, name, value = param_item.split('\t')
if component == self.component and name == self.name:
self._value = json.loads(value)
return True
return False
def set(self):
self._exec(['set_parameter',
'-p',
self.vhost,
self.component,
self.name,
json.dumps(self.value)])
def delete(self):
self._exec(['clear_parameter', '-p', self.vhost, self.component, self.name])
def has_modifications(self):
return self.value != self._value
def main():
arg_spec = dict(
component=dict(required=True),
name=dict(required=True),
value=dict(default=None),
vhost=dict(default='/'),
state=dict(default='present', choices=['present', 'absent']),
node=dict(default='rabbit')
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
component = module.params['component']
name = module.params['name']
value = module.params['value']
if isinstance(value, str):
value = json.loads(value)
vhost = module.params['vhost']
state = module.params['state']
node = module.params['node']
result = dict(changed=False)
rabbitmq_parameter = RabbitMqParameter(module, component, name, value, vhost, node)
if rabbitmq_parameter.get():
if state == 'absent':
rabbitmq_parameter.delete()
result['changed'] = True
else:
if rabbitmq_parameter.has_modifications():
rabbitmq_parameter.set()
result['changed'] = True
elif state == 'present':
rabbitmq_parameter.set()
result['changed'] = True
result['component'] = component
result['name'] = name
result['vhost'] = vhost
result['state'] = state
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,178 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2013, Chatham Financial <oss@chathamfinancial.com>
# 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: rabbitmq_plugin
short_description: Manage RabbitMQ plugins
description:
- This module can be used to enable or disable RabbitMQ plugins.
author:
- Chris Hoffman (@chrishoffman)
options:
names:
description:
- Comma-separated list of plugin names. Also, accepts plugin name.
required: true
aliases: [name]
new_only:
description:
- Only enable missing plugins.
- Does not disable plugins that are not in the names list.
type: bool
default: "no"
state:
description:
- Specify if plugins are to be enabled or disabled.
default: enabled
choices: [enabled, disabled]
prefix:
description:
- Specify a custom install prefix to a Rabbit.
'''
EXAMPLES = '''
- name: Enables the rabbitmq_management plugin
rabbitmq_plugin:
names: rabbitmq_management
state: enabled
- name: Enable multiple rabbitmq plugins
rabbitmq_plugin:
names: rabbitmq_management,rabbitmq_management_visualiser
state: enabled
- name: Disable plugin
rabbitmq_plugin:
names: rabbitmq_management
state: disabled
- name: Enable every plugin in list with existing plugins
rabbitmq_plugin:
names: rabbitmq_management,rabbitmq_management_visualiser,rabbitmq_shovel,rabbitmq_shovel_management
state: enabled
new_only: 'yes'
'''
RETURN = '''
enabled:
description: list of plugins enabled during task run
returned: always
type: list
sample: ["rabbitmq_management"]
disabled:
description: list of plugins disabled during task run
returned: always
type: list
sample: ["rabbitmq_management"]
'''
import os
from ansible.module_utils.basic import AnsibleModule
class RabbitMqPlugins(object):
def __init__(self, module):
self.module = module
bin_path = ''
if module.params['prefix']:
if os.path.isdir(os.path.join(module.params['prefix'], 'bin')):
bin_path = os.path.join(module.params['prefix'], 'bin')
elif os.path.isdir(os.path.join(module.params['prefix'], 'sbin')):
bin_path = os.path.join(module.params['prefix'], 'sbin')
else:
# No such path exists.
module.fail_json(msg="No binary folder in prefix %s" % module.params['prefix'])
self._rabbitmq_plugins = os.path.join(bin_path, "rabbitmq-plugins")
else:
self._rabbitmq_plugins = module.get_bin_path('rabbitmq-plugins', True)
def _exec(self, args, run_in_check_mode=False):
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
cmd = [self._rabbitmq_plugins]
rc, out, err = self.module.run_command(cmd + args, check_rc=True)
return out.splitlines()
return list()
def get_all(self):
list_output = self._exec(['list', '-E', '-m'], True)
plugins = []
for plugin in list_output:
if not plugin:
break
plugins.append(plugin)
return plugins
def enable(self, name):
self._exec(['enable', name])
def disable(self, name):
self._exec(['disable', name])
def main():
arg_spec = dict(
names=dict(required=True, aliases=['name']),
new_only=dict(default='no', type='bool'),
state=dict(default='enabled', choices=['enabled', 'disabled']),
prefix=dict(required=False, default=None)
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
result = dict()
names = module.params['names'].split(',')
new_only = module.params['new_only']
state = module.params['state']
rabbitmq_plugins = RabbitMqPlugins(module)
enabled_plugins = rabbitmq_plugins.get_all()
enabled = []
disabled = []
if state == 'enabled':
if not new_only:
for plugin in enabled_plugins:
if " " in plugin:
continue
if plugin not in names:
rabbitmq_plugins.disable(plugin)
disabled.append(plugin)
for name in names:
if name not in enabled_plugins:
rabbitmq_plugins.enable(name)
enabled.append(name)
else:
for plugin in enabled_plugins:
if plugin in names:
rabbitmq_plugins.disable(plugin)
disabled.append(plugin)
result['changed'] = len(enabled) > 0 or len(disabled) > 0
result['enabled'] = enabled
result['disabled'] = disabled
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,245 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2013, John Dewey <john@dewey.ws>
# 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: rabbitmq_policy
short_description: Manage the state of policies in RabbitMQ
description:
- Manage the state of a policy in RabbitMQ.
author: John Dewey (@retr0h)
options:
name:
description:
- The name of the policy to manage.
required: true
vhost:
description:
- The name of the vhost to apply to.
default: /
apply_to:
description:
- What the policy applies to. Requires RabbitMQ 3.2.0 or later.
default: all
choices: [all, exchanges, queues]
pattern:
description:
- A regex of queues to apply the policy to. Required when
C(state=present). This option is no longer required as of Ansible 2.9.
required: false
default: null
tags:
description:
- A dict or string describing the policy. Required when
C(state=present). This option is no longer required as of Ansible 2.9.
required: false
default: null
priority:
description:
- The priority of the policy.
default: 0
node:
description:
- Erlang node name of the rabbit we wish to configure.
default: rabbit
state:
description:
- The state of the policy.
default: present
choices: [present, absent]
'''
EXAMPLES = '''
- name: ensure the default vhost contains the HA policy via a dict
rabbitmq_policy:
name: HA
pattern: .*
args:
tags:
ha-mode: all
- name: ensure the default vhost contains the HA policy
rabbitmq_policy:
name: HA
pattern: .*
tags:
ha-mode: all
'''
import json
import re
from distutils.version import LooseVersion as Version
from ansible.module_utils.basic import AnsibleModule
class RabbitMqPolicy(object):
def __init__(self, module, name):
self._module = module
self._name = name
self._vhost = module.params['vhost']
self._pattern = module.params['pattern']
self._apply_to = module.params['apply_to']
self._tags = module.params['tags']
self._priority = module.params['priority']
self._node = module.params['node']
self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
self._version = self._rabbit_version()
def _exec(self,
args,
run_in_check_mode=False,
split_lines=True,
add_vhost=True):
if (not self._module.check_mode
or (self._module.check_mode and run_in_check_mode)):
cmd = [self._rabbitmqctl, '-q', '-n', self._node]
if add_vhost:
args.insert(1, '-p')
args.insert(2, self._vhost)
rc, out, err = self._module.run_command(cmd + args, check_rc=True)
if split_lines:
return out.splitlines()
return out
return list()
def _rabbit_version(self):
status = self._exec(['status'], True, False, False)
# 3.7.x erlang style output
version_match = re.search('{rabbit,".*","(?P<version>.*)"}', status)
if version_match:
return Version(version_match.group('version'))
# 3.8.x style ouput
version_match = re.search('RabbitMQ version: (?P<version>.*)', status)
if version_match:
return Version(version_match.group('version'))
return None
def _list_policies(self):
if self._version and self._version >= Version('3.7.9'):
# Remove first header line from policies list for version > 3.7.9
return self._exec(['list_policies'], True)[1:]
return self._exec(['list_policies'], True)
def has_modifications(self):
if self._pattern is None or self._tags is None:
self._module.fail_json(
msg=('pattern and tags are required for '
'state=present'))
if self._version and self._version >= Version('3.7.0'):
# Change fields order in rabbitmqctl output in version 3.7
return not any(
self._policy_check(policy, apply_to_fno=3, pattern_fno=2)
for policy in self._list_policies())
else:
return not any(
self._policy_check(policy) for policy in self._list_policies())
def should_be_deleted(self):
return any(
self._policy_check_by_name(policy)
for policy in self._list_policies())
def set(self):
args = ['set_policy']
args.append(self._name)
args.append(self._pattern)
args.append(json.dumps(self._tags))
args.append('--priority')
args.append(self._priority)
if self._apply_to != 'all':
args.append('--apply-to')
args.append(self._apply_to)
return self._exec(args)
def clear(self):
return self._exec(['clear_policy', self._name])
def _policy_check(self,
policy,
name_fno=1,
apply_to_fno=2,
pattern_fno=3,
tags_fno=4,
priority_fno=5):
if not policy:
return False
policy_data = policy.split('\t')
policy_name = policy_data[name_fno]
apply_to = policy_data[apply_to_fno]
pattern = policy_data[pattern_fno].replace('\\\\', '\\')
tags = json.loads(policy_data[tags_fno])
priority = policy_data[priority_fno]
return (policy_name == self._name and apply_to == self._apply_to
and tags == self._tags and priority == self._priority
and pattern == self._pattern)
def _policy_check_by_name(self, policy):
if not policy:
return False
policy_name = policy.split('\t')[1]
return policy_name == self._name
def main():
arg_spec = dict(
name=dict(required=True),
vhost=dict(default='/'),
pattern=dict(required=False, default=None),
apply_to=dict(default='all', choices=['all', 'exchanges', 'queues']),
tags=dict(type='dict', required=False, default=None),
priority=dict(default='0'),
node=dict(default='rabbit'),
state=dict(default='present', choices=['present', 'absent']),
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
name = module.params['name']
state = module.params['state']
rabbitmq_policy = RabbitMqPolicy(module, name)
result = dict(changed=False, name=name, state=state)
if state == 'present' and rabbitmq_policy.has_modifications():
rabbitmq_policy.set()
result['changed'] = True
elif state == 'absent' and rabbitmq_policy.should_be_deleted():
rabbitmq_policy.clear()
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,256 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2015, Manuel Sousa <manuel.sousa@gmail.com>
# 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: rabbitmq_queue
author: Manuel Sousa (@manuel-sousa)
short_description: Manage rabbitMQ queues
description:
- This module uses rabbitMQ Rest API to create/delete queues
requirements: [ "requests >= 1.0.0" ]
options:
name:
description:
- Name of the queue
required: true
state:
description:
- Whether the queue should be present or absent
choices: [ "present", "absent" ]
default: present
durable:
description:
- whether queue is durable or not
type: bool
default: 'yes'
auto_delete:
description:
- if the queue should delete itself after all queues/queues unbound from it
type: bool
default: 'no'
message_ttl:
description:
- How long a message can live in queue before it is discarded (milliseconds)
default: forever
auto_expires:
description:
- How long a queue can be unused before it is automatically deleted (milliseconds)
default: forever
max_length:
description:
- How many messages can the queue contain before it starts rejecting
default: no limit
dead_letter_exchange:
description:
- Optional name of an exchange to which messages will be republished if they
- are rejected or expire
dead_letter_routing_key:
description:
- Optional replacement routing key to use when a message is dead-lettered.
- Original routing key will be used if unset
max_priority:
description:
- Maximum number of priority levels for the queue to support.
- If not set, the queue will not support message priorities.
- Larger numbers indicate higher priority.
arguments:
description:
- extra arguments for queue. If defined this argument is a key/value dictionary
default: {}
extends_documentation_fragment:
- community.general.rabbitmq
'''
EXAMPLES = '''
# Create a queue
- rabbitmq_queue:
name: myQueue
# Create a queue on remote host
- rabbitmq_queue:
name: myRemoteQueue
login_user: user
login_password: secret
login_host: remote.example.org
'''
import json
import traceback
REQUESTS_IMP_ERR = None
try:
import requests
HAS_REQUESTS = True
except ImportError:
REQUESTS_IMP_ERR = traceback.format_exc()
HAS_REQUESTS = False
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible.module_utils.six.moves.urllib import parse as urllib_parse
from ansible_collections.community.general.plugins.module_utils.rabbitmq import rabbitmq_argument_spec
def main():
argument_spec = rabbitmq_argument_spec()
argument_spec.update(
dict(
state=dict(default='present', choices=['present', 'absent'], type='str'),
name=dict(required=True, type='str'),
durable=dict(default=True, type='bool'),
auto_delete=dict(default=False, type='bool'),
message_ttl=dict(default=None, type='int'),
auto_expires=dict(default=None, type='int'),
max_length=dict(default=None, type='int'),
dead_letter_exchange=dict(default=None, type='str'),
dead_letter_routing_key=dict(default=None, type='str'),
arguments=dict(default=dict(), type='dict'),
max_priority=dict(default=None, type='int')
)
)
module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True)
url = "%s://%s:%s/api/queues/%s/%s" % (
module.params['login_protocol'],
module.params['login_host'],
module.params['login_port'],
urllib_parse.quote(module.params['vhost'], ''),
module.params['name']
)
if not HAS_REQUESTS:
module.fail_json(msg=missing_required_lib("requests"), exception=REQUESTS_IMP_ERR)
result = dict(changed=False, name=module.params['name'])
# Check if queue already exists
r = requests.get(url, auth=(module.params['login_user'], module.params['login_password']),
verify=module.params['ca_cert'], cert=(module.params['client_cert'], module.params['client_key']))
if r.status_code == 200:
queue_exists = True
response = r.json()
elif r.status_code == 404:
queue_exists = False
response = r.text
else:
module.fail_json(
msg="Invalid response from RESTAPI when trying to check if queue exists",
details=r.text
)
if module.params['state'] == 'present':
change_required = not queue_exists
else:
change_required = queue_exists
# Check if attributes change on existing queue
if not change_required and r.status_code == 200 and module.params['state'] == 'present':
if not (
response['durable'] == module.params['durable'] and
response['auto_delete'] == module.params['auto_delete'] and
(
('x-message-ttl' in response['arguments'] and response['arguments']['x-message-ttl'] == module.params['message_ttl']) or
('x-message-ttl' not in response['arguments'] and module.params['message_ttl'] is None)
) and
(
('x-expires' in response['arguments'] and response['arguments']['x-expires'] == module.params['auto_expires']) or
('x-expires' not in response['arguments'] and module.params['auto_expires'] is None)
) and
(
('x-max-length' in response['arguments'] and response['arguments']['x-max-length'] == module.params['max_length']) or
('x-max-length' not in response['arguments'] and module.params['max_length'] is None)
) and
(
('x-dead-letter-exchange' in response['arguments'] and
response['arguments']['x-dead-letter-exchange'] == module.params['dead_letter_exchange']) or
('x-dead-letter-exchange' not in response['arguments'] and module.params['dead_letter_exchange'] is None)
) and
(
('x-dead-letter-routing-key' in response['arguments'] and
response['arguments']['x-dead-letter-routing-key'] == module.params['dead_letter_routing_key']) or
('x-dead-letter-routing-key' not in response['arguments'] and module.params['dead_letter_routing_key'] is None)
) and
(
('x-max-priority' in response['arguments'] and
response['arguments']['x-max-priority'] == module.params['max_priority']) or
('x-max-priority' not in response['arguments'] and module.params['max_priority'] is None)
)
):
module.fail_json(
msg="RabbitMQ RESTAPI doesn't support attribute changes for existing queues",
)
# Copy parameters to arguments as used by RabbitMQ
for k, v in {
'message_ttl': 'x-message-ttl',
'auto_expires': 'x-expires',
'max_length': 'x-max-length',
'dead_letter_exchange': 'x-dead-letter-exchange',
'dead_letter_routing_key': 'x-dead-letter-routing-key',
'max_priority': 'x-max-priority'
}.items():
if module.params[k] is not None:
module.params['arguments'][v] = module.params[k]
# Exit if check_mode
if module.check_mode:
result['changed'] = change_required
result['details'] = response
result['arguments'] = module.params['arguments']
module.exit_json(**result)
# Do changes
if change_required:
if module.params['state'] == 'present':
r = requests.put(
url,
auth=(module.params['login_user'], module.params['login_password']),
headers={"content-type": "application/json"},
data=json.dumps({
"durable": module.params['durable'],
"auto_delete": module.params['auto_delete'],
"arguments": module.params['arguments']
}),
verify=module.params['ca_cert'],
cert=(module.params['client_cert'], module.params['client_key'])
)
elif module.params['state'] == 'absent':
r = requests.delete(url, auth=(module.params['login_user'], module.params['login_password']),
verify=module.params['ca_cert'], cert=(module.params['client_cert'], module.params['client_key']))
# RabbitMQ 3.6.7 changed this response code from 204 to 201
if r.status_code == 204 or r.status_code == 201:
result['changed'] = True
module.exit_json(**result)
else:
module.fail_json(
msg="Error creating queue",
status=r.status_code,
details=r.text
)
else:
module.exit_json(
changed=False,
name=module.params['name']
)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,321 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2013, Chatham Financial <oss@chathamfinancial.com>
# 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: rabbitmq_user
short_description: Manage RabbitMQ users
description:
- Add or remove users to RabbitMQ and assign permissions
author: Chris Hoffman (@chrishoffman)
options:
user:
description:
- Name of user to add
required: true
aliases: [username, name]
password:
description:
- Password of user to add.
- To change the password of an existing user, you must also specify
C(update_password=always).
tags:
description:
- User tags specified as comma delimited
permissions:
description:
- a list of dicts, each dict contains vhost, configure_priv, write_priv, and read_priv,
and represents a permission rule for that vhost.
- This option should be preferable when you care about all permissions of the user.
- You should use vhost, configure_priv, write_priv, and read_priv options instead
if you care about permissions for just some vhosts.
default: []
vhost:
description:
- vhost to apply access privileges.
- This option will be ignored when permissions option is used.
default: /
node:
description:
- erlang node name of the rabbit we wish to configure
default: rabbit
configure_priv:
description:
- Regular expression to restrict configure actions on a resource
for the specified vhost.
- By default all actions are restricted.
- This option will be ignored when permissions option is used.
default: ^$
write_priv:
description:
- Regular expression to restrict configure actions on a resource
for the specified vhost.
- By default all actions are restricted.
- This option will be ignored when permissions option is used.
default: ^$
read_priv:
description:
- Regular expression to restrict configure actions on a resource
for the specified vhost.
- By default all actions are restricted.
- This option will be ignored when permissions option is used.
default: ^$
force:
description:
- Deletes and recreates the user.
type: bool
default: 'no'
state:
description:
- Specify if user is to be added or removed
default: present
choices: [present, absent]
update_password:
description:
- C(on_create) will only set the password for newly created users. C(always) will update passwords if they differ.
required: false
default: on_create
choices: [ on_create, always ]
'''
EXAMPLES = '''
# Add user to server and assign full access control on / vhost.
# The user might have permission rules for other vhost but you don't care.
- rabbitmq_user:
user: joe
password: changeme
vhost: /
configure_priv: .*
read_priv: .*
write_priv: .*
state: present
# Add user to server and assign full access control on / vhost.
# The user doesn't have permission rules for other vhosts
- rabbitmq_user:
user: joe
password: changeme
permissions:
- vhost: /
configure_priv: .*
read_priv: .*
write_priv: .*
state: present
'''
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.common.collections import count
class RabbitMqUser(object):
def __init__(self, module, username, password, tags, permissions,
node, bulk_permissions=False):
self.module = module
self.username = username
self.password = password
self.node = node
if not tags:
self.tags = list()
else:
self.tags = tags.split(',')
self.permissions = permissions
self.bulk_permissions = bulk_permissions
self._tags = None
self._permissions = []
self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
def _exec(self, args, run_in_check_mode=False, check_rc=True):
if not self.module.check_mode or run_in_check_mode:
cmd = [self._rabbitmqctl, '-q']
if self.node:
cmd.extend(['-n', self.node])
rc, out, err = self.module.run_command(cmd + args, check_rc=check_rc)
return out.splitlines()
return list()
def get(self):
users = self._exec(['list_users'], True)
for user_tag in users:
if '\t' not in user_tag:
continue
user, tags = user_tag.split('\t')
if user == self.username:
for c in ['[', ']', ' ']:
tags = tags.replace(c, '')
if tags != '':
self._tags = tags.split(',')
else:
self._tags = list()
self._permissions = self._get_permissions()
return True
return False
def _get_permissions(self):
"""Get permissions of the user from RabbitMQ."""
perms_out = [perm for perm in self._exec(['list_user_permissions', self.username], True) if perm.strip()]
perms_list = list()
for perm in perms_out:
vhost, configure_priv, write_priv, read_priv = perm.split('\t')
if not self.bulk_permissions:
if vhost == self.permissions[0]['vhost']:
perms_list.append(dict(vhost=vhost, configure_priv=configure_priv,
write_priv=write_priv, read_priv=read_priv))
break
else:
perms_list.append(dict(vhost=vhost, configure_priv=configure_priv,
write_priv=write_priv, read_priv=read_priv))
return perms_list
def check_password(self):
return self._exec(['authenticate_user', self.username, self.password],
run_in_check_mode=True, check_rc=False)
def add(self):
if self.password is not None:
self._exec(['add_user', self.username, self.password])
else:
self._exec(['add_user', self.username, ''])
self._exec(['clear_password', self.username])
def delete(self):
self._exec(['delete_user', self.username])
def change_password(self):
if self.password is not None:
self._exec(['change_password', self.username, self.password])
else:
self._exec(['clear_password', self.username])
def set_tags(self):
self._exec(['set_user_tags', self.username] + self.tags)
def set_permissions(self):
permissions_to_clear = [permission for permission in self._permissions if permission not in self.permissions]
permissions_to_add = [permission for permission in self.permissions if permission not in self._permissions]
for permission in permissions_to_clear:
cmd = 'clear_permissions -p {vhost} {username}'.format(username=self.username,
vhost=permission['vhost'])
self._exec(cmd.split(' '))
for permission in permissions_to_add:
cmd = ('set_permissions -p {vhost} {username} {configure_priv} {write_priv} {read_priv}'
.format(username=self.username, **permission))
self._exec(cmd.split(' '))
def has_tags_modifications(self):
return set(self.tags) != set(self._tags)
def has_permissions_modifications(self):
def to_permission_tuple(vhost_permission_dict):
return vhost_permission_dict['vhost'], vhost_permission_dict
def permission_dict(vhost_permission_list):
return dict(map(to_permission_tuple, vhost_permission_list))
return permission_dict(self._permissions) != permission_dict(self.permissions)
def main():
arg_spec = dict(
user=dict(required=True, aliases=['username', 'name']),
password=dict(default=None, no_log=True),
tags=dict(default=None),
permissions=dict(default=list(), type='list'),
vhost=dict(default='/'),
configure_priv=dict(default='^$'),
write_priv=dict(default='^$'),
read_priv=dict(default='^$'),
force=dict(default='no', type='bool'),
state=dict(default='present', choices=['present', 'absent']),
node=dict(default='rabbit'),
update_password=dict(default='on_create', choices=['on_create', 'always'])
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
username = module.params['user']
password = module.params['password']
tags = module.params['tags']
permissions = module.params['permissions']
vhost = module.params['vhost']
configure_priv = module.params['configure_priv']
write_priv = module.params['write_priv']
read_priv = module.params['read_priv']
force = module.params['force']
state = module.params['state']
node = module.params['node']
update_password = module.params['update_password']
if permissions:
vhosts = map(lambda permission: permission.get('vhost', '/'), permissions)
if any(map(lambda count: count > 1, count(vhosts).values())):
module.fail_json(msg="Error parsing permissions: You can't have two permission dicts for the same vhost")
bulk_permissions = True
else:
perm = {
'vhost': vhost,
'configure_priv': configure_priv,
'write_priv': write_priv,
'read_priv': read_priv
}
permissions.append(perm)
bulk_permissions = False
rabbitmq_user = RabbitMqUser(module, username, password, tags, permissions,
node, bulk_permissions=bulk_permissions)
result = dict(changed=False, user=username, state=state)
if rabbitmq_user.get():
if state == 'absent':
rabbitmq_user.delete()
result['changed'] = True
else:
if force:
rabbitmq_user.delete()
rabbitmq_user.add()
rabbitmq_user.get()
result['changed'] = True
elif update_password == 'always':
if not rabbitmq_user.check_password():
rabbitmq_user.change_password()
result['changed'] = True
if rabbitmq_user.has_tags_modifications():
rabbitmq_user.set_tags()
result['changed'] = True
if rabbitmq_user.has_permissions_modifications():
rabbitmq_user.set_permissions()
result['changed'] = True
elif state == 'present':
rabbitmq_user.add()
rabbitmq_user.set_tags()
rabbitmq_user.set_permissions()
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,144 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2013, Chatham Financial <oss@chathamfinancial.com>
# 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: rabbitmq_vhost
short_description: Manage the state of a virtual host in RabbitMQ
description:
- Manage the state of a virtual host in RabbitMQ
author: Chris Hoffman (@chrishoffman)
options:
name:
description:
- The name of the vhost to manage
required: true
aliases: [vhost]
node:
description:
- erlang node name of the rabbit we wish to configure
default: rabbit
tracing:
description:
- Enable/disable tracing for a vhost
type: bool
default: 'no'
aliases: [trace]
state:
description:
- The state of vhost
default: present
choices: [present, absent]
'''
EXAMPLES = '''
# Ensure that the vhost /test exists.
- rabbitmq_vhost:
name: /test
state: present
'''
from ansible.module_utils.basic import AnsibleModule
class RabbitMqVhost(object):
def __init__(self, module, name, tracing, node):
self.module = module
self.name = name
self.tracing = tracing
self.node = node
self._tracing = False
self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
def _exec(self, args, run_in_check_mode=False):
if not self.module.check_mode or (self.module.check_mode and run_in_check_mode):
cmd = [self._rabbitmqctl, '-q', '-n', self.node]
rc, out, err = self.module.run_command(cmd + args, check_rc=True)
return out.splitlines()
return list()
def get(self):
vhosts = self._exec(['list_vhosts', 'name', 'tracing'], True)
for vhost in vhosts:
if '\t' not in vhost:
continue
name, tracing = vhost.split('\t')
if name == self.name:
self._tracing = self.module.boolean(tracing)
return True
return False
def add(self):
return self._exec(['add_vhost', self.name])
def delete(self):
return self._exec(['delete_vhost', self.name])
def set_tracing(self):
if self.tracing != self._tracing:
if self.tracing:
self._enable_tracing()
else:
self._disable_tracing()
return True
return False
def _enable_tracing(self):
return self._exec(['trace_on', '-p', self.name])
def _disable_tracing(self):
return self._exec(['trace_off', '-p', self.name])
def main():
arg_spec = dict(
name=dict(required=True, aliases=['vhost']),
tracing=dict(default='off', aliases=['trace'], type='bool'),
state=dict(default='present', choices=['present', 'absent']),
node=dict(default='rabbit'),
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
name = module.params['name']
tracing = module.params['tracing']
state = module.params['state']
node = module.params['node']
result = dict(changed=False, name=name, state=state)
rabbitmq_vhost = RabbitMqVhost(module, name, tracing, node)
if rabbitmq_vhost.get():
if state == 'absent':
rabbitmq_vhost.delete()
result['changed'] = True
else:
if rabbitmq_vhost.set_tracing():
result['changed'] = True
elif state == 'present':
rabbitmq_vhost.add()
rabbitmq_vhost.set_tracing()
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,172 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright: (c) 2018, Hiroyuki Matsuo <h.matsuo.engineer@gmail.com>
# 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: rabbitmq_vhost_limits
author: Hiroyuki Matsuo (@h-matsuo)
short_description: Manage the state of virtual host limits in RabbitMQ
description:
- This module sets/clears certain limits on a virtual host.
- The configurable limits are I(max_connections) and I(max-queues).
options:
max_connections:
description:
- Max number of concurrent client connections.
- Negative value means "no limit".
- Ignored when the I(state) is C(absent).
default: -1
max_queues:
description:
- Max number of queues.
- Negative value means "no limit".
- Ignored when the I(state) is C(absent).
default: -1
node:
description:
- Name of the RabbitMQ Erlang node to manage.
state:
description:
- Specify whether the limits are to be set or cleared.
- If set to C(absent), the limits of both I(max_connections) and I(max-queues) will be cleared.
default: present
choices: [present, absent]
vhost:
description:
- Name of the virtual host to manage.
default: /
'''
EXAMPLES = '''
# Limit both of the max number of connections and queues on the vhost '/'.
- rabbitmq_vhost_limits:
vhost: /
max_connections: 64
max_queues: 256
state: present
# Limit the max number of connections on the vhost '/'.
# This task implicitly clears the max number of queues limit using default value: -1.
- rabbitmq_vhost_limits:
vhost: /
max_connections: 64
state: present
# Clear the limits on the vhost '/'.
- rabbitmq_vhost_limits:
vhost: /
state: absent
'''
RETURN = ''' # '''
import json
from ansible.module_utils.basic import AnsibleModule
class RabbitMqVhostLimits(object):
def __init__(self, module):
self._module = module
self._max_connections = module.params['max_connections']
self._max_queues = module.params['max_queues']
self._node = module.params['node']
self._state = module.params['state']
self._vhost = module.params['vhost']
self._rabbitmqctl = module.get_bin_path('rabbitmqctl', True)
def _exec(self, args):
cmd = [self._rabbitmqctl, '-q', '-p', self._vhost]
if self._node is not None:
cmd.extend(['-n', self._node])
rc, out, err = self._module.run_command(cmd + args, check_rc=True)
return dict(rc=rc, out=out.splitlines(), err=err.splitlines())
def list(self):
exec_result = self._exec(['list_vhost_limits'])
vhost_limits = exec_result['out'][0]
max_connections = None
max_queues = None
if vhost_limits:
vhost_limits = json.loads(vhost_limits)
if 'max-connections' in vhost_limits:
max_connections = vhost_limits['max-connections']
if 'max-queues' in vhost_limits:
max_queues = vhost_limits['max-queues']
return dict(
max_connections=max_connections,
max_queues=max_queues
)
def set(self):
if self._module.check_mode:
return
json_str = '{{"max-connections": {0}, "max-queues": {1}}}'.format(self._max_connections, self._max_queues)
self._exec(['set_vhost_limits', json_str])
def clear(self):
if self._module.check_mode:
return
self._exec(['clear_vhost_limits'])
def main():
arg_spec = dict(
max_connections=dict(default=-1, type='int'),
max_queues=dict(default=-1, type='int'),
node=dict(default=None, type='str'),
state=dict(default='present', choices=['present', 'absent'], type='str'),
vhost=dict(default='/', type='str')
)
module = AnsibleModule(
argument_spec=arg_spec,
supports_check_mode=True
)
max_connections = module.params['max_connections']
max_queues = module.params['max_queues']
node = module.params['node']
state = module.params['state']
vhost = module.params['vhost']
module_result = dict(changed=False)
rabbitmq_vhost_limits = RabbitMqVhostLimits(module)
current_status = rabbitmq_vhost_limits.list()
if state == 'present':
wanted_status = dict(
max_connections=max_connections,
max_queues=max_queues
)
else: # state == 'absent'
wanted_status = dict(
max_connections=None,
max_queues=None
)
if current_status != wanted_status:
module_result['changed'] = True
if state == 'present':
rabbitmq_vhost_limits.set()
else: # state == 'absent'
rabbitmq_vhost_limits.clear()
module.exit_json(**module_result)
if __name__ == '__main__':
main()