#!/usr/bin/env python DOCUMENTATION = """ --- module: mongodb_step_down short_description: Issues a stepdown on the primary. description: - Issues replSetStepDown on the host provided in host:. Afterwards, loops several times to ensure that a new primary is elected and that it is a different host than the previous primary. Errors if the stepdown fails or if the cluster fails to elect a new primary. version_added: "1.9" author: - Kevin Falcone options: host: description: - The hostname or ip of a server in the mongo cluster. required: false default: 'localhost' port: description: - The port to connect to mongo on. required: false default: 27017 username: description: - The username of the mongo user to connect as. required: false password: description: - The password to use when authenticating. required: false auth_database: description: - The database to authenticate against. required: false """ EXAMPLES = ''' - name: Get status for the stage cluster mongodb_step_down host: localhost:27017 username: root password: password ''' # Magic import from ansible.module_utils.basic import * try: from pymongo import MongoClient from pymongo.errors import AutoReconnect from bson import json_util except ImportError: pymongo_found = False else: pymongo_found = True import json from urllib import quote_plus def main(): arg_spec = dict( host=dict(required=False, type='str', default="localhost"), port=dict(required=False, type='int', default=27017), username=dict(required=False, type='str'), password=dict(required=False, type='str'), auth_database=dict(required=False, type='str') ) module = AnsibleModule(argument_spec=arg_spec, supports_check_mode=False) if not pymongo_found: module.fail_json(msg="The python pymongo module is not installed.") mongo_uri = 'mongodb://' host = module.params.get('host') port = module.params.get('port') username = module.params.get('username') password = module.params.get('password') auth_database = module.params.get('auth_database') if (username and not password) or (password and not username): module.fail_json(msg="Must provide both username and password or neither.") if username: mongo_uri += "{}:{}@".format(*map(quote_plus, [username,password])) mongo_uri += "{}:{}".format(quote_plus(host),port) if auth_database: mongo_uri += '/{}'.format(quote_plus(auth_database)) client = MongoClient(mongo_uri) # This has no return since it forces a disconnect or throws an error # about being unable to elect a secondary. We only catch the AutoReconnect # so we see any other errors bubble up. try: client.admin.command("replSetStepDown",60,secondaryCatchUpPeriodSecs=30) except AutoReconnect: pass for i in range(5): status = client.admin.command("replSetGetStatus") primary = [m for m in status['members'] if m['stateStr'] == 'PRIMARY'] # This won't work as well if you mix hostnames and IPs in your cluster. # We use only IPs. if primary and primary[0]['name'] != "{}:{}".format(quote_plus(host),port): module.exit_json(changed=True, stepdown=True) time.sleep(2) module.fail_json(msg="Unable to step down {}".format(host)) if __name__ == '__main__': main()