diff --git a/database/redis b/database/redis new file mode 100644 index 00000000000..d43b9944916 --- /dev/null +++ b/database/redis @@ -0,0 +1,281 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +DOCUMENTATION = ''' +--- +module: redis +short_description: Various redis commands, slave and flush +description: + - Unified utility to interact with redis instances. + 'slave' Sets a redis instance in slave or master mode. + 'flush' Flushes all the instance or ans specified db. +version_added: "1.3" +options: + action: + description: + - The selected redis action + required: true + default: null + choices: [ "slave", "flush" ] + login_password: + description: + - The password used to authenticate with (usually not used) + required: false + default: null + login_host: + description: + - The host running the database + required: false + default: localhost + login_port: + description: + - The port to connect to + required: false + default: 6379 + master_host: + description: + - The host of the master instance [slave action] + required: false + default: null + master_port: + description: + - The port of the master instance [slave action] + required: false + default: null + slave_mode: + description: + - the mode of the redis instance [slave action] + required: false + default: slave + choices: [ "master", "slave" ] + db: + description: + - The database to flush (used in db mode) [flush action] + required: false + default: null + flush_mode: + description: + - Type of flush (all the dbs in a redis instance or a specific one) + [flush action] + required: false + default: all + choices: [ "all", "db" ] + + +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 +''' + +EXAMPLES = ''' +# Set local redis instance to be slave of melee.island on port 6377 +- redis: action=slave master_host=melee.island master_port=6377 + +# Deactivate slave mode +- redis: action=slave slave_mode=master + +# Flush all the redis db +- redis: action=flush flush_mode=all + +# Flush only one db in a redis instance +- redis: action=flush db=1 flush_mode=db +''' + +try: + import redis +except ImportError: + redis_found = False +else: + redis_found = True + + +# =========================================== +# 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 type(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( + action=dict(default=None, choices=['slave', 'flush']), + login_password=dict(default=None), + login_host=dict(default='localhost'), + login_port=dict(default='6379'), + master_host=dict(default=None), + master_port=dict(default=None), + slave_mode=dict(default='slave', choices=['master', 'slave']), + db=dict(default=None), + flush_mode=dict(default='all', choices=['all', 'db']), + ), + supports_check_mode = True + ) + + if not redis_found: + module.fail_json(msg="python redis module is required") + + login_password = module.params['login_password'] + login_host = module.params['login_host'] + login_port = int(module.params['login_port']) + action = module.params['action'] + + # Slave Command section ----------- + if action == "slave": + master_host = module.params['master_host'] + master_port = module.params['master_port'] + try: + master_port = int(module.params['master_port']) + except Exception: + pass + mode = module.params['slave_mode'] + + #Check if we ahve 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, e: + module.fail_json(msg="unable to connect to database: %s" % e) + + #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 = { + '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 actions so the actions aren't evaluated + # if not necesary) + 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 action == "flush": + try: + db = int(module.params['db']) + except Exception: + db = 0 + mode = module.params['flush_mode'] + + #Check if we have all the data + if mode == "db": + if type(db) != int: + 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, e: + module.fail_json(msg="unable to connect to database: %s" % e) + + # Do the stuff + # (Check Check_mode before actions so the actions aren't evaluated + # if not necesary) + 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) + + else: + module.fail_json(msg='A valid action must be provided') + +# this is magic, see lib/ansible/module_common.py +#<> +main()