mirror of https://github.com/ansible/ansible.git
Migrated to community.mongo
parent
0ed8af9021
commit
46b865c7d6
@ -1,444 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright: (c) 2020, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
|
||||
# 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()
|
@ -1,223 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2016, Loic Blot <loic.blot@unix-experience.fr>
|
||||
# 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()
|
@ -1,418 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright: (c) 2018, Rhys Campbell <rhys.james.campbell@googlemail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = 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()
|
@ -1,351 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# (c) 2018, Rhys Campbell <rhys.james.campbell@googlemail.com>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
__metaclass__ = type
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: 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 <replicaset>/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()
|
@ -1,474 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# (c) 2012, Elliott Foster <elliott@fourkitchens.com>
|
||||
# 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()
|
@ -1,181 +0,0 @@
|
||||
# (c) 2018, Matt Martz <matt@sivel.net>
|
||||
# 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__()
|
@ -1,238 +0,0 @@
|
||||
# (c) 2016, Marcos Diez <marcos@unitron.com.br>
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from ansible.module_utils.six import string_types, integer_types
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = '''
|
||||
author: 'Marcos Diez <marcos (at) unitron.com.br>'
|
||||
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
|
@ -1,5 +0,0 @@
|
||||
destructive
|
||||
shippable/posix/group4
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/freebsd
|
@ -1,4 +0,0 @@
|
||||
mongodb_default_port: 27017
|
||||
mongodb_admin_user: admin
|
||||
mongodb_admin_password: admin
|
||||
mongodb_default_db: admin
|
@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
- setup_mongodb_v4
|
||||
- setup_remote_tmp_dir
|
@ -1,8 +0,0 @@
|
||||
# Copyright 2020, Andrew Klychkov <aaklychkov@mail.ru>
|
||||
# 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', '>=')
|
@ -1,60 +0,0 @@
|
||||
# Copyright 2020, Andrew Klychkov <aaklychkov@mail.ru>
|
||||
# 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
|
@ -1,7 +0,0 @@
|
||||
destructive
|
||||
shippable/posix/group1
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/freebsd
|
||||
skip/rhel
|
||||
needs/root
|
@ -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" }
|
@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
- setup_mongodb
|
||||
- setup_remote_tmp_dir
|
@ -1,143 +0,0 @@
|
||||
# test code for the mongodb_parameter module
|
||||
# (c) 2019, Rhys Campbell <rhys.james.campbell@googlemail.com>
|
||||
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ============================================================
|
||||
|
||||
- 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
|
@ -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 }}"
|
@ -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
|
@ -1,7 +0,0 @@
|
||||
destructive
|
||||
shippable/posix/group1
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/freebsd
|
||||
skip/rhel
|
||||
needs/root
|
@ -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
|
@ -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.");
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
- setup_mongodb
|
||||
- setup_remote_tmp_dir
|
@ -1,540 +0,0 @@
|
||||
# test code for the mongodb_replicaset module
|
||||
# (c) 2019, Rhys Campbell <rhys.james.campbell@googlemail.com>
|
||||
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ============================================================
|
||||
|
||||
- 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
|
@ -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 }}"
|
@ -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
|
@ -1,7 +0,0 @@
|
||||
destructive
|
||||
shippable/posix/group1
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/freebsd
|
||||
skip/rhel
|
||||
needs/root
|
@ -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
|
@ -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;
|
@ -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.");
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
- setup_mongodb
|
||||
- setup_remote_tmp_dir
|
@ -1,458 +0,0 @@
|
||||
# test code for the mongodb_shard module
|
||||
# (c) 2019, Rhys Campbell <rhys.james.campbell@googlemail.com>
|
||||
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ============================================================
|
||||
|
||||
- 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
|
@ -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 }}"
|
@ -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
|
@ -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 }
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
destructive
|
||||
shippable/posix/group1
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/freebsd
|
||||
skip/rhel
|
||||
needs/root
|
||||
disabled
|
@ -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" }
|
@ -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.");
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
dependencies:
|
||||
- setup_mongodb
|
||||
- setup_remote_tmp_dir
|
@ -1,226 +0,0 @@
|
||||
# test code for the mongodb_user module
|
||||
# (c) 2019, Rhys Campbell <rhys.james.campbell@googlemail.com>
|
||||
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
# ============================================================
|
||||
|
||||
- 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
|
@ -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 }}"
|
@ -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
|
Loading…
Reference in New Issue