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,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()

View 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()

View 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()

View 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()