mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-22 04:40:22 -07:00
Initial commit
This commit is contained in:
commit
aebc1b03fd
4861 changed files with 812621 additions and 0 deletions
298
plugins/modules/database/misc/elasticsearch_plugin.py
Normal file
298
plugins/modules/database/misc/elasticsearch_plugin.py
Normal file
|
@ -0,0 +1,298 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# (c) 2015, Mathew Davies <thepixeldeveloper@googlemail.com>
|
||||
# (c) 2017, Sam Doran <sdoran@redhat.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: elasticsearch_plugin
|
||||
short_description: Manage Elasticsearch plugins
|
||||
description:
|
||||
- Manages Elasticsearch plugins.
|
||||
author:
|
||||
- Mathew Davies (@ThePixelDeveloper)
|
||||
- Sam Doran (@samdoran)
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the plugin to install.
|
||||
required: True
|
||||
state:
|
||||
description:
|
||||
- Desired state of a plugin.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
src:
|
||||
description:
|
||||
- Optionally set the source location to retrieve the plugin from. This can be a file://
|
||||
URL to install from a local file, or a remote URL. If this is not set, the plugin
|
||||
location is just based on the name.
|
||||
- The name parameter must match the descriptor in the plugin ZIP specified.
|
||||
- Is only used if the state would change, which is solely checked based on the name
|
||||
parameter. If, for example, the plugin is already installed, changing this has no
|
||||
effect.
|
||||
- For ES 1.x use url.
|
||||
required: False
|
||||
url:
|
||||
description:
|
||||
- Set exact URL to download the plugin from (Only works for ES 1.x).
|
||||
- For ES 2.x and higher, use src.
|
||||
required: False
|
||||
timeout:
|
||||
description:
|
||||
- "Timeout setting: 30s, 1m, 1h..."
|
||||
- Only valid for Elasticsearch < 5.0. This option is ignored for Elasticsearch > 5.0.
|
||||
default: 1m
|
||||
force:
|
||||
description:
|
||||
- "Force batch mode when installing plugins. This is only necessary if a plugin requires additional permissions and console detection fails."
|
||||
default: False
|
||||
type: bool
|
||||
plugin_bin:
|
||||
description:
|
||||
- Location of the plugin binary. If this file is not found, the default plugin binaries will be used.
|
||||
- The default changed in Ansible 2.4 to None.
|
||||
plugin_dir:
|
||||
description:
|
||||
- Your configured plugin directory specified in Elasticsearch
|
||||
default: /usr/share/elasticsearch/plugins/
|
||||
proxy_host:
|
||||
description:
|
||||
- Proxy host to use during plugin installation
|
||||
proxy_port:
|
||||
description:
|
||||
- Proxy port to use during plugin installation
|
||||
version:
|
||||
description:
|
||||
- Version of the plugin to be installed.
|
||||
If plugin exists with previous version, it will NOT be updated
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Install Elasticsearch Head plugin in Elasticsearch 2.x
|
||||
- elasticsearch_plugin:
|
||||
name: mobz/elasticsearch-head
|
||||
state: present
|
||||
|
||||
# Install a specific version of Elasticsearch Head in Elasticsearch 2.x
|
||||
- elasticsearch_plugin:
|
||||
name: mobz/elasticsearch-head
|
||||
version: 2.0.0
|
||||
|
||||
# Uninstall Elasticsearch head plugin in Elasticsearch 2.x
|
||||
- elasticsearch_plugin:
|
||||
name: mobz/elasticsearch-head
|
||||
state: absent
|
||||
|
||||
# Install a specific plugin in Elasticsearch >= 5.0
|
||||
- elasticsearch_plugin:
|
||||
name: analysis-icu
|
||||
state: present
|
||||
|
||||
# Install the ingest-geoip plugin with a forced installation
|
||||
- elasticsearch_plugin:
|
||||
name: ingest-geoip
|
||||
state: present
|
||||
force: yes
|
||||
'''
|
||||
|
||||
import os
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
PACKAGE_STATE_MAP = dict(
|
||||
present="install",
|
||||
absent="remove"
|
||||
)
|
||||
|
||||
PLUGIN_BIN_PATHS = tuple([
|
||||
'/usr/share/elasticsearch/bin/elasticsearch-plugin',
|
||||
'/usr/share/elasticsearch/bin/plugin'
|
||||
])
|
||||
|
||||
|
||||
def parse_plugin_repo(string):
|
||||
elements = string.split("/")
|
||||
|
||||
# We first consider the simplest form: pluginname
|
||||
repo = elements[0]
|
||||
|
||||
# We consider the form: username/pluginname
|
||||
if len(elements) > 1:
|
||||
repo = elements[1]
|
||||
|
||||
# remove elasticsearch- prefix
|
||||
# remove es- prefix
|
||||
for string in ("elasticsearch-", "es-"):
|
||||
if repo.startswith(string):
|
||||
return repo[len(string):]
|
||||
|
||||
return repo
|
||||
|
||||
|
||||
def is_plugin_present(plugin_name, plugin_dir):
|
||||
return os.path.isdir(os.path.join(plugin_dir, plugin_name))
|
||||
|
||||
|
||||
def parse_error(string):
|
||||
reason = "ERROR: "
|
||||
try:
|
||||
return string[string.index(reason) + len(reason):].strip()
|
||||
except ValueError:
|
||||
return string
|
||||
|
||||
|
||||
def install_plugin(module, plugin_bin, plugin_name, version, src, url, proxy_host, proxy_port, timeout, force):
|
||||
cmd_args = [plugin_bin, PACKAGE_STATE_MAP["present"]]
|
||||
is_old_command = (os.path.basename(plugin_bin) == 'plugin')
|
||||
|
||||
# Timeout and version are only valid for plugin, not elasticsearch-plugin
|
||||
if is_old_command:
|
||||
if timeout:
|
||||
cmd_args.append("--timeout %s" % timeout)
|
||||
|
||||
if version:
|
||||
plugin_name = plugin_name + '/' + version
|
||||
cmd_args[2] = plugin_name
|
||||
|
||||
if proxy_host and proxy_port:
|
||||
cmd_args.append("-DproxyHost=%s -DproxyPort=%s" % (proxy_host, proxy_port))
|
||||
|
||||
# Legacy ES 1.x
|
||||
if url:
|
||||
cmd_args.append("--url %s" % url)
|
||||
|
||||
if force:
|
||||
cmd_args.append("--batch")
|
||||
if src:
|
||||
cmd_args.append(src)
|
||||
else:
|
||||
cmd_args.append(plugin_name)
|
||||
|
||||
cmd = " ".join(cmd_args)
|
||||
|
||||
if module.check_mode:
|
||||
rc, out, err = 0, "check mode", ""
|
||||
else:
|
||||
rc, out, err = module.run_command(cmd)
|
||||
|
||||
if rc != 0:
|
||||
reason = parse_error(out)
|
||||
module.fail_json(msg="Installing plugin '%s' failed: %s" % (plugin_name, reason), err=err)
|
||||
|
||||
return True, cmd, out, err
|
||||
|
||||
|
||||
def remove_plugin(module, plugin_bin, plugin_name):
|
||||
cmd_args = [plugin_bin, PACKAGE_STATE_MAP["absent"], parse_plugin_repo(plugin_name)]
|
||||
|
||||
cmd = " ".join(cmd_args)
|
||||
|
||||
if module.check_mode:
|
||||
rc, out, err = 0, "check mode", ""
|
||||
else:
|
||||
rc, out, err = module.run_command(cmd)
|
||||
|
||||
if rc != 0:
|
||||
reason = parse_error(out)
|
||||
module.fail_json(msg="Removing plugin '%s' failed: %s" % (plugin_name, reason), err=err)
|
||||
|
||||
return True, cmd, out, err
|
||||
|
||||
|
||||
def get_plugin_bin(module, plugin_bin=None):
|
||||
# Use the plugin_bin that was supplied first before trying other options
|
||||
valid_plugin_bin = None
|
||||
if plugin_bin and os.path.isfile(plugin_bin):
|
||||
valid_plugin_bin = plugin_bin
|
||||
|
||||
else:
|
||||
# Add the plugin_bin passed into the module to the top of the list of paths to test,
|
||||
# testing for that binary name first before falling back to the default paths.
|
||||
bin_paths = list(PLUGIN_BIN_PATHS)
|
||||
if plugin_bin and plugin_bin not in bin_paths:
|
||||
bin_paths.insert(0, plugin_bin)
|
||||
|
||||
# Get separate lists of dirs and binary names from the full paths to the
|
||||
# plugin binaries.
|
||||
plugin_dirs = list(set([os.path.dirname(x) for x in bin_paths]))
|
||||
plugin_bins = list(set([os.path.basename(x) for x in bin_paths]))
|
||||
|
||||
# Check for the binary names in the default system paths as well as the path
|
||||
# specified in the module arguments.
|
||||
for bin_file in plugin_bins:
|
||||
valid_plugin_bin = module.get_bin_path(bin_file, opt_dirs=plugin_dirs)
|
||||
if valid_plugin_bin:
|
||||
break
|
||||
|
||||
if not valid_plugin_bin:
|
||||
module.fail_json(msg='%s does not exist and no other valid plugin installers were found. Make sure Elasticsearch is installed.' % plugin_bin)
|
||||
|
||||
return valid_plugin_bin
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(required=True),
|
||||
state=dict(default="present", choices=PACKAGE_STATE_MAP.keys()),
|
||||
src=dict(default=None),
|
||||
url=dict(default=None),
|
||||
timeout=dict(default="1m"),
|
||||
force=dict(type='bool', default=False),
|
||||
plugin_bin=dict(type="path"),
|
||||
plugin_dir=dict(default="/usr/share/elasticsearch/plugins/", type="path"),
|
||||
proxy_host=dict(default=None),
|
||||
proxy_port=dict(default=None),
|
||||
version=dict(default=None)
|
||||
),
|
||||
mutually_exclusive=[("src", "url")],
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
name = module.params["name"]
|
||||
state = module.params["state"]
|
||||
url = module.params["url"]
|
||||
src = module.params["src"]
|
||||
timeout = module.params["timeout"]
|
||||
force = module.params["force"]
|
||||
plugin_bin = module.params["plugin_bin"]
|
||||
plugin_dir = module.params["plugin_dir"]
|
||||
proxy_host = module.params["proxy_host"]
|
||||
proxy_port = module.params["proxy_port"]
|
||||
version = module.params["version"]
|
||||
|
||||
# Search provided path and system paths for valid binary
|
||||
plugin_bin = get_plugin_bin(module, plugin_bin)
|
||||
|
||||
repo = parse_plugin_repo(name)
|
||||
present = is_plugin_present(repo, plugin_dir)
|
||||
|
||||
# skip if the state is correct
|
||||
if (present and state == "present") or (state == "absent" and not present):
|
||||
module.exit_json(changed=False, name=name, state=state)
|
||||
|
||||
if state == "present":
|
||||
changed, cmd, out, err = install_plugin(module, plugin_bin, name, version, src, url, proxy_host, proxy_port, timeout, force)
|
||||
|
||||
elif state == "absent":
|
||||
changed, cmd, out, err = remove_plugin(module, plugin_bin, name)
|
||||
|
||||
module.exit_json(changed=changed, cmd=cmd, name=name, state=state, url=url, timeout=timeout, stdout=out, stderr=err)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
264
plugins/modules/database/misc/kibana_plugin.py
Normal file
264
plugins/modules/database/misc/kibana_plugin.py
Normal file
|
@ -0,0 +1,264 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2016, Thierno IB. BARRY @barryib
|
||||
# Sponsored by Polyconseil http://polyconseil.fr.
|
||||
#
|
||||
# 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: kibana_plugin
|
||||
short_description: Manage Kibana plugins
|
||||
description:
|
||||
- This module can be used to manage Kibana plugins.
|
||||
author: Thierno IB. BARRY (@barryib)
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
- Name of the plugin to install.
|
||||
required: True
|
||||
state:
|
||||
description:
|
||||
- Desired state of a plugin.
|
||||
choices: ["present", "absent"]
|
||||
default: present
|
||||
url:
|
||||
description:
|
||||
- Set exact URL to download the plugin from.
|
||||
- For local file, prefix its absolute path with file://
|
||||
timeout:
|
||||
description:
|
||||
- "Timeout setting: 30s, 1m, 1h etc."
|
||||
default: 1m
|
||||
plugin_bin:
|
||||
description:
|
||||
- Location of the Kibana binary.
|
||||
default: /opt/kibana/bin/kibana
|
||||
plugin_dir:
|
||||
description:
|
||||
- Your configured plugin directory specified in Kibana.
|
||||
default: /opt/kibana/installedPlugins/
|
||||
version:
|
||||
description:
|
||||
- Version of the plugin to be installed.
|
||||
- If plugin exists with previous version, plugin will NOT be updated unless C(force) is set to yes.
|
||||
force:
|
||||
description:
|
||||
- Delete and re-install the plugin. Can be useful for plugins update.
|
||||
type: bool
|
||||
default: 'no'
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Install Elasticsearch head plugin
|
||||
kibana_plugin:
|
||||
state: present
|
||||
name: elasticsearch/marvel
|
||||
|
||||
- name: Install specific version of a plugin
|
||||
kibana_plugin:
|
||||
state: present
|
||||
name: elasticsearch/marvel
|
||||
version: '2.3.3'
|
||||
|
||||
- name: Uninstall Elasticsearch head plugin
|
||||
kibana_plugin:
|
||||
state: absent
|
||||
name: elasticsearch/marvel
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
cmd:
|
||||
description: the launched command during plugin management (install / remove)
|
||||
returned: success
|
||||
type: str
|
||||
name:
|
||||
description: the plugin name to install or remove
|
||||
returned: success
|
||||
type: str
|
||||
url:
|
||||
description: the url from where the plugin is installed from
|
||||
returned: success
|
||||
type: str
|
||||
timeout:
|
||||
description: the timeout for plugin download
|
||||
returned: success
|
||||
type: str
|
||||
stdout:
|
||||
description: the command stdout
|
||||
returned: success
|
||||
type: str
|
||||
stderr:
|
||||
description: the command stderr
|
||||
returned: success
|
||||
type: str
|
||||
state:
|
||||
description: the state for the managed plugin
|
||||
returned: success
|
||||
type: str
|
||||
'''
|
||||
|
||||
import os
|
||||
from distutils.version import LooseVersion
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
PACKAGE_STATE_MAP = dict(
|
||||
present="--install",
|
||||
absent="--remove"
|
||||
)
|
||||
|
||||
|
||||
def parse_plugin_repo(string):
|
||||
elements = string.split("/")
|
||||
|
||||
# We first consider the simplest form: pluginname
|
||||
repo = elements[0]
|
||||
|
||||
# We consider the form: username/pluginname
|
||||
if len(elements) > 1:
|
||||
repo = elements[1]
|
||||
|
||||
# remove elasticsearch- prefix
|
||||
# remove es- prefix
|
||||
for string in ("elasticsearch-", "es-"):
|
||||
if repo.startswith(string):
|
||||
return repo[len(string):]
|
||||
|
||||
return repo
|
||||
|
||||
|
||||
def is_plugin_present(plugin_dir, working_dir):
|
||||
return os.path.isdir(os.path.join(working_dir, plugin_dir))
|
||||
|
||||
|
||||
def parse_error(string):
|
||||
reason = "reason: "
|
||||
try:
|
||||
return string[string.index(reason) + len(reason):].strip()
|
||||
except ValueError:
|
||||
return string
|
||||
|
||||
|
||||
def install_plugin(module, plugin_bin, plugin_name, url, timeout, kibana_version='4.6'):
|
||||
if LooseVersion(kibana_version) > LooseVersion('4.6'):
|
||||
kibana_plugin_bin = os.path.join(os.path.dirname(plugin_bin), 'kibana-plugin')
|
||||
cmd_args = [kibana_plugin_bin, "install"]
|
||||
if url:
|
||||
cmd_args.append(url)
|
||||
else:
|
||||
cmd_args.append(plugin_name)
|
||||
else:
|
||||
cmd_args = [plugin_bin, "plugin", PACKAGE_STATE_MAP["present"], plugin_name]
|
||||
|
||||
if url:
|
||||
cmd_args.append("--url %s" % url)
|
||||
|
||||
if timeout:
|
||||
cmd_args.append("--timeout %s" % timeout)
|
||||
|
||||
cmd = " ".join(cmd_args)
|
||||
|
||||
if module.check_mode:
|
||||
return True, cmd, "check mode", ""
|
||||
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc != 0:
|
||||
reason = parse_error(out)
|
||||
module.fail_json(msg=reason)
|
||||
|
||||
return True, cmd, out, err
|
||||
|
||||
|
||||
def remove_plugin(module, plugin_bin, plugin_name, kibana_version='4.6'):
|
||||
if LooseVersion(kibana_version) > LooseVersion('4.6'):
|
||||
kibana_plugin_bin = os.path.join(os.path.dirname(plugin_bin), 'kibana-plugin')
|
||||
cmd_args = [kibana_plugin_bin, "remove", plugin_name]
|
||||
else:
|
||||
cmd_args = [plugin_bin, "plugin", PACKAGE_STATE_MAP["absent"], plugin_name]
|
||||
|
||||
cmd = " ".join(cmd_args)
|
||||
|
||||
if module.check_mode:
|
||||
return True, cmd, "check mode", ""
|
||||
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc != 0:
|
||||
reason = parse_error(out)
|
||||
module.fail_json(msg=reason)
|
||||
|
||||
return True, cmd, out, err
|
||||
|
||||
|
||||
def get_kibana_version(module, plugin_bin):
|
||||
cmd_args = [plugin_bin, '--version']
|
||||
cmd = " ".join(cmd_args)
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Failed to get Kibana version : %s" % err)
|
||||
|
||||
return out.strip()
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
name=dict(required=True),
|
||||
state=dict(default="present", choices=PACKAGE_STATE_MAP.keys()),
|
||||
url=dict(default=None),
|
||||
timeout=dict(default="1m"),
|
||||
plugin_bin=dict(default="/opt/kibana/bin/kibana", type="path"),
|
||||
plugin_dir=dict(default="/opt/kibana/installedPlugins/", type="path"),
|
||||
version=dict(default=None),
|
||||
force=dict(default="no", type="bool")
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
name = module.params["name"]
|
||||
state = module.params["state"]
|
||||
url = module.params["url"]
|
||||
timeout = module.params["timeout"]
|
||||
plugin_bin = module.params["plugin_bin"]
|
||||
plugin_dir = module.params["plugin_dir"]
|
||||
version = module.params["version"]
|
||||
force = module.params["force"]
|
||||
|
||||
changed, cmd, out, err = False, '', '', ''
|
||||
|
||||
kibana_version = get_kibana_version(module, plugin_bin)
|
||||
|
||||
present = is_plugin_present(parse_plugin_repo(name), plugin_dir)
|
||||
|
||||
# skip if the state is correct
|
||||
if (present and state == "present" and not force) or (state == "absent" and not present and not force):
|
||||
module.exit_json(changed=False, name=name, state=state)
|
||||
|
||||
if version:
|
||||
name = name + '/' + version
|
||||
|
||||
if state == "present":
|
||||
if force:
|
||||
remove_plugin(module, plugin_bin, name)
|
||||
changed, cmd, out, err = install_plugin(module, plugin_bin, name, url, timeout, kibana_version)
|
||||
|
||||
elif state == "absent":
|
||||
changed, cmd, out, err = remove_plugin(module, plugin_bin, name, kibana_version)
|
||||
|
||||
module.exit_json(changed=changed, cmd=cmd, name=name, state=state, url=url, timeout=timeout, stdout=out, stderr=err)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
312
plugins/modules/database/misc/redis.py
Normal file
312
plugins/modules/database/misc/redis.py
Normal file
|
@ -0,0 +1,312 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: Ansible Project
|
||||
# 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: redis
|
||||
short_description: Various redis commands, slave and flush
|
||||
description:
|
||||
- Unified utility to interact with redis instances.
|
||||
options:
|
||||
command:
|
||||
description:
|
||||
- The selected redis command
|
||||
- C(config) (new in 1.6), ensures a configuration setting on an instance.
|
||||
- C(flush) flushes all the instance or a specified db.
|
||||
- C(slave) sets a redis instance in slave or master mode.
|
||||
required: true
|
||||
choices: [ config, flush, slave ]
|
||||
login_password:
|
||||
description:
|
||||
- The password used to authenticate with (usually not used)
|
||||
login_host:
|
||||
description:
|
||||
- The host running the database
|
||||
default: localhost
|
||||
login_port:
|
||||
description:
|
||||
- The port to connect to
|
||||
default: 6379
|
||||
master_host:
|
||||
description:
|
||||
- The host of the master instance [slave command]
|
||||
master_port:
|
||||
description:
|
||||
- The port of the master instance [slave command]
|
||||
slave_mode:
|
||||
description:
|
||||
- the mode of the redis instance [slave command]
|
||||
default: slave
|
||||
choices: [ master, slave ]
|
||||
db:
|
||||
description:
|
||||
- The database to flush (used in db mode) [flush command]
|
||||
flush_mode:
|
||||
description:
|
||||
- Type of flush (all the dbs in a redis instance or a specific one)
|
||||
[flush command]
|
||||
default: all
|
||||
choices: [ all, db ]
|
||||
name:
|
||||
description:
|
||||
- A redis config key.
|
||||
value:
|
||||
description:
|
||||
- A redis config value. When memory size is needed, it is possible
|
||||
to specify it in the usal form of 1KB, 2M, 400MB where the base is 1024.
|
||||
Units are case insensitive i.e. 1m = 1mb = 1M = 1MB.
|
||||
|
||||
notes:
|
||||
- Requires the redis-py Python package on the remote host. You can
|
||||
install it with pip (pip install redis) or with a package manager.
|
||||
https://github.com/andymccurdy/redis-py
|
||||
- If the redis master instance we are making slave of is password protected
|
||||
this needs to be in the redis.conf in the masterauth variable
|
||||
|
||||
requirements: [ redis ]
|
||||
author: "Xabier Larrakoetxea (@slok)"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Set local redis instance to be slave of melee.island on port 6377
|
||||
redis:
|
||||
command: slave
|
||||
master_host: melee.island
|
||||
master_port: 6377
|
||||
|
||||
- name: Deactivate slave mode
|
||||
redis:
|
||||
command: slave
|
||||
slave_mode: master
|
||||
|
||||
- name: Flush all the redis db
|
||||
redis:
|
||||
command: flush
|
||||
flush_mode: all
|
||||
|
||||
- name: Flush only one db in a redis instance
|
||||
redis:
|
||||
command: flush
|
||||
db: 1
|
||||
flush_mode: db
|
||||
|
||||
- name: Configure local redis to have 10000 max clients
|
||||
redis:
|
||||
command: config
|
||||
name: maxclients
|
||||
value: 10000
|
||||
|
||||
- name: Configure local redis maxmemory to 4GB
|
||||
redis:
|
||||
command: config
|
||||
name: maxmemory
|
||||
value: 4GB
|
||||
|
||||
- name: Configure local redis to have lua time limit of 100 ms
|
||||
redis:
|
||||
command: config
|
||||
name: lua-time-limit
|
||||
value: 100
|
||||
'''
|
||||
|
||||
import traceback
|
||||
|
||||
REDIS_IMP_ERR = None
|
||||
try:
|
||||
import redis
|
||||
except ImportError:
|
||||
REDIS_IMP_ERR = traceback.format_exc()
|
||||
redis_found = False
|
||||
else:
|
||||
redis_found = True
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
from ansible.module_utils.common.text.formatters import human_to_bytes
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
# Redis module specific support methods.
|
||||
def set_slave_mode(client, master_host, master_port):
|
||||
try:
|
||||
return client.slaveof(master_host, master_port)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def set_master_mode(client):
|
||||
try:
|
||||
return client.slaveof()
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
def flush(client, db=None):
|
||||
try:
|
||||
if not isinstance(db, int):
|
||||
return client.flushall()
|
||||
else:
|
||||
# The passed client has been connected to the database already
|
||||
return client.flushdb()
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
# Module execution.
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
command=dict(type='str', choices=['config', 'flush', 'slave']),
|
||||
login_password=dict(type='str', no_log=True),
|
||||
login_host=dict(type='str', default='localhost'),
|
||||
login_port=dict(type='int', default=6379),
|
||||
master_host=dict(type='str'),
|
||||
master_port=dict(type='int'),
|
||||
slave_mode=dict(type='str', default='slave', choices=['master', 'slave']),
|
||||
db=dict(type='int'),
|
||||
flush_mode=dict(type='str', default='all', choices=['all', 'db']),
|
||||
name=dict(type='str'),
|
||||
value=dict(type='str')
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
if not redis_found:
|
||||
module.fail_json(msg=missing_required_lib('redis'), exception=REDIS_IMP_ERR)
|
||||
|
||||
login_password = module.params['login_password']
|
||||
login_host = module.params['login_host']
|
||||
login_port = module.params['login_port']
|
||||
command = module.params['command']
|
||||
|
||||
# Slave Command section -----------
|
||||
if command == "slave":
|
||||
master_host = module.params['master_host']
|
||||
master_port = module.params['master_port']
|
||||
mode = module.params['slave_mode']
|
||||
|
||||
# Check if we have all the data
|
||||
if mode == "slave": # Only need data if we want to be slave
|
||||
if not master_host:
|
||||
module.fail_json(msg='In slave mode master host must be provided')
|
||||
|
||||
if not master_port:
|
||||
module.fail_json(msg='In slave mode master port must be provided')
|
||||
|
||||
# Connect and check
|
||||
r = redis.StrictRedis(host=login_host, port=login_port, password=login_password)
|
||||
try:
|
||||
r.ping()
|
||||
except Exception as e:
|
||||
module.fail_json(msg="unable to connect to database: %s" % to_native(e), exception=traceback.format_exc())
|
||||
|
||||
# Check if we are already in the mode that we want
|
||||
info = r.info()
|
||||
if mode == "master" and info["role"] == "master":
|
||||
module.exit_json(changed=False, mode=mode)
|
||||
|
||||
elif mode == "slave" and info["role"] == "slave" and info["master_host"] == master_host and info["master_port"] == master_port:
|
||||
status = dict(
|
||||
status=mode,
|
||||
master_host=master_host,
|
||||
master_port=master_port,
|
||||
)
|
||||
module.exit_json(changed=False, mode=status)
|
||||
else:
|
||||
# Do the stuff
|
||||
# (Check Check_mode before commands so the commands aren't evaluated
|
||||
# if not necessary)
|
||||
if mode == "slave":
|
||||
if module.check_mode or\
|
||||
set_slave_mode(r, master_host, master_port):
|
||||
info = r.info()
|
||||
status = {
|
||||
'status': mode,
|
||||
'master_host': master_host,
|
||||
'master_port': master_port,
|
||||
}
|
||||
module.exit_json(changed=True, mode=status)
|
||||
else:
|
||||
module.fail_json(msg='Unable to set slave mode')
|
||||
|
||||
else:
|
||||
if module.check_mode or set_master_mode(r):
|
||||
module.exit_json(changed=True, mode=mode)
|
||||
else:
|
||||
module.fail_json(msg='Unable to set master mode')
|
||||
|
||||
# flush Command section -----------
|
||||
elif command == "flush":
|
||||
db = module.params['db']
|
||||
mode = module.params['flush_mode']
|
||||
|
||||
# Check if we have all the data
|
||||
if mode == "db":
|
||||
if db is None:
|
||||
module.fail_json(msg="In db mode the db number must be provided")
|
||||
|
||||
# Connect and check
|
||||
r = redis.StrictRedis(host=login_host, port=login_port, password=login_password, db=db)
|
||||
try:
|
||||
r.ping()
|
||||
except Exception as e:
|
||||
module.fail_json(msg="unable to connect to database: %s" % to_native(e), exception=traceback.format_exc())
|
||||
|
||||
# Do the stuff
|
||||
# (Check Check_mode before commands so the commands aren't evaluated
|
||||
# if not necessary)
|
||||
if mode == "all":
|
||||
if module.check_mode or flush(r):
|
||||
module.exit_json(changed=True, flushed=True)
|
||||
else: # Flush never fails :)
|
||||
module.fail_json(msg="Unable to flush all databases")
|
||||
|
||||
else:
|
||||
if module.check_mode or flush(r, db):
|
||||
module.exit_json(changed=True, flushed=True, db=db)
|
||||
else: # Flush never fails :)
|
||||
module.fail_json(msg="Unable to flush '%d' database" % db)
|
||||
elif command == 'config':
|
||||
name = module.params['name']
|
||||
|
||||
try: # try to parse the value as if it were the memory size
|
||||
value = str(human_to_bytes(module.params['value'].upper()))
|
||||
except ValueError:
|
||||
value = module.params['value']
|
||||
|
||||
r = redis.StrictRedis(host=login_host, port=login_port, password=login_password)
|
||||
|
||||
try:
|
||||
r.ping()
|
||||
except Exception as e:
|
||||
module.fail_json(msg="unable to connect to database: %s" % to_native(e), exception=traceback.format_exc())
|
||||
|
||||
try:
|
||||
old_value = r.config_get(name)[name]
|
||||
except Exception as e:
|
||||
module.fail_json(msg="unable to read config: %s" % to_native(e), exception=traceback.format_exc())
|
||||
changed = old_value != value
|
||||
|
||||
if module.check_mode or not changed:
|
||||
module.exit_json(changed=changed, name=name, value=value)
|
||||
else:
|
||||
try:
|
||||
r.config_set(name, value)
|
||||
except Exception as e:
|
||||
module.fail_json(msg="unable to write config: %s" % to_native(e), exception=traceback.format_exc())
|
||||
module.exit_json(changed=changed, name=name, value=value)
|
||||
else:
|
||||
module.fail_json(msg='A valid command must be provided')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
226
plugins/modules/database/misc/riak.py
Normal file
226
plugins/modules/database/misc/riak.py
Normal file
|
@ -0,0 +1,226 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2013, James Martin <jmartin@basho.com>, Drew Kerrigan <dkerrigan@basho.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: riak
|
||||
short_description: This module handles some common Riak operations
|
||||
description:
|
||||
- This module can be used to join nodes to a cluster, check
|
||||
the status of the cluster.
|
||||
author:
|
||||
- "James Martin (@jsmartin)"
|
||||
- "Drew Kerrigan (@drewkerrigan)"
|
||||
options:
|
||||
command:
|
||||
description:
|
||||
- The command you would like to perform against the cluster.
|
||||
choices: ['ping', 'kv_test', 'join', 'plan', 'commit']
|
||||
config_dir:
|
||||
description:
|
||||
- The path to the riak configuration directory
|
||||
default: /etc/riak
|
||||
http_conn:
|
||||
description:
|
||||
- The ip address and port that is listening for Riak HTTP queries
|
||||
default: 127.0.0.1:8098
|
||||
target_node:
|
||||
description:
|
||||
- The target node for certain operations (join, ping)
|
||||
default: riak@127.0.0.1
|
||||
wait_for_handoffs:
|
||||
description:
|
||||
- Number of seconds to wait for handoffs to complete.
|
||||
wait_for_ring:
|
||||
description:
|
||||
- Number of seconds to wait for all nodes to agree on the ring.
|
||||
wait_for_service:
|
||||
description:
|
||||
- Waits for a riak service to come online before continuing.
|
||||
choices: ['kv']
|
||||
validate_certs:
|
||||
description:
|
||||
- If C(no), SSL certificates will not be validated. This should only be used
|
||||
on personally controlled sites using self-signed certificates.
|
||||
type: bool
|
||||
default: 'yes'
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Join's a Riak node to another node
|
||||
- riak:
|
||||
command: join
|
||||
target_node: riak@10.1.1.1
|
||||
|
||||
# Wait for handoffs to finish. Use with async and poll.
|
||||
- riak:
|
||||
wait_for_handoffs: yes
|
||||
|
||||
# Wait for riak_kv service to startup
|
||||
- riak:
|
||||
wait_for_service: kv
|
||||
'''
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
from ansible.module_utils.urls import fetch_url
|
||||
|
||||
|
||||
def ring_check(module, riak_admin_bin):
|
||||
cmd = '%s ringready' % riak_admin_bin
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc == 0 and 'TRUE All nodes agree on the ring' in out:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=dict(
|
||||
command=dict(required=False, default=None, choices=[
|
||||
'ping', 'kv_test', 'join', 'plan', 'commit']),
|
||||
config_dir=dict(default='/etc/riak', type='path'),
|
||||
http_conn=dict(required=False, default='127.0.0.1:8098'),
|
||||
target_node=dict(default='riak@127.0.0.1', required=False),
|
||||
wait_for_handoffs=dict(default=False, type='int'),
|
||||
wait_for_ring=dict(default=False, type='int'),
|
||||
wait_for_service=dict(
|
||||
required=False, default=None, choices=['kv']),
|
||||
validate_certs=dict(default='yes', type='bool'))
|
||||
)
|
||||
|
||||
command = module.params.get('command')
|
||||
http_conn = module.params.get('http_conn')
|
||||
target_node = module.params.get('target_node')
|
||||
wait_for_handoffs = module.params.get('wait_for_handoffs')
|
||||
wait_for_ring = module.params.get('wait_for_ring')
|
||||
wait_for_service = module.params.get('wait_for_service')
|
||||
|
||||
# make sure riak commands are on the path
|
||||
riak_bin = module.get_bin_path('riak')
|
||||
riak_admin_bin = module.get_bin_path('riak-admin')
|
||||
|
||||
timeout = time.time() + 120
|
||||
while True:
|
||||
if time.time() > timeout:
|
||||
module.fail_json(msg='Timeout, could not fetch Riak stats.')
|
||||
(response, info) = fetch_url(module, 'http://%s/stats' % (http_conn), force=True, timeout=5)
|
||||
if info['status'] == 200:
|
||||
stats_raw = response.read()
|
||||
break
|
||||
time.sleep(5)
|
||||
|
||||
# here we attempt to load those stats,
|
||||
try:
|
||||
stats = json.loads(stats_raw)
|
||||
except Exception:
|
||||
module.fail_json(msg='Could not parse Riak stats.')
|
||||
|
||||
node_name = stats['nodename']
|
||||
nodes = stats['ring_members']
|
||||
ring_size = stats['ring_creation_size']
|
||||
rc, out, err = module.run_command([riak_bin, 'version'])
|
||||
version = out.strip()
|
||||
|
||||
result = dict(node_name=node_name,
|
||||
nodes=nodes,
|
||||
ring_size=ring_size,
|
||||
version=version)
|
||||
|
||||
if command == 'ping':
|
||||
cmd = '%s ping %s' % (riak_bin, target_node)
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc == 0:
|
||||
result['ping'] = out
|
||||
else:
|
||||
module.fail_json(msg=out)
|
||||
|
||||
elif command == 'kv_test':
|
||||
cmd = '%s test' % riak_admin_bin
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc == 0:
|
||||
result['kv_test'] = out
|
||||
else:
|
||||
module.fail_json(msg=out)
|
||||
|
||||
elif command == 'join':
|
||||
if nodes.count(node_name) == 1 and len(nodes) > 1:
|
||||
result['join'] = 'Node is already in cluster or staged to be in cluster.'
|
||||
else:
|
||||
cmd = '%s cluster join %s' % (riak_admin_bin, target_node)
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc == 0:
|
||||
result['join'] = out
|
||||
result['changed'] = True
|
||||
else:
|
||||
module.fail_json(msg=out)
|
||||
|
||||
elif command == 'plan':
|
||||
cmd = '%s cluster plan' % riak_admin_bin
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc == 0:
|
||||
result['plan'] = out
|
||||
if 'Staged Changes' in out:
|
||||
result['changed'] = True
|
||||
else:
|
||||
module.fail_json(msg=out)
|
||||
|
||||
elif command == 'commit':
|
||||
cmd = '%s cluster commit' % riak_admin_bin
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if rc == 0:
|
||||
result['commit'] = out
|
||||
result['changed'] = True
|
||||
else:
|
||||
module.fail_json(msg=out)
|
||||
|
||||
# this could take a while, recommend to run in async mode
|
||||
if wait_for_handoffs:
|
||||
timeout = time.time() + wait_for_handoffs
|
||||
while True:
|
||||
cmd = '%s transfers' % riak_admin_bin
|
||||
rc, out, err = module.run_command(cmd)
|
||||
if 'No transfers active' in out:
|
||||
result['handoffs'] = 'No transfers active.'
|
||||
break
|
||||
time.sleep(10)
|
||||
if time.time() > timeout:
|
||||
module.fail_json(msg='Timeout waiting for handoffs.')
|
||||
|
||||
if wait_for_service:
|
||||
cmd = [riak_admin_bin, 'wait_for_service', 'riak_%s' % wait_for_service, node_name]
|
||||
rc, out, err = module.run_command(cmd)
|
||||
result['service'] = out
|
||||
|
||||
if wait_for_ring:
|
||||
timeout = time.time() + wait_for_ring
|
||||
while True:
|
||||
if ring_check(module, riak_admin_bin):
|
||||
break
|
||||
time.sleep(10)
|
||||
if time.time() > timeout:
|
||||
module.fail_json(msg='Timeout waiting for nodes to agree on ring.')
|
||||
|
||||
result['ring_ready'] = ring_check(module, riak_admin_bin)
|
||||
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Add table
Add a link
Reference in a new issue