From 4560e8fc7c99fe1ca267c70e0f49e5e42015fdfa Mon Sep 17 00:00:00 2001 From: Xabier Larrakoetxea Date: Mon, 15 Jul 2013 21:47:36 +0200 Subject: [PATCH 1/2] Added redis config module (slave and flush) --- library/database/redis | 281 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 library/database/redis diff --git a/library/database/redis b/library/database/redis new file mode 100644 index 00000000000..d43b9944916 --- /dev/null +++ b/library/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() From 8c25f98c433e56e5808ebbce4200bb397bfaba0d Mon Sep 17 00:00:00 2001 From: Xabier Larrakoetxea Date: Sat, 20 Jul 2013 18:39:18 +0200 Subject: [PATCH 2/2] Changed action keyword to command --- library/database/redis | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/library/database/redis b/library/database/redis index d43b9944916..d3ff5f7e7fb 100644 --- a/library/database/redis +++ b/library/database/redis @@ -26,9 +26,9 @@ description: 'flush' Flushes all the instance or ans specified db. version_added: "1.3" options: - action: + command: description: - - The selected redis action + - The selected redis command required: true default: null choices: [ "slave", "flush" ] @@ -49,29 +49,29 @@ options: default: 6379 master_host: description: - - The host of the master instance [slave action] + - The host of the master instance [slave command] required: false default: null master_port: description: - - The port of the master instance [slave action] + - The port of the master instance [slave command] required: false default: null slave_mode: description: - - the mode of the redis instance [slave action] + - the mode of the redis instance [slave command] required: false default: slave choices: [ "master", "slave" ] db: description: - - The database to flush (used in db mode) [flush action] + - The database to flush (used in db mode) [flush command] required: false default: null flush_mode: description: - Type of flush (all the dbs in a redis instance or a specific one) - [flush action] + [flush command] required: false default: all choices: [ "all", "db" ] @@ -90,16 +90,16 @@ 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 +- redis: command=slave master_host=melee.island master_port=6377 # Deactivate slave mode -- redis: action=slave slave_mode=master +- redis: command=slave slave_mode=master # Flush all the redis db -- redis: action=flush flush_mode=all +- redis: command=flush flush_mode=all # Flush only one db in a redis instance -- redis: action=flush db=1 flush_mode=db +- redis: command=flush db=1 flush_mode=db ''' try: @@ -146,7 +146,7 @@ def flush(client, db=None): def main(): module = AnsibleModule( argument_spec = dict( - action=dict(default=None, choices=['slave', 'flush']), + command=dict(default=None, choices=['slave', 'flush']), login_password=dict(default=None), login_host=dict(default='localhost'), login_port=dict(default='6379'), @@ -165,10 +165,10 @@ def main(): login_password = module.params['login_password'] login_host = module.params['login_host'] login_port = int(module.params['login_port']) - action = module.params['action'] + command = module.params['command'] # Slave Command section ----------- - if action == "slave": + if command == "slave": master_host = module.params['master_host'] master_port = module.params['master_port'] try: @@ -213,7 +213,7 @@ def main(): module.exit_json(changed=False, mode=status) else: # Do the stuff - # (Check Check_mode before actions so the actions aren't evaluated + # (Check Check_mode before commands so the commands aren't evaluated # if not necesary) if mode == "slave": if module.check_mode or\ @@ -235,7 +235,7 @@ def main(): module.fail_json(msg='Unable to set master mode') # flush Command section ----------- - elif action == "flush": + elif command == "flush": try: db = int(module.params['db']) except Exception: @@ -259,7 +259,7 @@ def main(): 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 + # (Check Check_mode before commands so the commands aren't evaluated # if not necesary) if mode == "all": if module.check_mode or flush(r): @@ -274,7 +274,7 @@ def main(): module.fail_json(msg="Unable to flush '%d' database" % db) else: - module.fail_json(msg='A valid action must be provided') + module.fail_json(msg='A valid command must be provided') # this is magic, see lib/ansible/module_common.py #<>