From eec0fb31de7c73c8556638a249789b6b0d7e7956 Mon Sep 17 00:00:00 2001 From: Ansible Core Team Date: Mon, 9 Mar 2020 09:40:30 +0000 Subject: Migrated to community.mongo --- .../modules/database/mongodb/mongodb_info.py | 444 ----------------- .../modules/database/mongodb/mongodb_parameter.py | 223 --------- .../modules/database/mongodb/mongodb_replicaset.py | 418 ---------------- .../modules/database/mongodb/mongodb_shard.py | 351 -------------- .../modules/database/mongodb/mongodb_user.py | 474 ------------------ lib/ansible/plugins/cache/mongodb.py | 181 ------- lib/ansible/plugins/lookup/mongodb.py | 238 --------- test/integration/targets/mongodb_info/aliases | 5 - .../targets/mongodb_info/defaults/main.yml | 4 - .../integration/targets/mongodb_info/meta/main.yml | 3 - .../targets/mongodb_info/tasks/main.yml | 8 - .../targets/mongodb_info/tasks/mongodb_info.yml | 60 --- test/integration/targets/mongodb_parameter/aliases | 7 - .../targets/mongodb_parameter/defaults/main.yml | 21 - .../targets/mongodb_parameter/meta/main.yml | 3 - .../targets/mongodb_parameter/tasks/main.yml | 143 ------ .../mongodb_parameter/tasks/mongod_singlenode.yml | 55 --- .../mongodb_parameter/tasks/mongod_teardown.yml | 25 - .../integration/targets/mongodb_replicaset/aliases | 7 - .../targets/mongodb_replicaset/defaults/main.yml | 24 - .../mongodb_replicaset/files/js/is_primary.js | 13 - .../targets/mongodb_replicaset/meta/main.yml | 3 - .../targets/mongodb_replicaset/tasks/main.yml | 540 --------------------- .../mongodb_replicaset/tasks/mongod_replicaset.yml | 43 -- .../mongodb_replicaset/tasks/mongod_teardown.yml | 27 -- test/integration/targets/mongodb_shard/aliases | 7 - .../targets/mongodb_shard/defaults/main.yml | 16 - .../mongodb_shard/files/bash/ensure_primary.sh.j2 | 38 -- .../targets/mongodb_shard/files/js/is_primary.js | 13 - .../targets/mongodb_shard/meta/main.yml | 3 - .../targets/mongodb_shard/tasks/main.yml | 458 ----------------- .../mongodb_shard/tasks/mongod_replicaset.yml | 51 -- .../mongodb_shard/tasks/mongod_teardown.yml | 35 -- .../templates/create_user_root_3.2.js.j2 | 8 - test/integration/targets/mongodb_user/aliases | 8 - .../targets/mongodb_user/defaults/main.yml | 21 - .../targets/mongodb_user/files/js/is_primary.js | 13 - .../integration/targets/mongodb_user/meta/main.yml | 3 - .../targets/mongodb_user/tasks/main.yml | 226 --------- .../mongodb_user/tasks/mongod_replicaset.yml | 51 -- .../targets/mongodb_user/tasks/mongod_teardown.yml | 27 -- test/sanity/ignore.txt | 4 - 42 files changed, 4302 deletions(-) delete mode 100644 lib/ansible/modules/database/mongodb/mongodb_info.py delete mode 100644 lib/ansible/modules/database/mongodb/mongodb_parameter.py delete mode 100644 lib/ansible/modules/database/mongodb/mongodb_replicaset.py delete mode 100644 lib/ansible/modules/database/mongodb/mongodb_shard.py delete mode 100644 lib/ansible/modules/database/mongodb/mongodb_user.py delete mode 100644 lib/ansible/plugins/cache/mongodb.py delete mode 100644 lib/ansible/plugins/lookup/mongodb.py delete mode 100644 test/integration/targets/mongodb_info/aliases delete mode 100644 test/integration/targets/mongodb_info/defaults/main.yml delete mode 100644 test/integration/targets/mongodb_info/meta/main.yml delete mode 100644 test/integration/targets/mongodb_info/tasks/main.yml delete mode 100644 test/integration/targets/mongodb_info/tasks/mongodb_info.yml delete mode 100644 test/integration/targets/mongodb_parameter/aliases delete mode 100644 test/integration/targets/mongodb_parameter/defaults/main.yml delete mode 100644 test/integration/targets/mongodb_parameter/meta/main.yml delete mode 100644 test/integration/targets/mongodb_parameter/tasks/main.yml delete mode 100644 test/integration/targets/mongodb_parameter/tasks/mongod_singlenode.yml delete mode 100644 test/integration/targets/mongodb_parameter/tasks/mongod_teardown.yml delete mode 100644 test/integration/targets/mongodb_replicaset/aliases delete mode 100644 test/integration/targets/mongodb_replicaset/defaults/main.yml delete mode 100644 test/integration/targets/mongodb_replicaset/files/js/is_primary.js delete mode 100644 test/integration/targets/mongodb_replicaset/meta/main.yml delete mode 100644 test/integration/targets/mongodb_replicaset/tasks/main.yml delete mode 100644 test/integration/targets/mongodb_replicaset/tasks/mongod_replicaset.yml delete mode 100644 test/integration/targets/mongodb_replicaset/tasks/mongod_teardown.yml delete mode 100644 test/integration/targets/mongodb_shard/aliases delete mode 100644 test/integration/targets/mongodb_shard/defaults/main.yml delete mode 100644 test/integration/targets/mongodb_shard/files/bash/ensure_primary.sh.j2 delete mode 100644 test/integration/targets/mongodb_shard/files/js/is_primary.js delete mode 100644 test/integration/targets/mongodb_shard/meta/main.yml delete mode 100644 test/integration/targets/mongodb_shard/tasks/main.yml delete mode 100644 test/integration/targets/mongodb_shard/tasks/mongod_replicaset.yml delete mode 100644 test/integration/targets/mongodb_shard/tasks/mongod_teardown.yml delete mode 100644 test/integration/targets/mongodb_shard/templates/create_user_root_3.2.js.j2 delete mode 100644 test/integration/targets/mongodb_user/aliases delete mode 100644 test/integration/targets/mongodb_user/defaults/main.yml delete mode 100644 test/integration/targets/mongodb_user/files/js/is_primary.js delete mode 100644 test/integration/targets/mongodb_user/meta/main.yml delete mode 100644 test/integration/targets/mongodb_user/tasks/main.yml delete mode 100644 test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml delete mode 100644 test/integration/targets/mongodb_user/tasks/mongod_teardown.yml diff --git a/lib/ansible/modules/database/mongodb/mongodb_info.py b/lib/ansible/modules/database/mongodb/mongodb_info.py deleted file mode 100644 index 97bb468401..0000000000 --- a/lib/ansible/modules/database/mongodb/mongodb_info.py +++ /dev/null @@ -1,444 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright: (c) 2020, Andrew Klychkov (@Andersson007) -# 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 = r''' ---- -module: mongodb_info - -short_description: Gather information about MongoDB instance. - -description: -- Gather information about MongoDB instance. - -author: Andrew Klychkov (@Andersson007) - -version_added: '2.10' - -options: - filter: - description: - - Limit the collected information by comma separated string or YAML list. - - Allowable values are C(general), C(databases), C(total_size), C(parameters), C(users), C(roles). - - By default, collects all subsets. - - You can use '!' before value (for example, C(!users)) to exclude it from the information. - - If you pass including and excluding values to the filter, for example, I(filter=!general,users), - the excluding values, C(!general) in this case, will be ignored. - required: no - type: list - elements: str - login_user: - description: - - The MongoDB user to login with. - - Required when I(login_password) is specified. - required: no - type: str - login_password: - description: - - The password used to authenticate with. - - Required when I(login_user) is specified. - required: no - type: str - login_database: - description: - - The database where login credentials are stored. - required: no - type: str - default: 'admin' - login_host: - description: - - The host running MongoDB instance to login to. - required: no - type: str - default: 'localhost' - login_port: - description: - - The MongoDB server port to login to. - required: no - type: int - default: 27017 - ssl: - description: - - Whether to use an SSL connection when connecting to the database. - required: no - type: bool - default: no - ssl_cert_reqs: - description: - - Specifies whether a certificate is required from the other side of the connection, - and whether it will be validated if provided. - required: no - type: str - default: 'CERT_REQUIRED' - choices: ['CERT_NONE', 'CERT_OPTIONAL', 'CERT_REQUIRED'] - -notes: - - Requires the pymongo Python package on the remote host, version 2.4.2+. - -requirements: [ 'pymongo' ] -''' - -EXAMPLES = r''' -- name: Gather all supported information - mongodb_info: - login_user: admin - login_password: secret - register: result - -- name: Show gathered info - debug: - msg: '{{ result }}' - -- name: Gather only information about databases and their total size - mongodb_info: - login_user: admin - login_password: secret - filter: databases, total_size - -- name: Gather all information except parameters - mongodb_info: - login_user: admin - login_password: secret - filter: '!parameters' -''' - -RETURN = r''' -general: - description: General instance information. - returned: always - type: dict - sample: {"allocator": "tcmalloc", "bits": 64, "storageEngines": ["biggie"], "version": "4.2.3", "maxBsonObjectSize": 16777216} -databases: - description: Database information. - returned: always - type: dict - sample: {"admin": {"empty": false, "sizeOnDisk": 245760}, "config": {"empty": false, "sizeOnDisk": 110592}} -total_size: - description: Total size of all databases in bytes. - returned: always - type: int - sample: 397312 -users: - description: User information. - returned: always - type: dict - sample: {"new_user": {"_id": "config.new_user", "db": "config", "mechanisms": ["SCRAM-SHA-1", "SCRAM-SHA-256"], "roles": []}} -roles: - description: Role information. - returned: always - type: dict - sample: {"restore": {"db": "admin", "inheritedRoles": [], "isBuiltin": true, "roles": []}} -parameters: - description: Server parameters information. - returned: always - type: dict - sample: {"maxOplogTruncationPointsAfterStartup": 100, "maxOplogTruncationPointsDuringStartup": 100, "maxSessions": 1000000} -''' - -import traceback - -from uuid import UUID - -import ssl as ssl_lib -from distutils.version import LooseVersion - -PYMONGO_IMP_ERR = None -try: - from pymongo import version as PyMongoVersion - from pymongo import MongoClient -except ImportError: - PYMONGO_IMP_ERR = traceback.format_exc() - pymongo_found = False -else: - pymongo_found = True - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils._text import to_native -from ansible.module_utils.six import iteritems - - -# ========================================= -# MongoDB module specific support methods. -# - -def check_compatibility(module, srv_version, driver_version): - """Check the compatibility between the driver and the database. - - See: https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#python-driver-compatibility - - Args: - module: Ansible module. - srv_version (LooseVersion): MongoDB server version. - driver_version (LooseVersion): Pymongo version. - """ - msg = 'pymongo driver version and MongoDB version are incompatible: ' - - if srv_version >= LooseVersion('4.2') and driver_version < LooseVersion('3.9'): - msg += 'you must use pymongo 3.9+ with MongoDB >= 4.2' - module.fail_json(msg=msg) - - elif srv_version >= LooseVersion('4.0') and driver_version < LooseVersion('3.7'): - msg += 'you must use pymongo 3.7+ with MongoDB >= 4.0' - module.fail_json(msg=msg) - - elif srv_version >= LooseVersion('3.6') and driver_version < LooseVersion('3.6'): - msg += 'you must use pymongo 3.6+ with MongoDB >= 3.6' - module.fail_json(msg=msg) - - elif srv_version >= LooseVersion('3.4') and driver_version < LooseVersion('3.4'): - msg += 'you must use pymongo 3.4+ with MongoDB >= 3.4' - module.fail_json(msg=msg) - - elif srv_version >= LooseVersion('3.2') and driver_version < LooseVersion('3.2'): - msg += 'you must use pymongo 3.2+ with MongoDB >= 3.2' - module.fail_json(msg=msg) - - elif srv_version >= LooseVersion('3.0') and driver_version <= LooseVersion('2.8'): - msg += 'you must use pymongo 2.8+ with MongoDB 3.0' - module.fail_json(msg=msg) - - elif srv_version >= LooseVersion('2.6') and driver_version <= LooseVersion('2.7'): - msg += 'you must use pymongo 2.7+ with MongoDB 2.6' - module.fail_json(msg=msg) - - -class MongoDbInfo(): - """Class for gathering MongoDB instance information. - - Args: - module (AnsibleModule): Object of AnsibleModule class. - client (pymongo): pymongo client object to interact with the database. - """ - def __init__(self, module, client): - self.module = module - self.client = client - self.admin_db = self.client.admin - self.info = { - 'general': {}, - 'databases': {}, - 'total_size': {}, - 'parameters': {}, - 'users': {}, - 'roles': {}, - } - - def get_info(self, filter_): - """Get MongoDB instance information and return it based on filter_. - - Args: - filter_ (list): List of collected subsets (e.g., general, users, etc.), - when it is empty, return all available information. - """ - self.__collect() - - inc_list = [] - exc_list = [] - - if filter_: - partial_info = {} - - for fi in filter_: - if fi.lstrip('!') not in self.info: - self.module.warn("filter element '%s' is not allowable, ignored" % fi) - continue - - if fi[0] == '!': - exc_list.append(fi.lstrip('!')) - - else: - inc_list.append(fi) - - if inc_list: - for i in self.info: - if i in inc_list: - partial_info[i] = self.info[i] - - else: - for i in self.info: - if i not in exc_list: - partial_info[i] = self.info[i] - - return partial_info - - else: - return self.info - - def __collect(self): - """Collect information.""" - # Get general info: - self.info['general'] = self.client.server_info() - - # Get parameters: - self.info['parameters'] = self.get_parameters_info() - - # Gather info about databases and their total size: - self.info['databases'], self.info['total_size'] = self.get_db_info() - - for dbname, val in iteritems(self.info['databases']): - # Gather info about users for each database: - self.info['users'].update(self.get_users_info(dbname)) - - # Gather info about roles for each database: - self.info['roles'].update(self.get_roles_info(dbname)) - - def get_roles_info(self, dbname): - """Gather information about roles. - - Args: - dbname (str): Database name to get role info from. - - Returns a dictionary with role information. - """ - db = self.client[dbname] - result = db.command({'rolesInfo': 1, 'showBuiltinRoles': True})['roles'] - - roles_dict = {} - for elem in result: - roles_dict[elem['role']] = {} - for key, val in iteritems(elem): - if key == 'role': - continue - - roles_dict[elem['role']][key] = val - - return roles_dict - - def get_users_info(self, dbname): - """Gather information about users. - - Args: - dbname (str): Database name to get user info from. - - Returns a dictionary with user information. - """ - db = self.client[dbname] - result = db.command({'usersInfo': 1})['users'] - - users_dict = {} - for elem in result: - users_dict[elem['user']] = {} - for key, val in iteritems(elem): - if key == 'user': - continue - - if isinstance(val, UUID): - val = val.hex - - users_dict[elem['user']][key] = val - - return users_dict - - def get_db_info(self): - """Gather information about databases. - - Returns a dictionary with database information. - """ - result = self.admin_db.command({'listDatabases': 1}) - total_size = int(result['totalSize']) - result = result['databases'] - - db_dict = {} - for elem in result: - db_dict[elem['name']] = {} - for key, val in iteritems(elem): - if key == 'name': - continue - - if key == 'sizeOnDisk': - val = int(val) - - db_dict[elem['name']][key] = val - - return db_dict, total_size - - def get_parameters_info(self): - """Gather parameters information. - - Returns a dictionary with parameters. - """ - return self.admin_db.command({'getParameter': '*'}) - - -# ================ -# Module execution -# - -def main(): - argument_spec = dict( - login_user=dict(type='str', required=False), - login_password=dict(type='str', required=False, no_log=True), - login_database=dict(type='str', required=False, default='admin'), - login_host=dict(type='str', required=False, default='localhost'), - login_port=dict(type='int', required=False, default=27017), - ssl=dict(type='bool', required=False, default=False), - ssl_cert_reqs=dict(type='str', required=False, default='CERT_REQUIRED', - choices=['CERT_NONE', 'CERT_OPTIONAL', 'CERT_REQUIRED']), - filter=dict(type='list', elements='str', required=False), - ) - - module = AnsibleModule( - argument_spec=argument_spec, - supports_check_mode=True, - required_together=[['login_user', 'login_password']], - ) - - if not pymongo_found: - module.fail_json(msg=missing_required_lib('pymongo'), exception=PYMONGO_IMP_ERR) - - login_user = module.params['login_user'] - login_password = module.params['login_password'] - login_database = module.params['login_database'] - login_host = module.params['login_host'] - login_port = module.params['login_port'] - ssl = module.params['ssl'] - filter_ = module.params['filter'] - - if filter_: - filter_ = [f.strip() for f in filter_] - - connection_params = { - 'host': login_host, - 'port': login_port, - } - - if ssl: - connection_params['ssl'] = ssl - connection_params['ssl_cert_reqs'] = getattr(ssl_lib, module.params['ssl_cert_reqs']) - - client = MongoClient(**connection_params) - - if login_user: - try: - client.admin.authenticate(login_user, login_password, source=login_database) - except Exception as e: - module.fail_json(msg='Unable to authenticate: %s' % to_native(e)) - - # Get server version: - try: - srv_version = LooseVersion(client.server_info()['version']) - except Exception as e: - module.fail_json(msg='Unable to get MongoDB server version: %s' % to_native(e)) - - # Get driver version:: - driver_version = LooseVersion(PyMongoVersion) - - # Check driver and server version compatibility: - check_compatibility(module, srv_version, driver_version) - - # Initialize an object and start main work: - mongodb = MongoDbInfo(module, client) - - module.exit_json(changed=False, **mongodb.get_info(filter_)) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/database/mongodb/mongodb_parameter.py b/lib/ansible/modules/database/mongodb/mongodb_parameter.py deleted file mode 100644 index 05de42b2ea..0000000000 --- a/lib/ansible/modules/database/mongodb/mongodb_parameter.py +++ /dev/null @@ -1,223 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# (c) 2016, Loic Blot -# Sponsored by Infopro Digital. http://www.infopro-digital.com/ -# Sponsored by E.T.A.I. http://www.etai.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 = r''' ---- -module: mongodb_parameter -short_description: Change an administrative parameter on a MongoDB server -description: - - Change an administrative parameter on a MongoDB server. -version_added: "2.1" -options: - login_user: - description: - - The MongoDB username used to authenticate with. - type: str - login_password: - description: - - The login user's password used to authenticate with. - type: str - login_host: - description: - - The host running the database. - type: str - default: localhost - login_port: - description: - - The MongoDB port to connect to. - default: 27017 - type: int - login_database: - description: - - The database where login credentials are stored. - type: str - replica_set: - description: - - Replica set to connect to (automatically connects to primary for writes). - type: str - ssl: - description: - - Whether to use an SSL connection when connecting to the database. - type: bool - default: no - param: - description: - - MongoDB administrative parameter to modify. - type: str - required: true - value: - description: - - MongoDB administrative parameter value to set. - type: str - required: true - param_type: - description: - - Define the type of parameter value. - default: str - type: str - choices: [int, str] - -notes: - - Requires the pymongo Python package on the remote host, version 2.4.2+. - - This can be installed using pip or the OS package manager. - - See also U(http://api.mongodb.org/python/current/installation.html) -requirements: [ "pymongo" ] -author: "Loic Blot (@nerzhul)" -''' - -EXAMPLES = r''' -- name: Set MongoDB syncdelay to 60 (this is an int) - mongodb_parameter: - param: syncdelay - value: 60 - param_type: int -''' - -RETURN = r''' -before: - description: value before modification - returned: success - type: str -after: - description: value after modification - returned: success - type: str -''' - -import os -import traceback - -try: - from pymongo.errors import ConnectionFailure - from pymongo.errors import OperationFailure - from pymongo import version as PyMongoVersion - from pymongo import MongoClient -except ImportError: - try: # for older PyMongo 2.2 - from pymongo import Connection as MongoClient - except ImportError: - pymongo_found = False - else: - pymongo_found = True -else: - pymongo_found = True - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils.six.moves import configparser -from ansible.module_utils._text import to_native - - -# ========================================= -# MongoDB module specific support methods. -# - -def load_mongocnf(): - config = configparser.RawConfigParser() - mongocnf = os.path.expanduser('~/.mongodb.cnf') - - try: - config.readfp(open(mongocnf)) - creds = dict( - user=config.get('client', 'user'), - password=config.get('client', 'pass') - ) - except (configparser.NoOptionError, IOError): - return False - - return creds - - -# ========================================= -# Module execution. -# - -def main(): - module = AnsibleModule( - argument_spec=dict( - login_user=dict(default=None), - login_password=dict(default=None, no_log=True), - login_host=dict(default='localhost'), - login_port=dict(default=27017, type='int'), - login_database=dict(default=None), - replica_set=dict(default=None), - param=dict(required=True), - value=dict(required=True), - param_type=dict(default="str", choices=['str', 'int']), - ssl=dict(default=False, type='bool'), - ) - ) - - if not pymongo_found: - module.fail_json(msg=missing_required_lib('pymongo')) - - login_user = module.params['login_user'] - login_password = module.params['login_password'] - login_host = module.params['login_host'] - login_port = module.params['login_port'] - login_database = module.params['login_database'] - - replica_set = module.params['replica_set'] - ssl = module.params['ssl'] - - param = module.params['param'] - param_type = module.params['param_type'] - value = module.params['value'] - - # Verify parameter is coherent with specified type - try: - if param_type == 'int': - value = int(value) - except ValueError: - module.fail_json(msg="value '%s' is not %s" % (value, param_type)) - - try: - if replica_set: - client = MongoClient(login_host, int(login_port), replicaset=replica_set, ssl=ssl) - else: - client = MongoClient(login_host, int(login_port), ssl=ssl) - - if login_user is None and login_password is None: - mongocnf_creds = load_mongocnf() - if mongocnf_creds is not False: - login_user = mongocnf_creds['user'] - login_password = mongocnf_creds['password'] - elif login_password is None or login_user is None: - module.fail_json(msg='when supplying login arguments, both login_user and login_password must be provided') - - if login_user is not None and login_password is not None: - client.admin.authenticate(login_user, login_password, source=login_database) - - except ConnectionFailure as e: - module.fail_json(msg='unable to connect to database: %s' % to_native(e), exception=traceback.format_exc()) - - db = client.admin - - try: - after_value = db.command("setParameter", **{param: value}) - except OperationFailure as e: - module.fail_json(msg="unable to change parameter: %s" % to_native(e), exception=traceback.format_exc()) - - if "was" not in after_value: - module.exit_json(changed=True, msg="Unable to determine old value, assume it changed.") - else: - module.exit_json(changed=(value != after_value["was"]), before=after_value["was"], - after=value) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/database/mongodb/mongodb_replicaset.py b/lib/ansible/modules/database/mongodb/mongodb_replicaset.py deleted file mode 100644 index 090724dd88..0000000000 --- a/lib/ansible/modules/database/mongodb/mongodb_replicaset.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/python - -# Copyright: (c) 2018, Rhys Campbell -# 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 = r''' ---- -module: mongodb_replicaset -short_description: Initialises a MongoDB replicaset -description: -- Initialises a MongoDB replicaset in a new deployment. -- Validates the replicaset name for existing deployments. -author: Rhys Campbell (@rhysmeister) -version_added: "2.8" -options: - login_user: - description: - - The username to authenticate with. - type: str - login_password: - description: - - The password to authenticate with. - type: str - login_database: - description: - - The database where login credentials are stored. - type: str - default: admin - login_host: - description: - - The MongoDB hostname. - type: str - default: localhost - login_port: - description: - - The MongoDB port to login to. - type: int - default: 27017 - replica_set: - description: - - Replicaset name. - type: str - default: rs0 - members: - description: - - A comma-separated string or a yaml list consisting of the replicaset members. - - Supply as a simple csv string, i.e. mongodb1:27017,mongodb2:27017,mongodb3:27017. - - If a port number is not provided then 27017 is assumed. - type: list - elements: raw - validate: - description: - - Performs some basic validation on the provided replicaset config. - type: bool - default: yes - ssl: - description: - - Whether to use an SSL connection when connecting to the database - type: bool - default: no - ssl_cert_reqs: - description: - - Specifies whether a certificate is required from the other side of the connection, and whether it will be validated if provided. - type: str - default: CERT_REQUIRED - choices: [ CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED ] - arbiter_at_index: - description: - - Identifies the position of the member in the array that is an arbiter. - type: int - chaining_allowed: - description: - - When I(settings.chaining_allowed=true), the replicaset allows secondary members to replicate from other - secondary members. - - When I(settings.chaining_allowed=false), secondaries can replicate only from the primary. - type: bool - default: yes - heartbeat_timeout_secs: - description: - - Number of seconds that the replicaset members wait for a successful heartbeat from each other. - - If a member does not respond in time, other members mark the delinquent member as inaccessible. - - The setting only applies when using I(protocol_version=0). When using I(protocol_version=1) the relevant - setting is I(settings.election_timeout_millis). - type: int - default: 10 - election_timeout_millis: - description: - - The time limit in milliseconds for detecting when a replicaset's primary is unreachable. - type: int - default: 10000 - protocol_version: - description: Version of the replicaset election protocol. - type: int - choices: [ 0, 1 ] - default: 1 -notes: -- Requires the pymongo Python package on the remote host, version 2.4.2+. This - can be installed using pip or the OS package manager. @see U(http://api.mongodb.org/python/current/installation.html) -requirements: -- pymongo -''' - -EXAMPLES = r''' -# Create a replicaset called 'rs0' with the 3 provided members -- name: Ensure replicaset rs0 exists - mongodb_replicaset: - login_host: localhost - login_user: admin - login_password: admin - replica_set: rs0 - members: - - mongodb1:27017 - - mongodb2:27017 - - mongodb3:27017 - when: groups.mongod.index(inventory_hostname) == 0 - -# Create two single-node replicasets on the localhost for testing -- name: Ensure replicaset rs0 exists - mongodb_replicaset: - login_host: localhost - login_port: 3001 - login_user: admin - login_password: secret - login_database: admin - replica_set: rs0 - members: localhost:3001 - validate: no - -- name: Ensure replicaset rs1 exists - mongodb_replicaset: - login_host: localhost - login_port: 3002 - login_user: admin - login_password: secret - login_database: admin - replica_set: rs1 - members: localhost:3002 - validate: no -''' - -RETURN = r''' -mongodb_replicaset: - description: The name of the replicaset that has been created. - returned: success - type: str -''' - -from copy import deepcopy - -import os -import ssl as ssl_lib -from distutils.version import LooseVersion - -try: - from pymongo.errors import ConnectionFailure - from pymongo.errors import OperationFailure - from pymongo import version as PyMongoVersion - from pymongo import MongoClient - HAS_PYMONGO = True -except ImportError: - try: # for older PyMongo 2.2 - from pymongo import Connection as MongoClient - HAS_PYMONGO = True - except ImportError: - HAS_PYMONGO = False - -from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import binary_type, text_type -from ansible.module_utils.six.moves import configparser -from ansible.module_utils._text import to_native - - -# ========================================= -# MongoDB module specific support methods. -# - -def check_compatibility(module, client): - """Check the compatibility between the driver and the database. - - See: https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#python-driver-compatibility - - Args: - module: Ansible module. - client (cursor): Mongodb cursor on admin database. - """ - loose_srv_version = LooseVersion(client.server_info()['version']) - loose_driver_version = LooseVersion(PyMongoVersion) - - if loose_srv_version >= LooseVersion('3.2') and loose_driver_version < LooseVersion('3.2'): - module.fail_json(msg=' (Note: you must use pymongo 3.2+ with MongoDB >= 3.2)') - - elif loose_srv_version >= LooseVersion('3.0') and loose_driver_version <= LooseVersion('2.8'): - module.fail_json(msg=' (Note: you must use pymongo 2.8+ with MongoDB 3.0)') - - elif loose_srv_version >= LooseVersion('2.6') and loose_driver_version <= LooseVersion('2.7'): - module.fail_json(msg=' (Note: you must use pymongo 2.7+ with MongoDB 2.6)') - - elif LooseVersion(PyMongoVersion) <= LooseVersion('2.5'): - module.fail_json(msg=' (Note: you must be on mongodb 2.4+ and pymongo 2.5+ to use the roles param)') - - -def replicaset_find(client): - """Check if a replicaset exists. - - Args: - client (cursor): Mongodb cursor on admin database. - replica_set (str): replica_set to check. - - Returns: - dict: when user exists, False otherwise. - """ - for rs in client["local"].system.replset.find({}): - return rs["_id"] - return False - - -def replicaset_add(module, client, replica_set, members, arbiter_at_index, protocol_version, - chaining_allowed, heartbeat_timeout_secs, election_timeout_millis): - - try: - from collections import OrderedDict - except ImportError as excep: - try: - from ordereddict import OrderedDict - except ImportError as excep: - module.fail_json(msg='Cannot import OrderedDict class. You can probably install with: pip install ordereddict: %s' - % to_native(excep)) - - members_dict_list = [] - index = 0 - settings = { - "chainingAllowed": bool(chaining_allowed), - } - if protocol_version == 0: - settings['heartbeatTimeoutSecs'] = heartbeat_timeout_secs - else: - settings['electionTimeoutMillis'] = election_timeout_millis - for member in members: - if ':' not in member: # No port supplied. Assume 27017 - member += ":27017" - members_dict_list.append(OrderedDict([("_id", index), ("host", member)])) - if index == arbiter_at_index: - members_dict_list[index]['arbiterOnly'] = True - index += 1 - - conf = OrderedDict([("_id", replica_set), - ("protocolVersion", protocol_version), - ("members", members_dict_list), - ("settings", settings)]) - client["admin"].command('replSetInitiate', conf) - - -def replicaset_remove(module, client, replica_set): - raise NotImplementedError - # exists = replicaset_find(client, replica_set) - # if exists: - # if module.check_mode: - # module.exit_json(changed=True, replica_set=replica_set) - # db = client[db_name] - # db.remove_user(replica_set) - # else: - # module.exit_json(changed=False, user=user) - - -def load_mongocnf(): - config = configparser.RawConfigParser() - mongocnf = os.path.expanduser('~/.mongodb.cnf') - - try: - config.readfp(open(mongocnf)) - except (configparser.NoOptionError, IOError): - return False - - creds = dict( - user=config.get('client', 'user'), - password=config.get('client', 'pass') - ) - - return creds - - -# ========================================= -# Module execution. -# - - -def main(): - module = AnsibleModule( - argument_spec=dict( - login_user=dict(type='str'), - login_password=dict(type='str', no_log=True), - login_database=dict(type='str', default="admin"), - login_host=dict(type='str', default="localhost"), - login_port=dict(type='int', default=27017), - replica_set=dict(type='str', default="rs0"), - members=dict(type='list', elements='raw'), - arbiter_at_index=dict(type='int'), - validate=dict(type='bool', default=True), - ssl=dict(type='bool', default=False), - ssl_cert_reqs=dict(type='str', default='CERT_REQUIRED', choices=['CERT_NONE', 'CERT_OPTIONAL', 'CERT_REQUIRED']), - protocol_version=dict(type='int', default=1, choices=[0, 1]), - chaining_allowed=dict(type='bool', default=True), - heartbeat_timeout_secs=dict(type='int', default=10), - election_timeout_millis=dict(type='int', default=10000) - ), - supports_check_mode=True, - ) - - if not HAS_PYMONGO: - module.fail_json(msg='the python pymongo module is required') - - login_user = module.params['login_user'] - login_password = module.params['login_password'] - login_database = module.params['login_database'] - login_host = module.params['login_host'] - login_port = module.params['login_port'] - replica_set = module.params['replica_set'] - members = module.params['members'] - arbiter_at_index = module.params['arbiter_at_index'] - validate = module.params['validate'] - ssl = module.params['ssl'] - protocol_version = module.params['protocol_version'] - chaining_allowed = module.params['chaining_allowed'] - heartbeat_timeout_secs = module.params['heartbeat_timeout_secs'] - election_timeout_millis = module.params['election_timeout_millis'] - - if validate: - if len(members) <= 2 or len(members) % 2 == 0: - module.fail_json(msg="MongoDB Replicaset validation failed. Invalid number of replicaset members.") - if arbiter_at_index is not None and len(members) - 1 < arbiter_at_index: - module.fail_json(msg="MongoDB Replicaset validation failed. Invalid arbiter index.") - - result = dict( - changed=False, - replica_set=replica_set, - ) - - connection_params = dict( - host=login_host, - port=int(login_port), - ) - - if ssl: - connection_params["ssl"] = ssl - connection_params["ssl_cert_reqs"] = getattr(ssl_lib, module.params['ssl_cert_reqs']) - - try: - client = MongoClient(**connection_params) - except Exception as e: - module.fail_json(msg='Unable to connect to database: %s' % to_native(e)) - - try: - check_compatibility(module, client) - except Exception as excep: - if "not authorized on" not in str(excep) and "there are no users authenticated" not in str(excep): - raise excep - if login_user is None or login_password is None: - raise excep - client.admin.authenticate(login_user, login_password, source=login_database) - check_compatibility(module, client) - - if login_user is None and login_password is None: - mongocnf_creds = load_mongocnf() - if mongocnf_creds is not False: - login_user = mongocnf_creds['user'] - login_password = mongocnf_creds['password'] - elif login_password is None or login_user is None: - module.fail_json(msg="When supplying login arguments, both 'login_user' and 'login_password' must be provided") - - try: - client['admin'].command('listDatabases', 1.0) # if this throws an error we need to authenticate - except Exception as excep: - if "not authorized on" in str(excep) or "command listDatabases requires authentication" in str(excep): - if login_user is not None and login_password is not None: - client.admin.authenticate(login_user, login_password, source=login_database) - else: - raise excep - else: - raise excep - - if len(replica_set) == 0: - module.fail_json(msg="Parameter 'replica_set' must not be an empty string") - - try: - rs = replicaset_find(client) - except Exception as e: - module.fail_json(msg='Unable to query replica_set info: %s' % to_native(e)) - - if not rs: - if not module.check_mode: - try: - replicaset_add(module, client, replica_set, members, arbiter_at_index, protocol_version, - chaining_allowed, heartbeat_timeout_secs, election_timeout_millis) - result['changed'] = True - except Exception as e: - module.fail_json(msg='Unable to create replica_set: %s' % to_native(e)) - else: - if not module.check_mode: - try: - rs = replicaset_find(client) - except Exception as e: - module.fail_json(msg='Unable to query replica_set info: %s' % to_native(e)) - if rs is not None and rs != replica_set: - module.fail_json(msg="The replica_set name of '{0}' does not match the expected: '{1}'".format(rs, replica_set)) - result['changed'] = False - - module.exit_json(**result) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/database/mongodb/mongodb_shard.py b/lib/ansible/modules/database/mongodb/mongodb_shard.py deleted file mode 100644 index 96c652e799..0000000000 --- a/lib/ansible/modules/database/mongodb/mongodb_shard.py +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/python - -# (c) 2018, Rhys Campbell -# 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: mongodb_shard -short_description: Add or remove shards from a MongoDB Cluster -description: - - Add or remove shards from a MongoDB Cluster. -author: Rhys Campbell (@rhysmeister) -version_added: "2.8" -options: - login_user: - description: - - The MongoDB user to login with. - required: false - type: str - login_password: - description: - - The login user's password used to authenticate with. - required: false - type: str - login_database: - description: - - The database where login credentials are stored. - required: false - type: str - default: admin - login_host: - description: - - The host to login to. - - This must be a mongos. - required: false - type: str - default: localhost - login_port: - description: - - The MongoDB port to login to. - required: false - type: int - default: 27017 - shard: - description: - - The shard connection string. - - Should be supplied in the form /host:port as detailed - in U(https://docs.mongodb.com/manual/tutorial/add-shards-to-shard-cluster/). - - For example rs0/example1.mongodb.com:27017. - required: true - type: str - ssl: - description: - - Whether to use an SSL connection when connecting to the database. - default: False - type: bool - ssl_cert_reqs: - description: - - Specifies whether a certificate is required from the other side of the connection, - and whether it will be validated if provided. - required: false - type: str - default: CERT_REQUIRED - choices: [CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED] - state: - description: - - Whether the shard should be present or absent from the Cluster. - required: false - type: str - default: present - choices: [absent, present] - -notes: - - Requires the pymongo Python package on the remote host, version 2.4.2+. - -requirements: [ pymongo ] -''' - -EXAMPLES = ''' -- name: Add a replicaset shard named rs1 with a member running on port 27018 on mongodb0.example.net - mongodb_shard: - login_user: admin - login_password: admin - shard: "rs1/mongodb0.example.net:27018" - state: present - -- name: Add a standalone mongod shard running on port 27018 of mongodb0.example.net - mongodb_shard: - login_user: admin - login_password: admin - shard: "mongodb0.example.net:27018" - state: present - -- name: To remove a shard called 'rs1' - mongodb_shard: - login_user: admin - login_password: admin - shard: rs1 - state: absent - -# Single node shard running on localhost -- name: Ensure shard rs0 exists - mongodb_shard: - login_user: admin - login_password: secret - shard: "rs0/localhost:3001" - state: present - -# Single node shard running on localhost -- name: Ensure shard rs1 exists - mongodb_shard: - login_user: admin - login_password: secret - shard: "rs1/localhost:3002" - state: present -''' - -RETURN = ''' -mongodb_shard: - description: The name of the shard to create. - returned: success - type: str -''' - -import os -import ssl as ssl_lib -import traceback -from distutils.version import LooseVersion - -try: - from pymongo.errors import ConnectionFailure - from pymongo.errors import OperationFailure - from pymongo import version as PyMongoVersion - from pymongo import MongoClient -except ImportError: - try: # for older PyMongo 2.2 - from pymongo import Connection as MongoClient - except ImportError: - pymongo_found = False - else: - pymongo_found = True -else: - pymongo_found = True - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils.six import binary_type, text_type -from ansible.module_utils.six.moves import configparser -from ansible.module_utils._text import to_native - - -# ========================================= -# MongoDB module specific support methods. -# - -def check_compatibility(module, client): - """Check the compatibility between the driver and the database. - - See: https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#python-driver-compatibility - - Args: - module: Ansible module. - client (cursor): Mongodb cursor on admin database. - """ - loose_srv_version = LooseVersion(client.server_info()['version']) - loose_driver_version = LooseVersion(PyMongoVersion) - - if loose_srv_version >= LooseVersion('3.2') and loose_driver_version < LooseVersion('3.2'): - module.fail_json(msg=' (Note: you must use pymongo 3.2+ with MongoDB >= 3.2)') - - elif loose_srv_version >= LooseVersion('3.0') and loose_driver_version <= LooseVersion('2.8'): - module.fail_json(msg=' (Note: you must use pymongo 2.8+ with MongoDB 3.0)') - - elif loose_srv_version >= LooseVersion('2.6') and loose_driver_version <= LooseVersion('2.7'): - module.fail_json(msg=' (Note: you must use pymongo 2.7+ with MongoDB 2.6)') - - elif LooseVersion(PyMongoVersion) <= LooseVersion('2.5'): - module.fail_json(msg=' (Note: you must be on mongodb 2.4+ and pymongo 2.5+ to use the roles param)') - - -def shard_find(client, shard): - """Check if a shard exists. - - Args: - client (cursor): Mongodb cursor on admin database. - shard (str): shard to check. - - Returns: - dict: when user exists, False otherwise. - """ - if '/' in shard: - s = shard.split('/')[0] - else: - s = shard - for shard in client["config"].shards.find({"_id": s}): - return shard - return False - - -def shard_add(client, shard): - try: - sh = client["admin"].command('addShard', shard) - except Exception as excep: - raise excep - return sh - - -def shard_remove(client, shard): - try: - sh = client["admin"].command('removeShard', shard) - except Exception as excep: - raise excep - return sh - - -def load_mongocnf(): - config = configparser.RawConfigParser() - mongocnf = os.path.expanduser('~/.mongodb.cnf') - - try: - config.readfp(open(mongocnf)) - creds = dict( - user=config.get('client', 'user'), - password=config.get('client', 'pass') - ) - except (configparser.NoOptionError, IOError): - return False - - return creds - -# ========================================= -# Module execution. -# - - -def main(): - module = AnsibleModule(argument_spec=dict(login_user=dict(type='str', required=False), - login_password=dict(type='str', required=False, no_log=True), - login_database=dict(type='str', required=False, default='admin'), - login_host=dict(type='str', required=False, default='localhost'), - login_port=dict(type='int', default=27017, required=False), - ssl=dict(type='bool', default=False, required=False), - ssl_cert_reqs=dict(type='str', required=False, default='CERT_REQUIRED', - choices=['CERT_NONE', 'CERT_OPTIONAL', 'CERT_REQUIRED']), - shard=dict(type='str', required=True), - state=dict(type='str', required=False, default='present', choices=['absent', 'present'])), - supports_check_mode=True) - - if not pymongo_found: - module.fail_json(msg=missing_required_lib('pymongo')) - - login_user = module.params['login_user'] - login_password = module.params['login_password'] - login_database = module.params['login_database'] - login_host = module.params['login_host'] - login_port = module.params['login_port'] - ssl = module.params['ssl'] - shard = module.params['shard'] - state = module.params['state'] - - try: - connection_params = { - "host": login_host, - "port": int(login_port) - } - - if ssl: - connection_params["ssl"] = ssl - connection_params["ssl_cert_reqs"] = getattr(ssl_lib, module.params['ssl_cert_reqs']) - - client = MongoClient(**connection_params) - - try: - check_compatibility(module, client) - except Exception as excep: - if "not authorized on" in str(excep) or "there are no users authenticated" in str(excep): - if login_user is not None and login_password is not None: - client.admin.authenticate(login_user, login_password, source=login_database) - check_compatibility(module, client) - else: - raise excep - else: - raise excep - - if login_user is None and login_password is None: - mongocnf_creds = load_mongocnf() - if mongocnf_creds is not False: - login_user = mongocnf_creds['user'] - login_password = mongocnf_creds['password'] - elif login_password is None or login_user is None: - module.fail_json(msg='when supplying login arguments, both login_user and login_password must be provided') - - try: - client['admin'].command('listDatabases', 1.0) # if this throws an error we need to authenticate - except Exception as excep: - if "not authorized on" in str(excep) or "command listDatabases requires authentication" in str(excep): - if login_user is not None and login_password is not None: - client.admin.authenticate(login_user, login_password, source=login_database) - else: - raise excep - else: - raise excep - - except Exception as e: - module.fail_json(msg='unable to connect to database: %s' % to_native(e), exception=traceback.format_exc()) - - try: - if client["admin"].command("serverStatus")["process"] != "mongos": - module.fail_json(msg="Process running on {0}:{1} is not a mongos".format(login_host, login_port)) - shard_created = False - if module.check_mode: - if state == "present": - if not shard_find(client, shard): - changed = True - else: - changed = False - elif state == "absent": - if not shard_find(client, shard): - changed = False - else: - changed = True - else: - if state == "present": - if not shard_find(client, shard): - shard_add(client, shard) - changed = True - else: - changed = False - elif state == "absent": - if shard_find(client, shard): - shard_remove(client, shard) - changed = True - else: - changed = False - except Exception as e: - action = "add" - if state == "absent": - action = "remove" - module.fail_json(msg='Unable to {0} shard: %s'.format(action) % to_native(e), exception=traceback.format_exc()) - - module.exit_json(changed=changed, shard=shard) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/modules/database/mongodb/mongodb_user.py b/lib/ansible/modules/database/mongodb/mongodb_user.py deleted file mode 100644 index 362b3aa45e..0000000000 --- a/lib/ansible/modules/database/mongodb/mongodb_user.py +++ /dev/null @@ -1,474 +0,0 @@ -#!/usr/bin/python - -# (c) 2012, Elliott Foster -# Sponsored by Four Kitchens http://fourkitchens.com. -# (c) 2014, Epic Games, Inc. -# -# 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: mongodb_user -short_description: Adds or removes a user from a MongoDB database -description: - - Adds or removes a user from a MongoDB database. -version_added: "1.1" -options: - login_user: - description: - - The MongoDB username used to authenticate with. - type: str - login_password: - description: - - The login user's password used to authenticate with. - type: str - login_host: - description: - - The host running the database. - default: localhost - type: str - login_port: - description: - - The MongoDB port to connect to. - default: '27017' - type: str - login_database: - version_added: "2.0" - description: - - The database where login credentials are stored. - type: str - replica_set: - version_added: "1.6" - description: - - Replica set to connect to (automatically connects to primary for writes). - type: str - database: - description: - - The name of the database to add/remove the user from. - required: true - type: str - aliases: [db] - name: - description: - - The name of the user to add or remove. - required: true - aliases: [user] - type: str - password: - description: - - The password to use for the user. - type: str - aliases: [pass] - ssl: - version_added: "1.8" - description: - - Whether to use an SSL connection when connecting to the database. - type: bool - ssl_cert_reqs: - version_added: "2.2" - description: - - Specifies whether a certificate is required from the other side of the connection, - and whether it will be validated if provided. - default: CERT_REQUIRED - choices: [CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED] - type: str - roles: - version_added: "1.3" - type: list - elements: raw - description: - - > - The database user roles valid values could either be one or more of the following strings: - 'read', 'readWrite', 'dbAdmin', 'userAdmin', 'clusterAdmin', 'readAnyDatabase', 'readWriteAnyDatabase', 'userAdminAnyDatabase', - 'dbAdminAnyDatabase' - - "Or the following dictionary '{ db: DATABASE_NAME, role: ROLE_NAME }'." - - "This param requires pymongo 2.5+. If it is a string, mongodb 2.4+ is also required. If it is a dictionary, mongo 2.6+ is required." - state: - description: - - The database user state. - default: present - choices: [absent, present] - type: str - update_password: - default: always - choices: [always, on_create] - version_added: "2.1" - description: - - C(always) will update passwords if they differ. - - C(on_create) will only set the password for newly created users. - type: str - -notes: - - Requires the pymongo Python package on the remote host, version 2.4.2+. This - can be installed using pip or the OS package manager. @see http://api.mongodb.org/python/current/installation.html -requirements: [ "pymongo" ] -author: - - "Elliott Foster (@elliotttf)" - - "Julien Thebault (@Lujeni)" -''' - -EXAMPLES = ''' -- name: Create 'burgers' database user with name 'bob' and password '12345'. - mongodb_user: - database: burgers - name: bob - password: 12345 - state: present - -- name: Create a database user via SSL (MongoDB must be compiled with the SSL option and configured properly) - mongodb_user: - database: burgers - name: bob - password: 12345 - state: present - ssl: True - -- name: Delete 'burgers' database user with name 'bob'. - mongodb_user: - database: burgers - name: bob - state: absent - -- name: Define more users with various specific roles (if not defined, no roles is assigned, and the user will be added via pre mongo 2.2 style) - mongodb_user: - database: burgers - name: ben - password: 12345 - roles: read - state: present - -- name: Define roles - mongodb_user: - database: burgers - name: jim - password: 12345 - roles: readWrite,dbAdmin,userAdmin - state: present - -- name: Define roles - mongodb_user: - database: burgers - name: joe - password: 12345 - roles: readWriteAnyDatabase - state: present - -- name: Add a user to database in a replica set, the primary server is automatically discovered and written to - mongodb_user: - database: burgers - name: bob - replica_set: belcher - password: 12345 - roles: readWriteAnyDatabase - state: present - -# add a user 'oplog_reader' with read only access to the 'local' database on the replica_set 'belcher'. This is useful for oplog access (MONGO_OPLOG_URL). -# please notice the credentials must be added to the 'admin' database because the 'local' database is not synchronized and can't receive user credentials -# To login with such user, the connection string should be MONGO_OPLOG_URL="mongodb://oplog_reader:oplog_reader_password@server1,server2/local?authSource=admin" -# This syntax requires mongodb 2.6+ and pymongo 2.5+ -- name: Roles as a dictionary - mongodb_user: - login_user: root - login_password: root_password - database: admin - user: oplog_reader - password: oplog_reader_password - state: present - replica_set: belcher - roles: - - db: local - role: read - -''' - -RETURN = ''' -user: - description: The name of the user to add or remove. - returned: success - type: str -''' - -import os -import ssl as ssl_lib -import traceback -from distutils.version import LooseVersion -from operator import itemgetter - -try: - from pymongo.errors import ConnectionFailure - from pymongo.errors import OperationFailure - from pymongo import version as PyMongoVersion - from pymongo import MongoClient -except ImportError: - try: # for older PyMongo 2.2 - from pymongo import Connection as MongoClient - except ImportError: - pymongo_found = False - else: - pymongo_found = True -else: - pymongo_found = True - -from ansible.module_utils.basic import AnsibleModule, missing_required_lib -from ansible.module_utils.six import binary_type, text_type -from ansible.module_utils.six.moves import configparser -from ansible.module_utils._text import to_native - - -# ========================================= -# MongoDB module specific support methods. -# - -def check_compatibility(module, client): - """Check the compatibility between the driver and the database. - - See: https://docs.mongodb.com/ecosystem/drivers/driver-compatibility-reference/#python-driver-compatibility - - Args: - module: Ansible module. - client (cursor): Mongodb cursor on admin database. - """ - loose_srv_version = LooseVersion(client.server_info()['version']) - loose_driver_version = LooseVersion(PyMongoVersion) - - if loose_srv_version >= LooseVersion('3.2') and loose_driver_version < LooseVersion('3.2'): - module.fail_json(msg=' (Note: you must use pymongo 3.2+ with MongoDB >= 3.2)') - - elif loose_srv_version >= LooseVersion('3.0') and loose_driver_version <= LooseVersion('2.8'): - module.fail_json(msg=' (Note: you must use pymongo 2.8+ with MongoDB 3.0)') - - elif loose_srv_version >= LooseVersion('2.6') and loose_driver_version <= LooseVersion('2.7'): - module.fail_json(msg=' (Note: you must use pymongo 2.7+ with MongoDB 2.6)') - - elif LooseVersion(PyMongoVersion) <= LooseVersion('2.5'): - module.fail_json(msg=' (Note: you must be on mongodb 2.4+ and pymongo 2.5+ to use the roles param)') - - -def user_find(client, user, db_name): - """Check if the user exists. - - Args: - client (cursor): Mongodb cursor on admin database. - user (str): User to check. - db_name (str): User's database. - - Returns: - dict: when user exists, False otherwise. - """ - for mongo_user in client["admin"].system.users.find(): - if mongo_user['user'] == user: - # NOTE: there is no 'db' field in mongo 2.4. - if 'db' not in mongo_user: - return mongo_user - - if mongo_user["db"] == db_name: - return mongo_user - return False - - -def user_add(module, client, db_name, user, password, roles): - # pymongo's user_add is a _create_or_update_user so we won't know if it was changed or updated - # without reproducing a lot of the logic in database.py of pymongo - db = client[db_name] - - if roles is None: - db.add_user(user, password, False) - else: - db.add_user(user, password, None, roles=roles) - - -def user_remove(module, client, db_name, user): - exists = user_find(client, user, db_name) - if exists: - if module.check_mode: - module.exit_json(changed=True, user=user) - db = client[db_name] - db.remove_user(user) - else: - module.exit_json(changed=False, user=user) - - -def load_mongocnf(): - config = configparser.RawConfigParser() - mongocnf = os.path.expanduser('~/.mongodb.cnf') - - try: - config.readfp(open(mongocnf)) - creds = dict( - user=config.get('client', 'user'), - password=config.get('client', 'pass') - ) - except (configparser.NoOptionError, IOError): - return False - - return creds - - -def check_if_roles_changed(uinfo, roles, db_name): - # We must be aware of users which can read the oplog on a replicaset - # Such users must have access to the local DB, but since this DB does not store users credentials - # and is not synchronized among replica sets, the user must be stored on the admin db - # Therefore their structure is the following : - # { - # "_id" : "admin.oplog_reader", - # "user" : "oplog_reader", - # "db" : "admin", # <-- admin DB - # "roles" : [ - # { - # "role" : "read", - # "db" : "local" # <-- local DB - # } - # ] - # } - - def make_sure_roles_are_a_list_of_dict(roles, db_name): - output = list() - for role in roles: - if isinstance(role, (binary_type, text_type)): - new_role = {"role": role, "db": db_name} - output.append(new_role) - else: - output.append(role) - return output - - roles_as_list_of_dict = make_sure_roles_are_a_list_of_dict(roles, db_name) - uinfo_roles = uinfo.get('roles', []) - - if sorted(roles_as_list_of_dict, key=itemgetter('db')) == sorted(uinfo_roles, key=itemgetter('db')): - return False - return True - - -# ========================================= -# Module execution. -# - -def main(): - module = AnsibleModule( - argument_spec=dict( - login_user=dict(default=None), - login_password=dict(default=None, no_log=True), - login_host=dict(default='localhost'), - login_port=dict(default='27017'), - login_database=dict(default=None), - replica_set=dict(default=None), - database=dict(required=True, aliases=['db']), - name=dict(required=True, aliases=['user']), - password=dict(aliases=['pass'], no_log=True), - ssl=dict(default=False, type='bool'), - roles=dict(default=None, type='list', elements='raw'), - state=dict(default='present', choices=['absent', 'present']), - update_password=dict(default="always", choices=["always", "on_create"]), - ssl_cert_reqs=dict(default='CERT_REQUIRED', choices=['CERT_NONE', 'CERT_OPTIONAL', 'CERT_REQUIRED']), - ), - supports_check_mode=True - ) - - if not pymongo_found: - module.fail_json(msg=missing_required_lib('pymongo')) - - login_user = module.params['login_user'] - login_password = module.params['login_password'] - login_host = module.params['login_host'] - login_port = module.params['login_port'] - login_database = module.params['login_database'] - - replica_set = module.params['replica_set'] - db_name = module.params['database'] - user = module.params['name'] - password = module.params['password'] - ssl = module.params['ssl'] - roles = module.params['roles'] or [] - state = module.params['state'] - update_password = module.params['update_password'] - - try: - connection_params = { - "host": login_host, - "port": int(login_port), - } - - if replica_set: - connection_params["replicaset"] = replica_set - - if ssl: - connection_params["ssl"] = ssl - connection_params["ssl_cert_reqs"] = getattr(ssl_lib, module.params['ssl_cert_reqs']) - - client = MongoClient(**connection_params) - - # NOTE: this check must be done ASAP. - # We doesn't need to be authenticated (this ability has lost in PyMongo 3.6) - if LooseVersion(PyMongoVersion) <= LooseVersion('3.5'): - check_compatibility(module, client) - - if login_user is None and login_password is None: - mongocnf_creds = load_mongocnf() - if mongocnf_creds is not False: - login_user = mongocnf_creds['user'] - login_password = mongocnf_creds['password'] - elif login_password is None or login_user is None: - module.fail_json(msg='when supplying login arguments, both login_user and login_password must be provided') - - if login_user is not None and login_password is not None: - client.admin.authenticate(login_user, login_password, source=login_database) - elif LooseVersion(PyMongoVersion) >= LooseVersion('3.0'): - if db_name != "admin": - module.fail_json(msg='The localhost login exception only allows the first admin account to be created') - # else: this has to be the first admin user added - - except Exception as e: - module.fail_json(msg='unable to connect to database: %s' % to_native(e), exception=traceback.format_exc()) - - if state == 'present': - if password is None and update_password == 'always': - module.fail_json(msg='password parameter required when adding a user unless update_password is set to on_create') - - try: - if update_password != 'always': - uinfo = user_find(client, user, db_name) - if uinfo: - password = None - if not check_if_roles_changed(uinfo, roles, db_name): - module.exit_json(changed=False, user=user) - - if module.check_mode: - module.exit_json(changed=True, user=user) - - user_add(module, client, db_name, user, password, roles) - except Exception as e: - module.fail_json(msg='Unable to add or update user: %s' % to_native(e), exception=traceback.format_exc()) - finally: - try: - client.close() - except Exception: - pass - # Here we can check password change if mongo provide a query for that : https://jira.mongodb.org/browse/SERVER-22848 - # newuinfo = user_find(client, user, db_name) - # if uinfo['role'] == newuinfo['role'] and CheckPasswordHere: - # module.exit_json(changed=False, user=user) - - elif state == 'absent': - try: - user_remove(module, client, db_name, user) - except Exception as e: - module.fail_json(msg='Unable to remove user: %s' % to_native(e), exception=traceback.format_exc()) - finally: - try: - client.close() - except Exception: - pass - module.exit_json(changed=True, user=user) - - -if __name__ == '__main__': - main() diff --git a/lib/ansible/plugins/cache/mongodb.py b/lib/ansible/plugins/cache/mongodb.py deleted file mode 100644 index 50ef450e0f..0000000000 --- a/lib/ansible/plugins/cache/mongodb.py +++ /dev/null @@ -1,181 +0,0 @@ -# (c) 2018, Matt Martz -# 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 = ''' - cache: mongodb - short_description: Use MongoDB for caching - description: - - This cache uses per host records saved in MongoDB. - version_added: "2.5" - requirements: - - pymongo>=3 - options: - _uri: - description: - - MongoDB Connection String URI - required: False - env: - - name: ANSIBLE_CACHE_PLUGIN_CONNECTION - ini: - - key: fact_caching_connection - section: defaults - _prefix: - description: User defined prefix to use when creating the DB entries - default: ansible_facts - env: - - name: ANSIBLE_CACHE_PLUGIN_PREFIX - ini: - - key: fact_caching_prefix - section: defaults - _timeout: - default: 86400 - description: Expiration timeout in seconds for the cache plugin data. Set to 0 to never expire - env: - - name: ANSIBLE_CACHE_PLUGIN_TIMEOUT - ini: - - key: fact_caching_timeout - section: defaults - type: integer -''' - -import datetime - -from contextlib import contextmanager - -from ansible import constants as C -from ansible.errors import AnsibleError -from ansible.plugins.cache import BaseCacheModule -from ansible.utils.display import Display - -try: - import pymongo -except ImportError: - raise AnsibleError("The 'pymongo' python module is required for the mongodb fact cache, 'pip install pymongo>=3.0'") - -display = Display() - - -class CacheModule(BaseCacheModule): - """ - A caching module backed by mongodb. - """ - def __init__(self, *args, **kwargs): - try: - super(CacheModule, self).__init__(*args, **kwargs) - self._connection = self.get_option('_uri') - self._timeout = int(self.get_option('_timeout')) - self._prefix = self.get_option('_prefix') - except KeyError: - display.deprecated('Rather than importing CacheModules directly, ' - 'use ansible.plugins.loader.cache_loader', version='2.12') - self._connection = C.CACHE_PLUGIN_CONNECTION - self._timeout = int(C.CACHE_PLUGIN_TIMEOUT) - self._prefix = C.CACHE_PLUGIN_PREFIX - - self._cache = {} - self._managed_indexes = False - - def _manage_indexes(self, collection): - ''' - This function manages indexes on the mongo collection. - We only do this once, at run time based on _managed_indexes, - rather than per connection instantiation as that would be overkill - ''' - _timeout = self._timeout - if _timeout and _timeout > 0: - try: - collection.create_index( - 'date', - name='ttl', - expireAfterSeconds=_timeout - ) - except pymongo.errors.OperationFailure: - # We make it here when the fact_caching_timeout was set to a different value between runs - collection.drop_index('ttl') - return self._manage_indexes(collection) - else: - collection.drop_index('ttl') - - @contextmanager - def _collection(self): - ''' - This is a context manager for opening and closing mongo connections as needed. This exists as to not create a global - connection, due to pymongo not being fork safe (http://api.mongodb.com/python/current/faq.html#is-pymongo-fork-safe) - ''' - mongo = pymongo.MongoClient(self._connection) - try: - db = mongo.get_default_database() - except pymongo.errors.ConfigurationError: - # We'll fall back to using ``ansible`` as the database if one was not provided - # in the MongoDB Connection String URI - db = mongo['ansible'] - - # The collection is hard coded as ``cache``, there are no configuration options for this - collection = db['cache'] - if not self._managed_indexes: - # Only manage the indexes once per run, not per connection - self._manage_indexes(collection) - self._managed_indexes = True - - yield collection - - mongo.close() - - def _make_key(self, key): - return '%s%s' % (self._prefix, key) - - def get(self, key): - if key not in self._cache: - with self._collection() as collection: - value = collection.find_one({'_id': self._make_key(key)}) - self._cache[key] = value['data'] - - return self._cache.get(key) - - def set(self, key, value): - self._cache[key] = value - with self._collection() as collection: - collection.update_one( - {'_id': self._make_key(key)}, - { - '$set': { - '_id': self._make_key(key), - 'data': value, - 'date': datetime.datetime.utcnow() - } - }, - upsert=True - ) - - def keys(self): - with self._collection() as collection: - return [doc['_id'] for doc in collection.find({}, {'_id': True})] - - def contains(self, key): - with self._collection() as collection: - return bool(collection.count({'_id': self._make_key(key)})) - - def delete(self, key): - del self._cache[key] - with self._collection() as collection: - collection.delete_one({'_id': self._make_key(key)}) - - def flush(self): - with self._collection() as collection: - collection.delete_many({}) - - def copy(self): - with self._collection() as collection: - return dict((d['_id'], d['data']) for d in collection.find({})) - - def __getstate__(self): - return dict() - - def __setstate__(self, data): - self.__init__() diff --git a/lib/ansible/plugins/lookup/mongodb.py b/lib/ansible/plugins/lookup/mongodb.py deleted file mode 100644 index 7f22983a7b..0000000000 --- a/lib/ansible/plugins/lookup/mongodb.py +++ /dev/null @@ -1,238 +0,0 @@ -# (c) 2016, Marcos Diez -# https://github.com/marcosdiez/ -# -# 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 . - -from __future__ import (absolute_import, division, print_function) -from ansible.module_utils.six import string_types, integer_types -__metaclass__ = type - -DOCUMENTATION = ''' - author: 'Marcos Diez ' - lookup: mongodb - version_added: "2.3" - short_description: lookup info from MongoDB - description: - - 'The ``MongoDB`` lookup runs the *find()* command on a given *collection* on a given *MongoDB* server.' - - 'The result is a list of jsons, so slightly different from what PyMongo returns. In particular, *timestamps* are converted to epoch integers.' - options: - connect_string: - description: - - Can be any valid MongoDB connection string, supporting authentication, replicasets, etc. - - "More info at U(https://docs.mongodb.org/manual/reference/connection-string/)" - default: "mongodb://localhost/" - database: - description: - - Name of the database which the query will be made - required: True - collection: - description: - - Name of the collection which the query will be made - required: True - filter: - description: - - Criteria of the output - type: 'dict' - default: '{}' - projection: - description: - - Fields you want returned - type: dict - default: "{}" - skip: - description: - - How many results should be skipped - type: integer - limit: - description: - - How many results should be shown - type: integer - sort: - description: - - Sorting rules. Please notice the constats are replaced by strings. - type: list - default: "[]" - notes: - - "Please check https://api.mongodb.org/python/current/api/pymongo/collection.html?highlight=find#pymongo.collection.Collection.find for more details." - requirements: - - pymongo >= 2.4 (python library) -''' - -EXAMPLES = ''' -- hosts: all - gather_facts: false - vars: - mongodb_parameters: - #mandatory parameters - database: 'local' - #optional - collection: "startup_log" - connection_string: "mongodb://localhost/" - extra_connection_parameters: { "ssl" : True , "ssl_certfile": /etc/self_signed_certificate.pem" } - #optional query parameters, we accept any parameter from the normal mongodb query. - filter: { "hostname": "batman" } - projection: { "pid": True , "_id" : False , "hostname" : True } - skip: 0 - limit: 1 - sort: [ [ "startTime" , "ASCENDING" ] , [ "age", "DESCENDING" ] ] - tasks: - - debug: msg="Mongo has already started with the following PID [{{ item.pid }}]" - with_mongodb: "{{mongodb_parameters}}" -''' - -import datetime - -try: - from pymongo import ASCENDING, DESCENDING - from pymongo.errors import ConnectionFailure - from pymongo import MongoClient -except ImportError: - try: # for older PyMongo 2.2 - from pymongo import Connection as MongoClient - except ImportError: - pymongo_found = False - else: - pymongo_found = True -else: - pymongo_found = True - - -from ansible.errors import AnsibleError -from ansible.plugins.lookup import LookupBase - - -class LookupModule(LookupBase): - - def _fix_sort_parameter(self, sort_parameter): - if sort_parameter is None: - return sort_parameter - - if not isinstance(sort_parameter, list): - raise AnsibleError(u"Error. Sort parameters must be a list, not [ {0} ]".format(sort_parameter)) - - for item in sort_parameter: - self._convert_sort_string_to_constant(item) - - return sort_parameter - - def _convert_sort_string_to_constant(self, item): - original_sort_order = item[1] - sort_order = original_sort_order.upper() - if sort_order == u"ASCENDING": - item[1] = ASCENDING - elif sort_order == u"DESCENDING": - item[1] = DESCENDING - # else the user knows what s/he is doing and we won't predict. PyMongo will return an error if necessary - - def convert_mongo_result_to_valid_json(self, result): - if result is None: - return result - if isinstance(result, integer_types + (float, bool)): - return result - if isinstance(result, string_types): - return result - elif isinstance(result, list): - new_list = [] - for elem in result: - new_list.append(self.convert_mongo_result_to_valid_json(elem)) - return new_list - elif isinstance(result, dict): - new_dict = {} - for key in result.keys(): - value = result[key] # python2 and 3 compatible.... - new_dict[key] = self.convert_mongo_result_to_valid_json(value) - return new_dict - elif isinstance(result, datetime.datetime): - # epoch - return (result - datetime.datetime(1970, 1, 1)). total_seconds() - else: - # failsafe - return u"{0}".format(result) - - def run(self, terms, variables, **kwargs): - - ret = [] - for term in terms: - u''' - Makes a MongoDB query and returns the output as a valid list of json. - Timestamps are converted to epoch integers/longs. - - Here is a sample playbook that uses it: - -------------------------------------------------------------------------------- -- hosts: all - gather_facts: false - - vars: - mongodb_parameters: - #optional parameter, default = "mongodb://localhost/" - # connection_string: "mongodb://localhost/" - - #mandatory parameters - database: 'local' - collection: "startup_log" - - #optional query parameters - #we accept any parameter from the normal mongodb query. - # the official documentation is here - # https://api.mongodb.org/python/current/api/pymongo/collection.html?highlight=find#pymongo.collection.Collection.find - # filter: { "hostname": "batman" } - # projection: { "pid": True , "_id" : False , "hostname" : True } - # skip: 0 - # limit: 1 - # sort: [ [ "startTime" , "ASCENDING" ] , [ "age", "DESCENDING" ] ] - # extra_connection_parameters = { } - - # dictionary with extra parameters like ssl, ssl_keyfile, maxPoolSize etc... - # the full list is available here. It varies from PyMongo version - # https://api.mongodb.org/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient - - tasks: - - debug: msg="Mongo has already started with the following PID [{{ item.pid }}] - full_data {{ item }} " - with_items: - - "{{ lookup('mongodb', mongodb_parameters) }}" -------------------------------------------------------------------------------- - ''' - - connection_string = term.get(u'connection_string', u"mongodb://localhost") - database = term[u"database"] - collection = term[u'collection'] - extra_connection_parameters = term.get(u'extra_connection_parameters', {}) - - if u"extra_connection_parameters" in term: - del term[u"extra_connection_parameters"] - if u"connection_string" in term: - del term[u"connection_string"] - del term[u"database"] - del term[u"collection"] - - if u"sort" in term: - term[u"sort"] = self._fix_sort_parameter(term[u"sort"]) - - # all other parameters are sent to mongo, so we are future and past proof - - try: - client = MongoClient(connection_string, **extra_connection_parameters) - results = client[database][collection].find(**term) - - for result in results: - result = self.convert_mongo_result_to_valid_json(result) - ret.append(result) - - except ConnectionFailure as e: - raise AnsibleError(u'unable to connect to database: %s' % str(e)) - - return ret diff --git a/test/integration/targets/mongodb_info/aliases b/test/integration/targets/mongodb_info/aliases deleted file mode 100644 index f2df32c48a..0000000000 --- a/test/integration/targets/mongodb_info/aliases +++ /dev/null @@ -1,5 +0,0 @@ -destructive -shippable/posix/group4 -skip/aix -skip/osx -skip/freebsd diff --git a/test/integration/targets/mongodb_info/defaults/main.yml b/test/integration/targets/mongodb_info/defaults/main.yml deleted file mode 100644 index 5f41a8becf..0000000000 --- a/test/integration/targets/mongodb_info/defaults/main.yml +++ /dev/null @@ -1,4 +0,0 @@ -mongodb_default_port: 27017 -mongodb_admin_user: admin -mongodb_admin_password: admin -mongodb_default_db: admin diff --git a/test/integration/targets/mongodb_info/meta/main.yml b/test/integration/targets/mongodb_info/meta/main.yml deleted file mode 100644 index 31081e2ede..0000000000 --- a/test/integration/targets/mongodb_info/meta/main.yml +++ /dev/null @@ -1,3 +0,0 @@ -dependencies: -- setup_mongodb_v4 -- setup_remote_tmp_dir diff --git a/test/integration/targets/mongodb_info/tasks/main.yml b/test/integration/targets/mongodb_info/tasks/main.yml deleted file mode 100644 index 859d4a66ae..0000000000 --- a/test/integration/targets/mongodb_info/tasks/main.yml +++ /dev/null @@ -1,8 +0,0 @@ -# Copyright 2020, Andrew Klychkov -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -# Main mongodb_info module tests -- import_tasks: mongodb_info.yml - when: - - ansible_distribution == 'CentOS' - - ansible_distribution_major_version is version('7', '>=') diff --git a/test/integration/targets/mongodb_info/tasks/mongodb_info.yml b/test/integration/targets/mongodb_info/tasks/mongodb_info.yml deleted file mode 100644 index 3690622475..0000000000 --- a/test/integration/targets/mongodb_info/tasks/mongodb_info.yml +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2020, Andrew Klychkov -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -- vars: - task_parameters: &task_parameters - register: result - mongo_parameters: &mongo_parameters - login_port: '{{ mongodb_default_port }}' - login_user: '{{ mongodb_admin_user }}' - login_password: '{{ mongodb_admin_password }}' - login_database: '{{ mongodb_default_db }}' - - block: - - - name: Get info - <<: *task_parameters - mongodb_info: - <<: *mongo_parameters - - - assert: - that: - - result is not changed - - result.general.version == '4.2.3' - - result.databases.admin - - result.total_size - - result.users.admin - - result.roles.backup - - result.parameters.logLevel == 0 - - - name: Get info with filter - <<: *task_parameters - mongodb_info: - <<: *mongo_parameters - filter: general, total_size - - - assert: - that: - - result is not changed - - result.general.version == '4.2.3' - - result.total_size - - result.databases is not defined - - result.parameters is not defined - - result.users is not defined - - result.roles is not defined - - - name: Get info with filter - <<: *task_parameters - mongodb_info: - <<: *mongo_parameters - filter: '!parameters' - - - assert: - that: - - result is not changed - - result.general.version == '4.2.3' - - result.databases.admin - - result.total_size - - result.users.admin - - result.roles.backup - - result.parameters is not defined diff --git a/test/integration/targets/mongodb_parameter/aliases b/test/integration/targets/mongodb_parameter/aliases deleted file mode 100644 index 8251a83e7f..0000000000 --- a/test/integration/targets/mongodb_parameter/aliases +++ /dev/null @@ -1,7 +0,0 @@ -destructive -shippable/posix/group1 -skip/aix -skip/osx -skip/freebsd -skip/rhel -needs/root diff --git a/test/integration/targets/mongodb_parameter/defaults/main.yml b/test/integration/targets/mongodb_parameter/defaults/main.yml deleted file mode 100644 index aac55526df..0000000000 --- a/test/integration/targets/mongodb_parameter/defaults/main.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# defaults file for test_mongodb_user -mongodb_admin_user: test_root -mongodb_admin_password: saE_Rr9!gE6gh#e~R#nZ -mongod_auth: false -kill_signal: SIGTERM -# Should be one of -# --storageEngine wiredTiger --wiredTigerEngineConfigString="cache_size=200M" -# --storageEngine mmapv1 --nojournal -mongod_storage_engine_opts: "--storageEngine wiredTiger --wiredTigerEngineConfigString='cache_size=200M'" -mongodb_user: mongodb -mongodb_user_list: - - { "name": "user1", "password": "password1", "roles": "read", "database": "test" } - - { "name": "user2", "password": "password2", "roles": "readWrite", "database": "test" } - - { "name": "user3", "password": "password3", "roles": "dbAdmin", "database": "test" } - - { "name": "user4", "password": "password4", "roles": "userAdmin", "database": "test" } - - { "name": "user5", "password": "password5", "roles": "clusterAdmin", "database": "admin" } - - { "name": "user6", "password": "password6", "roles": "readAnyDatabase", "database": "admin" } - - { "name": "user7", "password": "password7", "roles": "readWriteAnyDatabase", "database": "admin" } - - { "name": "user8", "password": "password8", "roles": "userAdminAnyDatabase", "database": "admin" } - - { "name": "user9", "password": "password9", "roles": "dbAdminAnyDatabase", "database": "admin" } diff --git a/test/integration/targets/mongodb_parameter/meta/main.yml b/test/integration/targets/mongodb_parameter/meta/main.yml deleted file mode 100644 index 9d941be0bc..0000000000 --- a/test/integration/targets/mongodb_parameter/meta/main.yml +++ /dev/null @@ -1,3 +0,0 @@ -dependencies: - - setup_mongodb - - setup_remote_tmp_dir diff --git a/test/integration/targets/mongodb_parameter/tasks/main.yml b/test/integration/targets/mongodb_parameter/tasks/main.yml deleted file mode 100644 index a0fda1dc60..0000000000 --- a/test/integration/targets/mongodb_parameter/tasks/main.yml +++ /dev/null @@ -1,143 +0,0 @@ -# test code for the mongodb_parameter module -# (c) 2019, Rhys Campbell - -# 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 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 . - -# ============================================================ - -- name: Ensure tests home exists - file: - path: "{{ remote_tmp_dir }}/tests" - state: directory - -- include_tasks: mongod_teardown.yml - -- include_tasks: mongod_singlenode.yml - -- name: Set syncdelay to 99 - mongodb_parameter: - login_port: 3001 - param: syncdelay - value: 99 - param_type: int - register: sd_change - -- assert: - that: - - sd_change.before | int == 60 - - sd_change.after | int == 99 - - sd_change.changed == True - -- name: Set syncdelay to 99 (again) - mongodb_parameter: - login_port: 3001 - param: syncdelay - value: 99 - param_type: int - register: sd_change - -- assert: - that: - - sd_change.before | int == 99 - - sd_change.after | int == 99 - - sd_change.changed == False - -- name: Create admin user with module - mongodb_user: - login_port: 3001 - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: root - state: present - register: mongodb_admin_user_created - -- assert: - that: - - mongodb_admin_user_created.changed == True - -- name: Kill all mongod processes - command: pkill -{{ kill_signal }} mongod - ignore_errors: true - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - delay: 3 - with_items: "{{ pids_of_mongod }}" - -- set_fact: - mongod_auth: true - -- include_tasks: mongod_singlenode.yml -# Tests with auth enabled - -- name: Set syncdelay to 59 with auth - mongodb_parameter: - login_port: 3001 - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - param: syncdelay - value: 59 - param_type: int - register: sd_change - -- assert: - that: - - sd_change.before | int == 60 - - sd_change.after | int == 59 - - sd_change.changed == True - -- name: Set syncdelay to 59 (again) with auth - mongodb_parameter: - login_port: 3001 - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - param: syncdelay - value: 59 - param_type: int - register: sd_change - -- assert: - that: - - sd_change.before | int == 59 - - sd_change.after | int == 59 - - sd_change.changed == False - -- name: Set authenticationMechanisms to MONGODB-X509 with auth (will fail) - mongodb_parameter: - login_port: 3001 - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - param: authenticationMechanisms - value: "MONGODB-X509" - param_type: str - register: diag_change - ignore_errors: yes - -- assert: - that: - - '"unable to change parameter" in diag_change.msg' - - diag_change.failed == True - -# Clean up -- include_tasks: mongod_teardown.yml diff --git a/test/integration/targets/mongodb_parameter/tasks/mongod_singlenode.yml b/test/integration/targets/mongodb_parameter/tasks/mongod_singlenode.yml deleted file mode 100644 index 291cb1c980..0000000000 --- a/test/integration/targets/mongodb_parameter/tasks/mongod_singlenode.yml +++ /dev/null @@ -1,55 +0,0 @@ -- name: Set mongodb_user user for redhat - set_fact: - mongodb_user: "mongod" - when: ansible_os_family == "RedHat" - -- set_fact: - mongodb_nodes: - - 3001 - -- name: Create directories for mongod processes - file: - path: "{{ remote_tmp_dir }}/mongod{{ item }}" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - recurse: yes - with_items: "{{ mongodb_nodes }}" - -- name: Ensure {{ remote_tmp_dir }}/config dir exists - file: - path: "{{ remote_tmp_dir }}/config" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - -- name: Create keyfile - copy: - dest: "{{ remote_tmp_dir }}/my.key" - content: | - fd2CUrbXBJpB4rt74A6F - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0600 - when: mongod_auth == True - -- name: Spawn mongod process without auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --logpath mongod{{ item }}/log.log --fork - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == False - -- name: Spawn mongod process with auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --logpath mongod{{ item }}/log.log --fork --auth --keyFile my.key - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == True - -- name: Wait for mongod to start responding - wait_for: - port: "{{ item }}" - with_items: "{{ mongodb_nodes }}" diff --git a/test/integration/targets/mongodb_parameter/tasks/mongod_teardown.yml b/test/integration/targets/mongodb_parameter/tasks/mongod_teardown.yml deleted file mode 100644 index a904a718b2..0000000000 --- a/test/integration/targets/mongodb_parameter/tasks/mongod_teardown.yml +++ /dev/null @@ -1,25 +0,0 @@ -- name: Kill all mongod processes - command: pkill -{{ kill_signal }} mongod - ignore_errors: true - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - delay: 1 - with_items: "{{ pids_of_mongod }}" - -- name: Remove all mongod folders - file: - path: "{{ remote_tmp_dir }}/{{ item }}" - state: absent - with_items: - - mongod3001 - -- name: Remove all mongod sock files - shell: rm -Rf /tmp/mongodb*.sock diff --git a/test/integration/targets/mongodb_replicaset/aliases b/test/integration/targets/mongodb_replicaset/aliases deleted file mode 100644 index 8251a83e7f..0000000000 --- a/test/integration/targets/mongodb_replicaset/aliases +++ /dev/null @@ -1,7 +0,0 @@ -destructive -shippable/posix/group1 -skip/aix -skip/osx -skip/freebsd -skip/rhel -needs/root diff --git a/test/integration/targets/mongodb_replicaset/defaults/main.yml b/test/integration/targets/mongodb_replicaset/defaults/main.yml deleted file mode 100644 index 343d48e96a..0000000000 --- a/test/integration/targets/mongodb_replicaset/defaults/main.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -# defaults file for test_mongodb_replicaset -mongodb_replicaset1: rs1 -mongodb_replicaset2: rs2 -mongodb_replicaset3: rs3 -mongodb_replicaset4: rs4 -mongodb_replicaset5: rs5 -mongodb_replicaset6: rs6 -mongodb_replicaset7: rs7 -mongodb_replicaset8: rs8 -test_mongo_auth: yes -mongodb_admin_user: test_root -mongodb_admin_password: saE_Rr9!gE6gh#e~R#nZ -debug: False -mongodb_nodes: - - 3001 - - 3002 - - 3003 -mongod_auth: false -kill_signal: SIGTERM -# Should be one of -mongod_storage_engine_opts: "--storageEngine wiredTiger --wiredTigerEngineConfigString='cache_size=200M'" -#mongod_storage_engine_opts: "--storageEngine mmapv1 --nojournal" -mongodb_user: mongodb diff --git a/test/integration/targets/mongodb_replicaset/files/js/is_primary.js b/test/integration/targets/mongodb_replicaset/files/js/is_primary.js deleted file mode 100644 index 7bb130614f..0000000000 --- a/test/integration/targets/mongodb_replicaset/files/js/is_primary.js +++ /dev/null @@ -1,13 +0,0 @@ -var done = false; -var iterations = 0; -while(rs.status()['myState'] != 1) { - if (!done) { - //print("State is not yet PRIMARY. Waiting..."); - done = true - } - sleep(1000); - iterations++; - if (iterations == 100) { - throw new Error("Exceeded iterations limit."); - } - } diff --git a/test/integration/targets/mongodb_replicaset/meta/main.yml b/test/integration/targets/mongodb_replicaset/meta/main.yml deleted file mode 100644 index 9d941be0bc..0000000000 --- a/test/integration/targets/mongodb_replicaset/meta/main.yml +++ /dev/null @@ -1,3 +0,0 @@ -dependencies: - - setup_mongodb - - setup_remote_tmp_dir diff --git a/test/integration/targets/mongodb_replicaset/tasks/main.yml b/test/integration/targets/mongodb_replicaset/tasks/main.yml deleted file mode 100644 index 72d00e4d58..0000000000 --- a/test/integration/targets/mongodb_replicaset/tasks/main.yml +++ /dev/null @@ -1,540 +0,0 @@ -# test code for the mongodb_replicaset module -# (c) 2019, Rhys Campbell - -# 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 . - -# ============================================================ - -- name: Ensure tests home exists - file: - path: "{{ remote_tmp_dir }}/tests" - state: directory - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset1 }}" - -- include_tasks: mongod_replicaset.yml - -# test with yaml list -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset1 }}" - heartbeat_timeout_secs: 1 - election_timeout_millis: 1000 - members: - - "localhost:3001" - - "localhost:3002" - - "localhost:3003" - -- name: Ensure is_primary script exists on host - copy: - src: js/is_primary.js - dest: "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Get replicaset info - command: mongo admin --eval "rs.status()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - -- name: Add mongodb admin user - mongodb_user: - login_host: localhost - login_port: 3001 - replica_set: "{{ mongodb_replicaset1 }}" - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: ["root"] - state: present - register: mongo_admin_user - when: test_mongo_auth - -- name: Murder all mongod processes - shell: pkill -{{ kill_signal }} mongod; - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - with_items: "{{ pids_of_mongod.pids }}" - -- set_fact: - current_replicaset: "{{ mongodb_replicaset1 }}" - -- set_fact: - mongod_auth: true - -- name: Execute mongod script to restart with auth enabled - include_tasks: mongod_replicaset.yml - -- name: Validate replicaset previously created - mongodb_replicaset: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset1 }}" - election_timeout_millis: 1000 - members: - - "localhost:3001" - - "localhost:3002" - - "localhost:3003" - register: mongodb_replicaset - -- name: Assert replicaset name has not changed - assert: - that: mongodb_replicaset.changed == False - -- name: Test with bad password - mongodb_replicaset: - login_user: "{{ mongodb_admin_user }}" - login_password: XXXXXXXXXXXXXXXX - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset1 }}" - election_timeout_millis: 1000 - members: - - "localhost:3001" - - "localhost:3002" - - "localhost:3003" - register: mongodb_replicaset_bad_pw - ignore_errors: True - -- name: Assert login failed - assert: - that: - - "mongodb_replicaset_bad_pw.rc == 1" - - "'Authentication failed' in mongodb_replicaset_bad_pw.module_stderr" - - ############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset2 }}" - -- set_fact: - mongod_auth: false - -- name: Execute mongod script to restart with auth enabled - include_tasks: mongod_replicaset.yml - -# Test with python style list -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset2 }}" - members: [ "localhost:3001", "localhost:3002", "localhost:3003" ] - election_timeout_millis: 1000 - heartbeat_timeout_secs: 1 - -- name: Get replicaset info - command: mongo admin --eval "rs.status()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset2 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - -############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset3 }}" - -- set_fact: - mongod_auth: false - -- name: Launch mongod processes - include_tasks: mongod_replicaset.yml - -# Test with csv string -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset3 }}" - members: "localhost:3001,localhost:3002,localhost:3003" - election_timeout_millis: 1000 - -- name: Get replicaset info - command: mongo admin --eval "rs.status()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset3 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - ############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset4 }}" - -- set_fact: - mongod_auth: false - -- name: Launch mongod processes - include_tasks: mongod_replicaset.yml - -# Test with arbiter_at_index -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - arbiter_at_index: 2 - replica_set: "{{ mongodb_replicaset4 }}" - members: "localhost:3001,localhost:3002,localhost:3003" - election_timeout_millis: 1000 - -- name: Ensure host reaches primary before proceeding 3001 - command: mongo admin --port 3001 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Get replicaset info - command: mongo admin --eval "rs.status()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset4 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - "'ARBITER' in mongo_output.stdout" - -############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset5 }}" - -- set_fact: - mongod_auth: false - -- name: Launch mongod processes - include_tasks: mongod_replicaset.yml - -# Test with chainingAllowed -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - chaining_allowed: no - replica_set: "{{ mongodb_replicaset5 }}" - election_timeout_millis: 1000 - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - -- name: Get replicaset info - command: mongo admin --eval "rs.conf()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset5 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - "'chainingAllowed\" : false,' in mongo_output.stdout" - -############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset6 }}" - -- set_fact: - mongodb_nodes: [ 3001, 3002, 3003, 3004, 3005] - -- set_fact: - mongod_auth: false - -- name: Launch mongod processes - include_tasks: mongod_replicaset.yml - -# Test with 5 mongod processes -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset6 }}" - election_timeout_millis: 1000 - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - - localhost:3004 - - localhost:3005 - -- name: Get replicaset info - command: mongo admin --eval "rs.conf()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset6 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - "'localhost:3004' in mongo_output.stdout" - - "'localhost:3005' in mongo_output.stdout" - -############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset7 }}" - -- set_fact: - mongod_auth: false - -- set_fact: - mongodb_nodes: [ 3001, 3002, 3003 ] - -- name: Launch mongod processes - include_tasks: mongod_replicaset.yml - -# Test withheartbeatTimeoutSecs -- name: Create replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - election_timeout_millis: 9999 - replica_set: "{{ mongodb_replicaset7 }}" - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - -- name: Get replicaset info - command: mongo admin --eval "rs.conf()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset7 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - "'electionTimeoutMillis\" : 9999,' in mongo_output.stdout" - -############################################################# - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset8 }}" - -- name: Launch mongod processes - include_tasks: mongod_replicaset.yml - -# Test with heartbeatTimeoutSecs -- name: Create replicaset with module protocolVersion 0 (Mongodb 3.0) - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - protocol_version: 0 - heartbeat_timeout_secs: 9 - replica_set: "{{ mongodb_replicaset8 }}" - election_timeout_millis: 1000 - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - when: mongodb_version.startswith('3') == True - -- name: Create replicaset with module protocolVersion 1 (MongoDB 4.0+) - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - protocol_version: 1 - election_timeout_millis: 9000 - replica_set: "{{ mongodb_replicaset8 }}" - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - when: mongodb_version.startswith('4') == True - -- name: Get replicaset info - command: mongo admin --eval "rs.conf()" --port 3001 - register: mongo_output - -- name: Assert replicaset name is in mongo_output MongoDB 3.0+ - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset8 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - "'heartbeatTimeoutSecs\" : 9,' in mongo_output.stdout" - when: mongodb_version.startswith('3') == True - -- name: Assert replicaset name is in mongo_output MongoDB 4.0+ - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset8 }}' in mongo_output.stdout" - - "'localhost:3001' in mongo_output.stdout" - - "'localhost:3002' in mongo_output.stdout" - - "'localhost:3003' in mongo_output.stdout" - - "'electionTimeoutMillis\" : 9000,' in mongo_output.stdout" - when: mongodb_version.startswith('4') == True - -# TODO - Readd this test once we support serverSelectionTimeoutMS / connectTimeoutMS -#- name: Run test with unknown host -# mongodb_replicaset: -# login_user: admin -# login_password: secret -# login_host: "idonotexist" -# login_port: 3001 -# login_database: "admin" -# protocol_version: 0 -# heartbeat_timeout_secs: 9 -# replica_set: "{{ mongodb_replicaset8 }}" -# election_timeout_millis: 1000 -# members: -# - idonotexist:3001 -# - idonotexist:3002 -# - idonotexist:3003 -# ignore_errors: True -# register: host_does_not_exist - -#- name: Assert that "Name or service not known" is in error -# assert: -# that: -# - "host_does_not_exist.rc == 1" -# - "'Name or service not known' in host_does_not_exist.module_stderr" - -# Final clean up to prevent "directory not empty" error - -# Test invalid arbiter handling -# Test with arbiter_at_index -- name: Test invalid arbiter handling 1 - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - arbiter_at_index: 0 - replica_set: "{{ mongodb_replicaset4 }}" - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - - localhost:3004 - ignore_errors: yes - register: invalid_num - -- assert: - that: - - "'MongoDB Replicaset validation failed. Invalid number of replicaset members.' == invalid_num.msg" - -- name: Test invalid arbiter handling 2 - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - arbiter_at_index: 4 - replica_set: "{{ mongodb_replicaset4 }}" - members: - - localhost:3001 - - localhost:3002 - - localhost:3003 - ignore_errors: yes - register: invalid_num2 - -- assert: - that: - - "'MongoDB Replicaset validation failed. Invalid arbiter index.' == invalid_num2.msg" - -- include_tasks: mongod_teardown.yml diff --git a/test/integration/targets/mongodb_replicaset/tasks/mongod_replicaset.yml b/test/integration/targets/mongodb_replicaset/tasks/mongod_replicaset.yml deleted file mode 100644 index f33d93f4ac..0000000000 --- a/test/integration/targets/mongodb_replicaset/tasks/mongod_replicaset.yml +++ /dev/null @@ -1,43 +0,0 @@ -- name: Set mongodb_user user for redhat - set_fact: - mongodb_user: "mongod" - when: ansible_os_family == "RedHat" - -- name: Create directories for mongod processes - file: - path: "{{ remote_tmp_dir }}/mongod{{ item }}" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - recurse: yes - with_items: "{{ mongodb_nodes }}" - -- name: Create keyfile - copy: - dest: "{{ remote_tmp_dir }}/my.key" - content: | - fd2CUrbXBJpB4rt74A6F - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0600 - when: mongod_auth == True - -- name: Spawn mongod process without auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == False - -- name: Spawn mongod process with auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork --auth --keyFile my.key - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == True - -- name: Wait for mongod to start responding - wait_for: - port: "{{ item }}" - with_items: "{{ mongodb_nodes }}" diff --git a/test/integration/targets/mongodb_replicaset/tasks/mongod_teardown.yml b/test/integration/targets/mongodb_replicaset/tasks/mongod_teardown.yml deleted file mode 100644 index 7bc5d3d0a0..0000000000 --- a/test/integration/targets/mongodb_replicaset/tasks/mongod_teardown.yml +++ /dev/null @@ -1,27 +0,0 @@ -- name: Kill all mongod processes - command: pkill -{{ kill_signal }} mongod - ignore_errors: true - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - delay: 1 - with_items: "{{ pids_of_mongod }}" - -- name: Remove all mongod folders - file: - path: "{{ remote_tmp_dir }}/{{ item }}" - state: absent - with_items: - - mongod3001 - - mongod3002 - - mongod3003 - -- name: Remove all mongod sock files - shell: rm -Rf /tmp/mongodb*.sock diff --git a/test/integration/targets/mongodb_shard/aliases b/test/integration/targets/mongodb_shard/aliases deleted file mode 100644 index 8251a83e7f..0000000000 --- a/test/integration/targets/mongodb_shard/aliases +++ /dev/null @@ -1,7 +0,0 @@ -destructive -shippable/posix/group1 -skip/aix -skip/osx -skip/freebsd -skip/rhel -needs/root diff --git a/test/integration/targets/mongodb_shard/defaults/main.yml b/test/integration/targets/mongodb_shard/defaults/main.yml deleted file mode 100644 index 7ad82d6806..0000000000 --- a/test/integration/targets/mongodb_shard/defaults/main.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -# defaults file for test_mongodb_shard -mongodb_replicaset1: rs1 -mongodb_replicaset2: rs2 -configsrv_replicaset: cfg -test_mongo_auth: yes -mongodb_admin_user: test_root -mongodb_admin_password: saE_Rr9!gE6gh#e~R#nZ -debug: yes -mongod_auth: false -kill_signal: SIGTERM -# Should be one of -# --storageEngine wiredTiger --wiredTigerEngineConfigString="cache_size=200M" -# --storageEngine mmapv1 --nojournal -mongod_storage_engine_opts: "--storageEngine wiredTiger --wiredTigerEngineConfigString='cache_size=200M'" -mongodb_user: mongodb diff --git a/test/integration/targets/mongodb_shard/files/bash/ensure_primary.sh.j2 b/test/integration/targets/mongodb_shard/files/bash/ensure_primary.sh.j2 deleted file mode 100644 index cff0638f10..0000000000 --- a/test/integration/targets/mongodb_shard/files/bash/ensure_primary.sh.j2 +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -# This script is here because on some occassions the head mongodb does not become primary. - -PRIMARY=$1; -AUTH=$2; - -if [ "$AUTH" == "1" ]; then - if [ "$PRIMARY" == "3001" ]; then - mongo admin --port 3002 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.freeze(120)"; - mongo admin --port 3003 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.freeze(120)"; - mongo admin --port 3002 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.stepDown()"; - mongo admin --port 3003 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.stepDown()"; - elif [ "$PRIMARY" == "3004" ]; then - mongo admin --port 3005 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.freeze(120)"; - mongo admin --port 3006 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.freeze(120)"; - mongo admin --port 3005 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.stepDown()"; - mongo admin --port 3006 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} --eval "rs.stepDown()"; - else - echo "Unsupported port!"; - exit 1; - fi; -else - if [ "$PRIMARY" == "3001" ]; then - mongo admin --port 3002 --eval "rs.freeze(120)"; - mongo admin --port 3003 --eval "rs.freeze(120)"; - mongo admin --port 3002 --eval "rs.stepDown()"; - mongo admin --port 3003 --eval "rs.stepDown()"; - elif [ "$PRIMARY" == "3004" ]; then - mongo admin --port 3005 --eval "rs.freeze(120)"; - mongo admin --port 3006 --eval "rs.freeze(120)"; - mongo admin --port 3005 --eval "rs.stepDown()"; - mongo admin --port 3006 --eval "rs.stepDown()"; - else - echo "Unsupported port!"; - exit 1; - fi; -fi; diff --git a/test/integration/targets/mongodb_shard/files/js/is_primary.js b/test/integration/targets/mongodb_shard/files/js/is_primary.js deleted file mode 100644 index 7bb130614f..0000000000 --- a/test/integration/targets/mongodb_shard/files/js/is_primary.js +++ /dev/null @@ -1,13 +0,0 @@ -var done = false; -var iterations = 0; -while(rs.status()['myState'] != 1) { - if (!done) { - //print("State is not yet PRIMARY. Waiting..."); - done = true - } - sleep(1000); - iterations++; - if (iterations == 100) { - throw new Error("Exceeded iterations limit."); - } - } diff --git a/test/integration/targets/mongodb_shard/meta/main.yml b/test/integration/targets/mongodb_shard/meta/main.yml deleted file mode 100644 index 9d941be0bc..0000000000 --- a/test/integration/targets/mongodb_shard/meta/main.yml +++ /dev/null @@ -1,3 +0,0 @@ -dependencies: - - setup_mongodb - - setup_remote_tmp_dir diff --git a/test/integration/targets/mongodb_shard/tasks/main.yml b/test/integration/targets/mongodb_shard/tasks/main.yml deleted file mode 100644 index 53f9b2d222..0000000000 --- a/test/integration/targets/mongodb_shard/tasks/main.yml +++ /dev/null @@ -1,458 +0,0 @@ -# test code for the mongodb_shard module -# (c) 2019, Rhys Campbell - -# 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 . - -# ============================================================ - -- name: Ensure tests home exists - file: - path: "{{ remote_tmp_dir }}/tests" - state: directory - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset1 }}" - -- set_fact: - mongodb_nodes: [ 3001, 3002, 3003 ] - -- include_tasks: mongod_replicaset.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset2 }}" - -- set_fact: - mongodb_nodes: [ 3004, 3005, 3006 ] - -- include_tasks: mongod_replicaset.yml - -- name: Launch cfg server - command: mongod --configsvr --port 4000 --dbpath {{ remote_tmp_dir }}/config --logpath {{ remote_tmp_dir }}/config.log --smallfiles --replSet "{{ configsrv_replicaset }}" --fork - -- name: Create replicaset1 with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset1 }}" - members: - - "localhost:3001" - - "localhost:3002" - - "localhost:3003" - -- name: Create replicaset2 with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3004 - login_database: "admin" - replica_set: "{{ mongodb_replicaset2 }}" - members: - - "localhost:3004" - - "localhost:3005" - - "localhost:3006" - -- name: Create config srv replicaset with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 4000 - login_database: "admin" - replica_set: "{{ configsrv_replicaset }}" - validate: no - members: - - "localhost:4000" - -- name: Get config server replset mongo_output - command: mongo admin --port 4000 --eval "rs.status();" - register: cfg_replset_output - -- name: Assert that replset is a config server - assert: - that: - - "'\"configsvr\" : true' in cfg_replset_output.stdout" - - "'\"set\" : \"{{ configsrv_replicaset }}\"' in cfg_replset_output.stdout" - -- name: Launch mongos - command: mongos --configdb "{{ configsrv_replicaset }}/localhost:4000" --logpath "{{ remote_tmp_dir }}/tests/mongos.log" --port 27017 --fork - -- name: Ensure is_primary script exists on host - copy: - src: js/is_primary.js - dest: "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Ensure host reaches primary before proceeding 3001 - command: mongo admin --port 3001 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Ensure host reaches primary before proceeding 3004 - command: mongo admin --port 3004 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Add shard 1 - mongodb_shard: - login_user: admin - login_password: admin - shard: "{{ mongodb_replicaset1 }}/localhost:3001" - state: present - -- name: Add shard 2 - mongodb_shard: - login_user: admin - login_password: admin - shard: "{{ mongodb_replicaset2 }}/localhost:3004" - state: present - -- name: Get replicaset info - command: mongo admin --eval "sh.status()" --port 27017 - register: mongo_output - -- name: Assert shard name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}/localhost:3001,localhost:3002,localhost:3003' in mongo_output.stdout" - - "'{{ mongodb_replicaset2 }}/localhost:3004,localhost:3005,localhost:3006' in mongo_output.stdout" - - "'balancer' in mongo_output.stdout" - -- name: Remove shard 2 - mongodb_shard: - login_user: admin - login_password: admin - shard: "{{ mongodb_replicaset2 }}" - state: absent - -- name: Get replicaset info - command: mongo admin --eval "sh.status()" --port 27017 - register: mongo_output - -- name: Assert shard 2 is draining - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}/localhost:3001,localhost:3002,localhost:3003' in mongo_output.stdout" - - "'\"draining\" : true' in mongo_output.stdout" - - "'balancer' in mongo_output.stdout" - -- name: Run remove command again to finalize shard removal - mongodb_shard: - login_user: admin - login_password: admin - shard: "{{ mongodb_replicaset2 }}" - state: absent - -- name: Get replicaset info - command: mongo admin --eval "sh.status()" --port 27017 - register: mongo_output - -- name: Assert shard 2 is not present - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}/localhost:3001,localhost:3002,localhost:3003' in mongo_output.stdout" - - "'{{ mongodb_replicaset2 }}/localhost:3004,localhost:3005,localhost:3006' not in mongo_output.stdout" - - "'balancer' in mongo_output.stdout" - -# Repeat of above with auth enabled -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset1 }}" - -- set_fact: - mongodb_nodes: [ 3001, 3002, 3003 ] - -- include_tasks: mongod_replicaset.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset2 }}" - -- set_fact: - mongodb_nodes: [ 3004, 3005, 3006 ] - -- include_tasks: mongod_replicaset.yml - -- name: Create replicaset1 with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3001 - login_database: "admin" - replica_set: "{{ mongodb_replicaset1 }}" - members: - - "localhost:3001" - - "localhost:3002" - - "localhost:3003" - -- name: Create replicaset2 with module - mongodb_replicaset: - login_user: admin - login_password: secret - login_host: "localhost" - login_port: 3004 - login_database: "admin" - replica_set: "{{ mongodb_replicaset2 }}" - members: - - "localhost:3004" - - "localhost:3005" - - "localhost:3006" - -- name: Launch cfg server - command: mongod --configsvr --port 4000 --dbpath {{ remote_tmp_dir }}/config --logpath {{ remote_tmp_dir }}/config.log --smallfiles --replSet "{{ configsrv_replicaset }}" --fork - -- name: Create config srv replicaset with module - mongodb_replicaset: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_port: 4000 - login_database: "admin" - replica_set: "{{ configsrv_replicaset }}" - validate: no - members: - - "localhost:4000" - -- name: Ensure host reaches primary before proceeding 3001 - command: mongo admin --port 3001 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Ensure host reaches primary before proceeding 3004 - command: mongo admin --port 3004 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Ensure host reaches primary before proceeding 4000 - command: mongo admin --port 4000 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Add mongodb admin user to each shard 3.4+ - mongodb_user: - login_host: localhost - login_port: "{{ item.port }}" - replica_set: "{{ item.rs }}" - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: ["root"] - state: present - register: mongo_admin_user - with_items: - - { "port": 3001, "rs": "{{ mongodb_replicaset1 }}" } - - { "port": 3004, "rs": "{{ mongodb_replicaset2 }}" } - - { "port": 4000, "rs": "{{ configsrv_replicaset }}" } - when: mongodb_version not in ["3.2", "4.0"] and test_mongo_auth == True - -- name: Add mongodb admin user to each shard 3.2 ^ 4.0 - mongodb_user: - login_host: localhost - login_port: "{{ item.port }}" - replica_set: "{{ item.rs }}" - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: ["root"] - state: present - register: mongo_admin_user - with_items: - - { "port": 3001, "rs": "{{ mongodb_replicaset1 }}" } - - { "port": 3004, "rs": "{{ mongodb_replicaset2 }}" } - when: mongodb_version not in ["3.2", "4.0"] and test_mongo_auth == True - -# mongodb_user throws an error when creating a user on 3.2 (also on 4.0 with Ubuntu 18.04) -# 'majority' is the only valid write concern when writing to config server replica sets -- name: Copy create_user_root_3.2.js.j2 template to host - template: - src: create_user_root_3.2.js.j2 - dest: /root/create_user_root_3.2.js - when: mongodb_version in ["3.2", "4.0"] - -- name: Copy script to host - template: - src: files/bash/ensure_primary.sh.j2 - dest: /root/ensure_primary.sh - -- name: Execute script for 3001 - script: /root/ensure_primary.sh 3001 0 -# We do this here because sometimes 3004 instance seems to be demoted -- name: Execute script for 3004 - script: /root/ensure_primary.sh 3004 0 - -- name: Create admin user on 3.2 and 4.0 config replset - shell: mongo admin --port {{ item }} /root/create_user_root_3.2.js - with_items: - - 4000 - - 3001 - - 3004 - when: mongodb_version in ["3.2", "4.0"] - -- name: Murder all mongod processes - shell: pkill -{{ kill_signal }} mongod || true; - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - with_items: "{{ pids_of_mongod }}" - -- set_fact: - current_replicaset: "{{ mongodb_replicaset1 }}" - -- set_fact: - mongodb_nodes: [ 3001, 3002, 3003 ] - -- set_fact: - mongod_auth: true - -- include_tasks: mongod_replicaset.yml - -- set_fact: - current_replicaset: "{{ mongodb_replicaset2 }}" - -- set_fact: - mongodb_nodes: [ 3004, 3005, 3006 ] - -- set_fact: - mongod_auth: true - -- include_tasks: mongod_replicaset.yml - -- name: Launch cfg server with auth - command: mongod --configsvr --port 4000 --dbpath {{ remote_tmp_dir }}/config --logpath {{ remote_tmp_dir }}/config.log --smallfiles --replSet "{{ configsrv_replicaset }}" --fork --auth --keyFile {{ remote_tmp_dir }}/my.key - -- name: Execute script for 3001 - script: /root/ensure_primary.sh 3001 1 - -- name: Execute script for 3004 - script: /root/ensure_primary.sh 3004 1 - -- name: Ensure host reaches primary before proceeding 3001 - command: mongo admin --port 3001 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Ensure host reaches primary before proceeding 3004 - command: mongo admin --port 3004 -u {{ mongodb_admin_user }} -p {{ mongodb_admin_password }} "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Launch mongos - command: mongos --configdb "{{ configsrv_replicaset }}/localhost:4000" --logpath "{{ remote_tmp_dir }}/mongos.log" --port 27017 --fork --keyFile {{ remote_tmp_dir }}/my.key - -- name: Wait for mongos to become active - wait_for: - host: localhost - port: 4000 - delay: 1 - -- name: Add shard 1 - mongodb_shard: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - shard: "{{ mongodb_replicaset1 }}/localhost:3001" - state: present - -- name: Add shard 2 - mongodb_shard: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - shard: "{{ mongodb_replicaset2 }}/localhost:3004" - state: present - -- name: Test with bad password - mongodb_shard: - login_user: "{{ mongodb_admin_user }}" - login_password: XXXXXXXXXXXX - shard: "{{ mongodb_replicaset2 }}/localhost:3004" - state: present - register: mongodb_shard_bad_pw - ignore_errors: True - -- name: Assert login failed - assert: - that: - - "mongodb_shard_bad_pw.changed == False" - - "'unable to connect to database: Authentication failed.' == mongodb_shard_bad_pw.msg" - -- name: Get replicaset info - command: mongo admin --eval "sh.status()" --port 27017 -u "{{ mongodb_admin_user }}" -p "{{ mongodb_admin_password }}" - register: mongo_output - -- name: Assert shard name is in mongo_output - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}/localhost:3001,localhost:3002,localhost:3003' in mongo_output.stdout" - - "'{{ mongodb_replicaset2 }}/localhost:3004,localhost:3005,localhost:3006' in mongo_output.stdout" - - "'balancer' in mongo_output.stdout" - -- name: Remove shard 2 - mongodb_shard: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - shard: "{{ mongodb_replicaset2 }}" - state: absent - -- name: Get replicaset info - command: mongo admin --eval "sh.status()" --port 27017 -u "{{ mongodb_admin_user }}" -p "{{ mongodb_admin_password }}" - register: mongo_output - -- name: Assert shard 2 is draining - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}/localhost:3001,localhost:3002,localhost:3003' in mongo_output.stdout" - - "'\"draining\" : true' in mongo_output.stdout" - - "'balancer' in mongo_output.stdout" - -- name: Run remove command again to finalize shard removal - mongodb_shard: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - shard: "{{ mongodb_replicaset2 }}" - state: absent - -- name: Get replicaset info - command: mongo admin --eval "sh.status()" --port 27017 -u "{{ mongodb_admin_user }}" -p "{{ mongodb_admin_password }}" - register: mongo_output - -- name: Assert shard 2 is not present - assert: - that: - - "mongo_output.changed == true" - - "'{{ mongodb_replicaset1 }}/localhost:3001,localhost:3002,localhost:3003' in mongo_output.stdout" - - "'{{ mongodb_replicaset2 }}/localhost:3004,localhost:3005,localhost:3006' not in mongo_output.stdout" - - "'balancer' in mongo_output.stdout" - -# TODO - Readd this test once we support serverSelectionTimeoutMS / connectTimeoutMS -#- name: Run test with unknown host -# mongodb_shard: -# login_user: "{{ mongodb_admin_user }}" -# login_password: "{{ mongodb_admin_password }}" -# login_host: "idonotexist" -# shard: "{{ mongodb_replicaset2 }}" -# state: absent -# ignore_errors: True -# register: host_does_not_exist - -#- name: Assert that "Name or service not known" is in error -# assert: -# that: -# - "host_does_not_exist.changed == False" -# - "'unable to connect to database: idonotexist:27017: [Errno -2] Name or service not known' == host_does_not_exist.msg" - -# Final clean up to prevent "directory not empty" error -- include_tasks: mongod_teardown.yml diff --git a/test/integration/targets/mongodb_shard/tasks/mongod_replicaset.yml b/test/integration/targets/mongodb_shard/tasks/mongod_replicaset.yml deleted file mode 100644 index fe1c2ffe62..0000000000 --- a/test/integration/targets/mongodb_shard/tasks/mongod_replicaset.yml +++ /dev/null @@ -1,51 +0,0 @@ -- name: Set mongodb_user user for redhat - set_fact: - mongodb_user: "mongod" - when: ansible_os_family == "RedHat" - -- name: Create directories for mongod processes - file: - path: "{{ remote_tmp_dir }}/mongod{{ item }}" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - recurse: yes - with_items: "{{ mongodb_nodes }}" - -- name: Ensure {{ remote_tmp_dir }}/config dir exists - file: - path: "{{ remote_tmp_dir }}/config" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - -- name: Create keyfile - copy: - dest: "{{ remote_tmp_dir }}/my.key" - content: | - fd2CUrbXBJpB4rt74A6F - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0600 - when: mongod_auth == True - -- name: Spawn mongod process without auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == False - -- name: Spawn mongod process with auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork --auth --keyFile my.key - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == True - -- name: Wait for mongod to start responding - wait_for: - port: "{{ item }}" - with_items: "{{ mongodb_nodes }}" diff --git a/test/integration/targets/mongodb_shard/tasks/mongod_teardown.yml b/test/integration/targets/mongodb_shard/tasks/mongod_teardown.yml deleted file mode 100644 index 3af09d59be..0000000000 --- a/test/integration/targets/mongodb_shard/tasks/mongod_teardown.yml +++ /dev/null @@ -1,35 +0,0 @@ -- name: Kill all mongod processes - command: pkill -{{ kill_signal }} mongod - ignore_errors: true - -- name: Kill all mongos processes - command: pkill -{{ kill_signal }} mongos - ignore_errors: true - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - delay: 1 - with_items: "{{ pids_of_mongod }}" - -- name: Remove all mongod folders - file: - path: "{{ remote_tmp_dir }}/{{ item }}" - state: absent - with_items: - - mongod3001 - - mongod3002 - - mongod3003 - - mongod3004 - - mongod3005 - - mongod3006 - - config - -- name: Remove all mongod sock files - shell: rm -Rf /tmp/mongodb*.sock diff --git a/test/integration/targets/mongodb_shard/templates/create_user_root_3.2.js.j2 b/test/integration/targets/mongodb_shard/templates/create_user_root_3.2.js.j2 deleted file mode 100644 index 368cb966bf..0000000000 --- a/test/integration/targets/mongodb_shard/templates/create_user_root_3.2.js.j2 +++ /dev/null @@ -1,8 +0,0 @@ -db.createUser( - { - user: "{{ mongodb_admin_user }}", - pwd: "{{ mongodb_admin_password }}", - roles: [ { role: "root", db: "admin" } ] - }, - { w: "majority", j: true, wtimeout: 10000 } -) diff --git a/test/integration/targets/mongodb_user/aliases b/test/integration/targets/mongodb_user/aliases deleted file mode 100644 index 0aa5f9a9bf..0000000000 --- a/test/integration/targets/mongodb_user/aliases +++ /dev/null @@ -1,8 +0,0 @@ -destructive -shippable/posix/group1 -skip/aix -skip/osx -skip/freebsd -skip/rhel -needs/root -disabled diff --git a/test/integration/targets/mongodb_user/defaults/main.yml b/test/integration/targets/mongodb_user/defaults/main.yml deleted file mode 100644 index aac55526df..0000000000 --- a/test/integration/targets/mongodb_user/defaults/main.yml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# defaults file for test_mongodb_user -mongodb_admin_user: test_root -mongodb_admin_password: saE_Rr9!gE6gh#e~R#nZ -mongod_auth: false -kill_signal: SIGTERM -# Should be one of -# --storageEngine wiredTiger --wiredTigerEngineConfigString="cache_size=200M" -# --storageEngine mmapv1 --nojournal -mongod_storage_engine_opts: "--storageEngine wiredTiger --wiredTigerEngineConfigString='cache_size=200M'" -mongodb_user: mongodb -mongodb_user_list: - - { "name": "user1", "password": "password1", "roles": "read", "database": "test" } - - { "name": "user2", "password": "password2", "roles": "readWrite", "database": "test" } - - { "name": "user3", "password": "password3", "roles": "dbAdmin", "database": "test" } - - { "name": "user4", "password": "password4", "roles": "userAdmin", "database": "test" } - - { "name": "user5", "password": "password5", "roles": "clusterAdmin", "database": "admin" } - - { "name": "user6", "password": "password6", "roles": "readAnyDatabase", "database": "admin" } - - { "name": "user7", "password": "password7", "roles": "readWriteAnyDatabase", "database": "admin" } - - { "name": "user8", "password": "password8", "roles": "userAdminAnyDatabase", "database": "admin" } - - { "name": "user9", "password": "password9", "roles": "dbAdminAnyDatabase", "database": "admin" } diff --git a/test/integration/targets/mongodb_user/files/js/is_primary.js b/test/integration/targets/mongodb_user/files/js/is_primary.js deleted file mode 100644 index 7bb130614f..0000000000 --- a/test/integration/targets/mongodb_user/files/js/is_primary.js +++ /dev/null @@ -1,13 +0,0 @@ -var done = false; -var iterations = 0; -while(rs.status()['myState'] != 1) { - if (!done) { - //print("State is not yet PRIMARY. Waiting..."); - done = true - } - sleep(1000); - iterations++; - if (iterations == 100) { - throw new Error("Exceeded iterations limit."); - } - } diff --git a/test/integration/targets/mongodb_user/meta/main.yml b/test/integration/targets/mongodb_user/meta/main.yml deleted file mode 100644 index 9d941be0bc..0000000000 --- a/test/integration/targets/mongodb_user/meta/main.yml +++ /dev/null @@ -1,3 +0,0 @@ -dependencies: - - setup_mongodb - - setup_remote_tmp_dir diff --git a/test/integration/targets/mongodb_user/tasks/main.yml b/test/integration/targets/mongodb_user/tasks/main.yml deleted file mode 100644 index f2f061f2c4..0000000000 --- a/test/integration/targets/mongodb_user/tasks/main.yml +++ /dev/null @@ -1,226 +0,0 @@ -# test code for the mongodb_user module -# (c) 2019, Rhys Campbell - -# 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 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 . - -# ============================================================ - -- name: Ensure tests home exists - file: - path: "{{ remote_tmp_dir }}/tests" - state: directory - -- include_tasks: mongod_teardown.yml - -- set_fact: - current_replicaset: mongodb_user_tests_replicaset - -- set_fact: - mongodb_nodes: [ 3001, 3002, 3003 ] - -- include_tasks: mongod_replicaset.yml - -- name: Create current_replicaset with module - mongodb_replicaset: - login_port: 3001 - replica_set: "{{ current_replicaset }}" - members: - - "localhost:3001" - - "localhost:3002" - - "localhost:3003" - -- name: Ensure is_primary script exists on host - copy: - src: js/is_primary.js - dest: "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Ensure host reaches primary before proceeding 3001 - command: mongo admin --port 3001 "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Create admin user with module - mongodb_user: - login_port: 3001 - replica_set: "{{ current_replicaset }}" - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: root - state: present - register: mongodb_admin_user_created - -- assert: - that: - - mongodb_admin_user_created.changed == True - -- name: Kill all mongod processes - command: pkill -{{ kill_signal }} mongod - ignore_errors: true - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - delay: 3 - with_items: "{{ pids_of_mongod }}" - -- set_fact: - mongod_auth: true - -- include_tasks: mongod_replicaset.yml -# Tests with auth enable - -- name: Ensure host reaches primary before proceeding 3001 - command: mongo admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" "{{ remote_tmp_dir }}/tests/is_primary.js" - -- name: Run admin user creation again - mongodb_user: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_database: admin - login_port: 3001 - replica_set: "{{ current_replicaset }}" - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: root - state: present - update_password: on_create - register: mongodb_admin_user_created - -- assert: - that: - - mongodb_admin_user_created.changed == False - -- name: Run admin user creation again with forced pw update - mongodb_user: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_database: admin - login_port: 3001 - replica_set: "{{ current_replicaset }}" - database: admin - name: "{{ mongodb_admin_user }}" - password: "{{ mongodb_admin_password }}" - roles: root - state: present - update_password: always - register: mongodb_admin_user_created - -- assert: - that: - - mongodb_admin_user_created.changed == True - -- name: Run user creation - mongodb_user: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_database: admin - login_port: 3001 - replica_set: "{{ current_replicaset }}" - database: "{{ item.database }}" - name: "{{ item.name }}" - password: "{{ item.password }}" - roles: "{{ item.roles }}" - state: present - with_items: "{{ mongodb_user_list }}" - -- name: Test login for all users - shell: mongo "{{ item.database }}" --port 3001 --username "{{ item.name }}" --password "{{ item.password }}" --eval "printjson(db.getCollectionNames())" - with_items: "{{ mongodb_user_list }}" - register: login_test - -- name: Assert all logins successful - assert: - that: "{{ item.rc == 0 }}" - with_items: "{{ login_test.results }}" - -- name: Get admin db users - shell: mongo admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" - register: admin_db_users - -- name: Assert that roles exist in admin db output - assert: - that: - - "'clusterAdmin' in admin_db_users.stdout" - - "'readAnyDatabase' in admin_db_users.stdout" - - "'readWriteAnyDatabase' in admin_db_users.stdout" - - "'userAdminAnyDatabase' in admin_db_users.stdout" - - "'dbAdminAnyDatabase' in admin_db_users.stdout" - -- name: Get test db users - shell: mongo test --authenticationDatabase admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" - register: test_db_users - -- name: Assert that roles exist in test db output - assert: - that: - - "'\"read\"' in test_db_users.stdout" - - "'readWrite' in test_db_users.stdout" - - "'dbAdmin' in test_db_users.stdout" - - "'userAdmin' in test_db_users.stdout" - -- name: Drop users in test db - mongodb_user: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_database: admin - login_port: 3001 - replica_set: "{{ current_replicaset }}" - database: "{{ item.database }}" - name: "{{ item.name }}" - state: absent - with_items: "{{ mongodb_user_list }}" - when: item.database == "test" - -- name: Get test db users - shell: mongo test --authenticationDatabase admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" - register: test_db_users - -- name: Assert that roles do not exist in test db output - assert: - that: - - "'user1' not in test_db_users.stdout" - - "'user2' not in test_db_users.stdout" - - "'user3' not in test_db_users.stdout" - - "'user4' not in test_db_users.stdout" - -- name: Create user with multiple roles in test db - mongodb_user: - login_user: "{{ mongodb_admin_user }}" - login_password: "{{ mongodb_admin_password }}" - login_database: admin - login_port: 3001 - replica_set: "{{ current_replicaset }}" - database: test - name: test_multiple_roles - password: secret - roles: readWrite,dbAdmin,userAdmin - state: present - -- name: Get test db users - shell: mongo test --authenticationDatabase admin --port 3001 --username "{{ mongodb_admin_user }}" --password "{{ mongodb_admin_password }}" --eval "printjson(db.getUsers())" - register: test_db_users - -- debug: - var: test_db_users - -# Clean up -- include_tasks: mongod_teardown.yml diff --git a/test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml b/test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml deleted file mode 100644 index fe1c2ffe62..0000000000 --- a/test/integration/targets/mongodb_user/tasks/mongod_replicaset.yml +++ /dev/null @@ -1,51 +0,0 @@ -- name: Set mongodb_user user for redhat - set_fact: - mongodb_user: "mongod" - when: ansible_os_family == "RedHat" - -- name: Create directories for mongod processes - file: - path: "{{ remote_tmp_dir }}/mongod{{ item }}" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - recurse: yes - with_items: "{{ mongodb_nodes }}" - -- name: Ensure {{ remote_tmp_dir }}/config dir exists - file: - path: "{{ remote_tmp_dir }}/config" - state: directory - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0755 - -- name: Create keyfile - copy: - dest: "{{ remote_tmp_dir }}/my.key" - content: | - fd2CUrbXBJpB4rt74A6F - owner: "{{ mongodb_user }}" - group: "{{ mongodb_user }}" - mode: 0600 - when: mongod_auth == True - -- name: Spawn mongod process without auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == False - -- name: Spawn mongod process with auth - command: mongod --shardsvr --smallfiles {{ mongod_storage_engine_opts }} --dbpath mongod{{ item }} --port {{ item }} --replSet {{ current_replicaset }} --logpath mongod{{ item }}/log.log --fork --auth --keyFile my.key - args: - chdir: "{{ remote_tmp_dir }}" - with_items: "{{ mongodb_nodes | sort }}" - when: mongod_auth == True - -- name: Wait for mongod to start responding - wait_for: - port: "{{ item }}" - with_items: "{{ mongodb_nodes }}" diff --git a/test/integration/targets/mongodb_user/tasks/mongod_teardown.yml b/test/integration/targets/mongodb_user/tasks/mongod_teardown.yml deleted file mode 100644 index 7bc5d3d0a0..0000000000 --- a/test/integration/targets/mongodb_user/tasks/mongod_teardown.yml +++ /dev/null @@ -1,27 +0,0 @@ -- name: Kill all mongod processes - command: pkill -{{ kill_signal }} mongod - ignore_errors: true - -- name: Getting pids for mongod - pids: - name: mongod - register: pids_of_mongod - -- name: Wait for all mongod processes to exit - wait_for: - path: "/proc/{{ item }}/status" - state: absent - delay: 1 - with_items: "{{ pids_of_mongod }}" - -- name: Remove all mongod folders - file: - path: "{{ remote_tmp_dir }}/{{ item }}" - state: absent - with_items: - - mongod3001 - - mongod3002 - - mongod3003 - -- name: Remove all mongod sock files - shell: rm -Rf /tmp/mongodb*.sock diff --git a/test/sanity/ignore.txt b/test/sanity/ignore.txt index 441c0fbb37..6bced3e4b2 100644 --- a/test/sanity/ignore.txt +++ b/test/sanity/ignore.txt @@ -1679,10 +1679,6 @@ lib/ansible/modules/commands/command.py validate-modules:nonexistent-parameter-d lib/ansible/modules/commands/command.py validate-modules:parameter-list-no-elements lib/ansible/modules/commands/command.py validate-modules:undocumented-parameter lib/ansible/modules/commands/expect.py validate-modules:doc-missing-type -lib/ansible/modules/database/mongodb/mongodb_parameter.py use-argspec-type-path -lib/ansible/modules/database/mongodb/mongodb_replicaset.py use-argspec-type-path -lib/ansible/modules/database/mongodb/mongodb_shard.py use-argspec-type-path -lib/ansible/modules/database/mongodb/mongodb_user.py use-argspec-type-path lib/ansible/modules/files/acl.py validate-modules:parameter-type-not-in-doc lib/ansible/modules/files/assemble.py validate-modules:nonexistent-parameter-documented lib/ansible/modules/files/blockinfile.py validate-modules:doc-choices-do-not-match-spec -- cgit v1.2.1