diff --git a/.travis.yml b/.travis.yml index 2c7740d4..e2e3d8b2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,6 @@ env: DISTRIBUTION=debian DIST_VERSION=9-builded MONGODB_VERSION=3.6 - MONGODB_PACKAGE=mongodb-org - > DISTRIBUTION=debian DIST_VERSION=8-builded diff --git a/README.md b/README.md index 8d122504..6a47e890 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,8 @@ mongodb_security_keyfile: /etc/mongodb-keyfile # Specify path to keyfile with pa mongodb_storage_dbpath: /data/db # Directory for datafiles mongodb_storage_dirperdb: false # Use one directory per DB -# The storage engine for the mongod database. Available values: -# 'mmapv1', 'wiredTiger' -mongodb_storage_engine: "{{ 'mmapv1' if mongodb_version[0:3] == '3.0' else 'wiredTiger' }}" +# The storage engine for the mongod database +mongodb_storage_engine: "wiredTiger" # mmapv1 specific options mongodb_storage_quota_enforced: false # Limits each database to a certain number of files mongodb_storage_quota_maxfiles: 8 # Number of quota files per DB diff --git a/defaults/main.yml b/defaults/main.yml index dcdf236d..a727e325 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -2,7 +2,7 @@ mongodb_package: mongodb-org mongodb_package_state: present -mongodb_version: "3.6" +mongodb_version: "4.0" mongodb_apt_keyserver: keyserver.ubuntu.com mongodb_apt_key_id: "3.4": "0C49F3730359A14518585931BC711F9BA15703C6" @@ -29,8 +29,8 @@ mongodb_net_ipv6: false # Enable IPv6 support (disabled mongodb_net_maxconns: 65536 # Max number of simultaneous connections mongodb_net_port: 27017 # Specify port number mongodb_net_ssl: disabled # Enable or disable ssl connections -mongodb_net_ssl_mode: # Set the ssl mode (RequireSSL / preferSSL / AllowSSL / disabled) -mongodb_net_ssl_pemfile: # Location of the pemfile to use for ssl +mongodb_net_ssl_mode: "" # Set the ssl mode (RequireSSL / preferSSL / AllowSSL / disabled) +mongodb_net_ssl_pemfile: "" # Location of the pemfile to use for ssl ## processManagement Options # Fork server process @@ -47,8 +47,7 @@ mongodb_security_javascript_enabled: false mongodb_storage_dbpath: /data/db # Directory for datafiles mongodb_storage_dirperdb: false # Use one directory per DB -# The storage engine for the mongod database. Available values: -# 'mmapv1', 'wiredTiger' +# The storage engine for the mongod database mongodb_storage_engine: "wiredTiger" # mmapv1 specific options mongodb_storage_quota_enforced: false # Limits each database to a certain number of files @@ -73,7 +72,7 @@ mongodb_operation_profiling_slow_op_threshold_ms: 100 mongodb_operation_profiling_mode: "off" ## replication Options -mongodb_replication_replset: # Enable replication [/] +mongodb_replication_replset: "" # Enable replication mongodb_replication_replindexprefetch: "all" # specify index prefetching behavior (if secondary) [none|_id_only|all] mongodb_replication_oplogsize: 1024 # specifies a maximum size in megabytes for the replication operation log diff --git a/files/disable-transparent-hugepages.init b/files/disable-transparent-hugepages.init deleted file mode 100644 index c3a5d5e7..00000000 --- a/files/disable-transparent-hugepages.init +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description="Disable transparent hugepages" -Before=mongodb.service - -[Service] -Type=oneshot -ExecStart=/opt/disable-transparent-hugepages.sh - -[Install] -WantedBy=multi-user.target diff --git a/files/disable-transparent-hugepages.service b/files/disable-transparent-hugepages.service new file mode 100644 index 00000000..8e0c3b73 --- /dev/null +++ b/files/disable-transparent-hugepages.service @@ -0,0 +1,21 @@ +[Unit] +Description="Disable Transparent Hugepage before MongoDB boots" +#WARN: check service name on your system +# If you are using MongoDB Cloud, service name is "mongodb-mms-automation-agent.service" +Before=mongodb.service + +[Service] +Type=oneshot +ExecStart=-/bin/bash -c 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' +ExecStart=-/bin/bash -c 'echo never > /sys/kernel/mm/transparent_hugepage/defrag' +ExecStart=-/bin/bash -c 'echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled' +ExecStart=-/bin/bash -c 'echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag' +ExecStart=-/bin/bash -c 'echo 0 > /sys/kernel/mm/transparent_hugepage/khugepaged/defrag' +ExecStart=-/bin/bash -c 'echo 0 > /sys/kernel/mm/redhat_transparent_hugepage/khugepaged/defrag' +ExecStart=-/bin/bash -c 'echo no > /sys/kernel/mm/transparent_hugepage/khugepaged/defrag' +ExecStart=-/bin/bash -c 'echo no > /sys/kernel/mm/redhat_transparent_hugepage/khugepaged/defrag' + +[Install] +#WARN: check service name on your system +# If you are using MongoDB Cloud, service name is "mongodb-mms-automation-agent.service" +RequiredBy=mongodb.service diff --git a/handlers/main.yml b/handlers/main.yml index 6ca9d4d5..84a055b2 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,20 +1,40 @@ --- +- name: reload systemd + systemd: + daemon_reload: yes + when: ansible_service_mgr == "systemd" and mongodb_manage_service + - name: mongodb reload service: name={{ mongodb_daemon_name }} state=reloaded - when: mongodb_manage_service + when: mongodb_manage_service|bool - name: mongodb restart service: name={{ mongodb_daemon_name }} state=restarted - when: mongodb_manage_service + when: mongodb_manage_service|bool - name: mongodb-mms-monitoring-agent restart service: name=mongodb-mms-monitoring-agent state=restarted - when: mongodb_manage_service - -- name: reload systemd - shell: systemctl daemon-reload - when: mongodb_is_systemd and mongodb_manage_service + when: mongodb_manage_service|bool - name: restart sysfsutils service: name=sysfsutils state=restarted + +- name: service started + service: + name: "{{ mongodb_daemon_name }}" + state: started + +- name: wait when mongodb is started + wait_for: + host: "{{ item }}" + port: "{{ mongodb_net_port }}" + timeout: 120 + with_items: "{{ mongodb_net_bindip.split(',') | map('replace', '0.0.0.0', '127.0.0.1') | list }}" + +- name: wait when mongodb is started on localhost + wait_for: + host: "127.0.0.1" + port: "{{ mongodb_net_port }}" + delay: 5 + timeout: 120 diff --git a/library/mongodb_user_fixed.py b/library/mongodb_user_fixed.py deleted file mode 100644 index 3c04724b..00000000 --- a/library/mongodb_user_fixed.py +++ /dev/null @@ -1,462 +0,0 @@ -#!/usr/bin/python - -# (c) 2012, Elliott Foster -# Sponsored by Four Kitchens http://fourkitchens.com. -# (c) 2014, Epic Games, Inc. -# -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - -from __future__ import absolute_import, division, print_function -__metaclass__ = type - - -ANSIBLE_METADATA = {'metadata_version': '1.1', - 'status': ['preview'], - 'supported_by': 'community'} - - -DOCUMENTATION = ''' ---- -module: mongodb_user -short_description: Adds or removes a user from a MongoDB database. -description: - - Adds or removes a user from a MongoDB database. -version_added: "1.1" -options: - login_user: - description: - - The username used to authenticate with - required: false - default: null - login_password: - description: - - The password used to authenticate with - required: false - default: null - login_host: - description: - - The host running the database - required: false - default: localhost - login_port: - description: - - The port to connect to - required: false - default: 27017 - login_database: - version_added: "2.0" - description: - - The database where login credentials are stored - required: false - default: admin - replica_set: - version_added: "1.6" - description: - - Replica set to connect to (automatically connects to primary for writes) - required: false - default: null - database: - description: - - The name of the database to add/remove the user from - required: true - name: - description: - - The name of the user to add or remove - required: true - default: null - aliases: [ 'user' ] - password: - description: - - The password to use for the user - required: false - default: null - ssl: - version_added: "1.8" - description: - - Whether to use an SSL connection when connecting to the database - default: False - 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. - required: false - default: "CERT_REQUIRED" - choices: ["CERT_REQUIRED", "CERT_OPTIONAL", "CERT_NONE"] - roles: - version_added: "1.3" - 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." - required: false - default: "readWrite" - state: - description: - - The database user state - required: false - default: present - choices: [ "present", "absent" ] - update_password: - required: false - 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. - -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 = ''' -# Create 'burgers' database user with name 'bob' and password '12345'. -- mongodb_user: - database: burgers - name: bob - password: 12345 - state: present - -# 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 - -# Delete 'burgers' database user with name 'bob'. -- mongodb_user: - database: burgers - name: bob - state: absent - -# 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 -- mongodb_user: - database: burgers - name: jim - password: 12345 - roles: readWrite,dbAdmin,userAdmin - state: present -- mongodb_user: - database: burgers - name: joe - password: 12345 - roles: readWriteAnyDatabase - state: present - -# 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 syncronized 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+ -- 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: string -''' - -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 -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) == sorted(uinfo_roles): - 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="admin"), - 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'), - 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='the python pymongo module is required') - - 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), - "username": login_user, - "password": login_password, - "authSource": login_database, - } - - 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. - 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()) - - # 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()) - - module.exit_json(changed=True, user=user) - - -if __name__ == '__main__': - main() diff --git a/meta/main.yml b/meta/main.yml index 5d9aab43..94bbca05 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -6,7 +6,7 @@ galaxy_info: company: Self-employed description: Manage MongoDB with authentication and replica sets license: GPLv2 - min_ansible_version: 2.4 + min_ansible_version: 2.5 platforms: - name: Ubuntu versions: diff --git a/tasks/auth_initialization.yml b/tasks/auth_initialization.yml index c5c5b799..e5e40cc5 100644 --- a/tasks/auth_initialization.yml +++ b/tasks/auth_initialization.yml @@ -1,23 +1,17 @@ --- - name: Use different mongod.conf for auth initialization - template: src=mongod_init.conf.j2 dest=/etc/mongod.conf owner=root group=root mode=0644 + template: + src: mongod_init.conf.j2 + dest: /etc/mongod.conf + owner: root + group: root + mode: 0644 + notify: + - mongodb restart + - wait when mongodb is started on localhost -- name: Restart mongodb service - service: name={{ mongodb_daemon_name }} state=restarted - when: mongodb_manage_service - -- name: wait MongoDB port is listening - wait_for: host=127.0.0.1 port="{{ mongodb_net_port }}" delay=5 state=started - -- name: get pid of mongodb for non daemon mode - shell: "pidof mongod" - register: pidof_mongod - when: mongodb_manage_service == false - ignore_errors: yes - -- name: start mongodb daemon - shell: "LC_ALL=C /usr/bin/mongod --config /etc/mongod.conf --fork" - when: mongodb_manage_service == false and pidof_mongod.rc == 1 +- name: Flush all handlers at this point + meta: flush_handlers - name: create administrative user siteUserAdmin mongodb_user: @@ -68,12 +62,15 @@ no_log: true - name: Move back mongod.conf - template: src=mongod.conf.j2 dest=/etc/mongod.conf owner=root group=root mode=0644 - -- name: Restart mongodb service - service: name={{ mongodb_daemon_name }} state=restarted - when: mongodb_manage_service + template: + src: mongod.conf.j2 + dest: /etc/mongod.conf + owner: root + group: root + mode: 0644 + notify: + - mongodb restart + - wait when mongodb is started -- name: Wait MongoDB port is listening - wait_for: host="{{ item }}" port="{{ mongodb_net_port }}" delay=5 state=started - with_items: "{{ mongodb_net_bindip.split(',') | map('replace', '0.0.0.0', '127.0.0.1') | list }}" +- name: Flush all handlers at this point + meta: flush_handlers diff --git a/tasks/configure.yml b/tasks/configure.yml index c71b9c4c..74a2d3b6 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -1,4 +1,31 @@ --- +- name: create mongodb group + group: + name: "{{ mongodb_user }}" + state: present + +- name: create mongodb user + user: + name: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + state: present + +# Workaround because default(omit) is not working. At least in Ansible 2.8. + +- name: set mongodb gid + group: + name: "{{ mongodb_user }}" + gid: "{{ mongodb_gid }}" + state: present + when: mongodb_gid is defined + +- name: set mongodb uid + user: + name: "{{ mongodb_user }}" + uid: "{{ mongodb_uid }}" + group: "{{ mongodb_user }}" + state: present + when: mongodb_uid is defined - name: Create keyFile copy: @@ -7,22 +34,16 @@ owner: "{{ mongodb_user }}" group: "root" mode: 0600 - when: mongodb_replication_replset and mongodb_replication_replset != '' - -- name: set mongodb gid - group: name=mongodb gid={{ mongodb_gid }} state=present - when: mongodb_gid - -- name: set mongodb uid - user: name=mongodb uid={{ mongodb_uid }} group=mongodb state=present - when: mongodb_uid - -- name: reset mongodb folder and subfolders with new uid - file: path={{ mongodb_storage_dbpath }} owner=mongodb group=mongodb follow=yes recurse=yes state=directory - when: mongodb_uid + when: mongodb_replication_replset | length > 0 - name: Create log dir if missing - file: state=directory recurse=yes dest={{ mongodb_systemlog_path|dirname }} owner={{ mongodb_user }} group={{mongodb_user}} mode=0755 + file: + state: directory + recurse: true + dest: "{{ mongodb_systemlog_path|dirname }}" + owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + mode: 0755 when: mongodb_systemlog_destination == "file" - name: Check than logfile exists @@ -31,7 +52,12 @@ when: mongodb_systemlog_destination == "file" - name: Create log if missing - file: state=touch dest={{ mongodb_systemlog_path }} owner={{ mongodb_user }} group={{mongodb_user}} mode=0755 + file: + state: touch + dest: "{{ mongodb_systemlog_path }}" + owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + mode: 0755 when: ( mongodb_systemlog_destination == "file" and logfile_stat is defined and not logfile_stat.stat.exists ) @@ -41,23 +67,23 @@ path: "{{ mongodb_storage_dbpath }}" state: directory owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" setype: 'mongod_var_lib_t' - recurse: yes + recurse: true + follow: true - name: Configure mongodb - template: src=mongod.conf.j2 dest=/etc/mongod.conf backup=yes owner=root group=root mode=0644 - register: config_result - -- name: mongodb restart - service: name={{ mongodb_daemon_name }} state=restarted - when: config_result is changed and mongodb_manage_service - -- name: Ensure service is started - service: name={{ mongodb_daemon_name }} state=started - -- name: Wait when mongodb is started - wait_for: - host: "{{ item }}" - port: "{{ mongodb_net_port }}" - timeout: 120 - with_items: "{{ mongodb_net_bindip.split(',') | map('replace', '0.0.0.0', '127.0.0.1') | list }}" + template: + src: mongod.conf.j2 + dest: /etc/mongod.conf + backup: true + owner: root + group: root + mode: 0644 + notify: + - mongodb restart + - service started + - wait when mongodb is started + +- name: Flush all handlers at this point + meta: flush_handlers diff --git a/tasks/disable_transparent_hugepages.yml b/tasks/disable_transparent_hugepages.yml index e32de2a5..37c28b82 100644 --- a/tasks/disable_transparent_hugepages.yml +++ b/tasks/disable_transparent_hugepages.yml @@ -1,22 +1,15 @@ -- name: Install disable transparent hugepages helper +--- +- name: Create disable transparent hugepages systemd service file copy: - src: disable-transparent-hugepages.sh - dest: /opt/disable-transparent-hugepages.sh - owner: root - group: root - mode: 0700 - -- name: Create disable transparent hugepages init file - copy: - src: disable-transparent-hugepages.init - dest: /etc/systemd/system/disable-transparent-hugepages.init + src: disable-transparent-hugepages.service + dest: /etc/systemd/system/disable-transparent-hugepages.service owner: root group: root mode: 0644 -- name: Enable init file +- name: Enable disable-transparent-hugepages.service systemd: name: disable-transparent-hugepages - daemon-reload: yes - enabled: yes + daemon-reload: true + enabled: true state: started diff --git a/tasks/install.amazon.yml b/tasks/install.amazon.yml index 0c057bb4..993d6845 100644 --- a/tasks/install.amazon.yml +++ b/tasks/install.amazon.yml @@ -8,20 +8,25 @@ src: mongodb.repo.j2 dest: /etc/yum.repos.d/mongodb.repo mode: 0644 - with_items: "{{ mongodb_version[0:3] }}" + with_items: "{{ mongodb_major_version }}" + loop_control: + loop_var: version_item when: mongodb_package == 'mongodb-org' - name: Install MongoDB package yum: - name: - - "{{ mongodb_package }}" - - numactl + name: "{{ mongodb_package }}{% if (mongodb_version | length > 3) %}={{ mongodb_version }}{% endif %}" + state: "{{ mongodb_package_state }}" + +- name: Install numactl package + yum: + name: numactl state: present - name: Install PyMongo package yum: name: python-pymongo - state: latest + state: present when: not mongodb_pymongo_from_pip - name: Install PIP diff --git a/tasks/install.debian.yml b/tasks/install.debian.yml index c4a31cdc..6bd9c630 100644 --- a/tasks/install.debian.yml +++ b/tasks/install.debian.yml @@ -1,21 +1,13 @@ --- - -- name: Check if running on systemd - stat: path=/sbin/init - register: sbin_init - changed_when: false - check_mode: no - - name: Establish some role-related facts set_fact: - mongodb_is_systemd: "{{ sbin_init.stat.islnk is defined and sbin_init.stat.islnk }}" mongodb_major_version: "{{ mongodb_version[0:3] }}" - name: Disable transparent huge pages on systemd systems include_tasks: disable_transparent_hugepages.yml when: - - mongodb_disable_transparent_hugepages - - mongodb_is_systemd + - mongodb_disable_transparent_hugepages | bool + - ansible_service_mgr == "systemd" - name: Add APT key apt_key: @@ -26,18 +18,17 @@ - name: Fail when used wrong mongodb_version variable with Debian Stretch fail: msg: "mongodb_version variable should be '3.6' or '4.0' for Debian Stretch" - when: (mongodb_package == 'mongodb-org' and - (mongodb_version is not defined - or mongodb_repository[mongodb_major_version] is not defined - or (mongodb_version != '3.6' and mongodb_version != '4.0')) - and (ansible_distribution_release == 'stretch' and ansible_distribution_release == 'jessie')) + when: + - mongodb_package == 'mongodb-org' + - (mongodb_major_version != '3.6' and mongodb_major_version != '4.0') + - ansible_distribution_release == 'stretch' - name: Fail when used wrong mongodb_version variable with Ubuntu 18.04 fail: msg: "mongodb_version variable should be '4.0' or else mongodb_package should be 'mongodb' for Ubuntu 18.04" when: - mongodb_package == 'mongodb-org' - - mongodb_version != '4.0' + - mongodb_major_version != '4.0' - ansible_distribution_release == "bionic" - name: Fail when used wrong mongodb_version variable @@ -48,37 +39,40 @@ or mongodb_repository[mongodb_major_version] is not defined)) - name: Add APT repository - apt_repository: repo="{{ mongodb_repository[item] }}" update_cache=yes + apt_repository: + repo: "{{ mongodb_repository[version_item] }}" + update_cache: true with_items: "{{ mongodb_major_version }}" + loop_control: + loop_var: version_item when: mongodb_package == 'mongodb-org' - name: Install MongoDB package - apt: - name: - - "{{mongodb_package}}" - - numactl + apt: + name: "{{ mongodb_package }}{% if (mongodb_version | length > 3) %}={{ mongodb_version }}{% endif %}" state: "{{ mongodb_package_state }}" - update_cache: yes + update_cache: true + +- name: Install numactl package + apt: + name: numactl + state: present - name: Add systemd configuration if present copy: src=mongodb.service dest=/lib/systemd/system/mongodb.service owner=root group=root mode=0644 - when: mongodb_is_systemd + when: ansible_service_mgr == "systemd" + notify: + - reload systemd - name: Add symlink for systemd file: src=/lib/systemd/system/mongodb.service dest=/etc/systemd/system/multi-user.target.wants/mongodb.service state=link - when: mongodb_is_systemd - notify: reload systemd - -- name: reload systemd - shell: systemctl daemon-reload - when: mongodb_is_systemd and mongodb_manage_service - -- block: - - meta: flush_handlers - when: mongodb_is_systemd + when: ansible_service_mgr == "systemd" + notify: + - reload systemd - name: Install PyMongo package - apt: pkg=python-pymongo state=latest + apt: + name: python-pymongo when: not mongodb_pymongo_from_pip - name: Install PIP @@ -86,11 +80,11 @@ pkg: - python-dev - python-pip - when: mongodb_pymongo_from_pip + when: mongodb_pymongo_from_pip | bool - name: Install PyMongo from PIP pip: name: pymongo state: "{{ mongodb_pymongo_pip_version is defined | ternary('present', 'latest') }}" version: "{{ mongodb_pymongo_pip_version | default(omit) }}" - when: mongodb_pymongo_from_pip + when: mongodb_pymongo_from_pip | bool diff --git a/tasks/install.redhat.yml b/tasks/install.redhat.yml index 8c596ddc..f2b060df 100644 --- a/tasks/install.redhat.yml +++ b/tasks/install.redhat.yml @@ -14,34 +14,37 @@ src: mongodb.repo.j2 dest: /etc/yum.repos.d/mongodb.repo mode: 0644 - with_items: "{{ mongodb_version[0:3] }}" + with_items: "{{ mongodb_major_version }}" + loop_control: + loop_var: version_item when: mongodb_package == 'mongodb-org' - name: Install MongoDB package yum: - name: "{{ item }}" + name: "{{ mongodb_package }}{% if (mongodb_version | length > 3) %}={{ mongodb_version }}{% endif %}" + state: "{{ mongodb_package_state }}" + +- name: Install numactl package + yum: + name: numactl state: present - with_items: - - "{{ mongodb_package }}" - - numactl - name: Install PyMongo package yum: name: python-pymongo - state: latest + state: present when: not mongodb_pymongo_from_pip - name: Install PIP yum: - name: "{{ item }}" - with_items: - - python-devel - - python-pip - when: mongodb_pymongo_from_pip + name: + - python-devel + - python-pip + when: mongodb_pymongo_from_pip | bool - name: Install PyMongo from PIP pip: name: pymongo state: "{{ mongodb_pymongo_pip_version is defined | ternary('present', 'latest') }}" version: "{{ mongodb_pymongo_pip_version | default(omit) }}" - when: mongodb_pymongo_from_pip + when: mongodb_pymongo_from_pip | bool diff --git a/tasks/main.yml b/tasks/main.yml index 28d32e0f..be249011 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -20,15 +20,14 @@ - name: Include replication and auth configuration include: replication_init_auth.yml - when: ( mongodb_replication_replset - and mongodb_replication_replset != '' + when: ( mongodb_replication_replset | length > 0 and mongodb_security_authorization == 'enabled' and mongodb_master is defined and mongodb_master ) tags: [mongodb] - name: Include replication configuration include: replication.yml - when: mongodb_replication_replset and mongodb_replication_replset != '' + when: mongodb_replication_replset | length > 0 tags: [mongodb] - name: Check where admin user already exists @@ -40,21 +39,19 @@ check_mode: no ignore_errors: true when: ( mongodb_security_authorization == 'enabled' - and (not mongodb_replication_replset - or mongodb_replication_replset == '') ) + and not mongodb_replication_replset ) no_log: true tags: [mongodb] - name: Include authorization configuration include: auth_initialization.yml when: ( mongodb_security_authorization == 'enabled' - and (not mongodb_replication_replset - or mongodb_replication_replset == '') + and not mongodb_replication_replset and mongodb_user_admin_check.rc != 0 ) tags: [mongodb] - name: create normal users with replicaset - mongodb_user_fixed: + mongodb_user: database: "{{ item.database }}" name: "{{ item.name }}" password: "{{ item.password }}" @@ -67,14 +64,13 @@ with_items: - "{{ mongodb_users | default([]) }}" when: ( mongodb_replication_replset - and mongodb_replication_replset != '' and mongodb_security_authorization == 'enabled' and mongodb_master is defined and mongodb_master ) no_log: true tags: [mongodb] - name: create normal users without replicaset - mongodb_user_fixed: + mongodb_user: database: "{{ item.database }}" name: "{{ item.name }}" password: "{{ item.password }}" @@ -86,13 +82,12 @@ with_items: - "{{ mongodb_users | default([]) }}" when: ( mongodb_security_authorization == 'enabled' - and (not mongodb_replication_replset - or mongodb_replication_replset == '') ) + and not mongodb_replication_replset ) no_log: true tags: [mongodb] - name: create oplog user with replicaset - mongodb_user_fixed: + mongodb_user: database: admin user: "{{ item.user }}" password: "{{ item.password }}" @@ -106,8 +101,7 @@ login_host: "{{ mongodb_login_host|default('localhost') }}" with_items: - "{{ mongodb_oplog_users | default([]) }}" - when: ( mongodb_replication_replset - and mongodb_replication_replset != '' + when: ( mongodb_replication_replset | length > 0 and mongodb_security_authorization == 'enabled' and mongodb_master is defined and mongodb_master ) no_log: false @@ -115,5 +109,5 @@ - name: Include MMS Agent configuration include: mms-agent.yml - when: mongodb_mms_api_key != "" + when: mongodb_mms_api_key | length > 0 tags: [mongodb] diff --git a/tasks/mms-agent.yml b/tasks/mms-agent.yml index 92f80aa2..9bc646ad 100644 --- a/tasks/mms-agent.yml +++ b/tasks/mms-agent.yml @@ -1,28 +1,22 @@ --- - -- name: Download MMS Agent (Debian) - get_url: url={{mongodb_mms_agent_pkg}} dest={{mongodb_storage_dbpath}}/mms-agent.deb - register: mongodb_mms_agent_loaded - when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' - - name: Install MMS agent (Debian) apt: - deb: "{{mongodb_storage_dbpath}}/mms-agent.deb" - when: mongodb_mms_agent_loaded.changed #and (ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu') - -- name: Download MMS Agent (RHEL) - get_url: url={{mongodb_mms_agent_pkg}} dest={{mongodb_storage_dbpath}}/mms-agent.rpm - register: mongodb_mms_agent_loaded - when: ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat' + deb: "{{ mongodb_mms_agent_pkg }}" + when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' - name: Install MMS agent (RHEL) yum: - name: "{{mongodb_storage_dbpath}}/mms-agent.rpm" + name: "{{ mongodb_mms_agent_pkg }}" state: present - when: mongodb_mms_agent_loaded.changed and (ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat') + when: ansible_distribution == 'CentOS' or ansible_distribution == 'RedHat' - name: Configure the MMS agent pt. 1 - file: state=directory path=/etc/mongodb-mms owner={{mongodb_user}} group={{mongodb_user}} mode=0755 + file: + state: directory + path: /etc/mongodb-mms + owner: "{{ mongodb_user }}" + group: "{{ mongodb_user }}" + mode: 0755 - name: Configure the MMS agent pt. 2 template: src=monitoring-agent.config.j2 dest=/etc/mongodb-mms/monitoring-agent.config diff --git a/tasks/replication_init_auth.yml b/tasks/replication_init_auth.yml index e6f2f9d8..76657db5 100644 --- a/tasks/replication_init_auth.yml +++ b/tasks/replication_init_auth.yml @@ -19,7 +19,7 @@ ignore_errors: true - include: auth_initialization.yml - when: mongodb_replica_init|failed + when: mongodb_replica_init is failed - name: Replication configuration | 2nd Pt mongodb_replication: @@ -35,6 +35,6 @@ hidden: "{{ item.hidden|default(false) }}" priority: "{{ item.priority|default(1.0) }}" votes: "{{ item.votes|default(omit) }}" - when: mongodb_replica_init|failed + when: mongodb_replica_init is failed with_items: - "{{ mongodb_replication_params|default([]) }}" diff --git a/templates/mongod.conf.j2 b/templates/mongod.conf.j2 index 31a865f9..e08be960 100644 --- a/templates/mongod.conf.j2 +++ b/templates/mongod.conf.j2 @@ -2,7 +2,7 @@ net: bindIp: {{ mongodb_net_bindip }} - {% if mongodb_major_version is version_compare("3.6", "<") -%} + {% if mongodb_major_version is version("3.6", "<") -%} http: enabled: {{ mongodb_net_http_enabled | to_nice_json }} {% endif -%} @@ -40,9 +40,7 @@ security: storage: dbPath: {{ mongodb_storage_dbpath }} directoryPerDB: {{ mongodb_storage_dirperdb | to_nice_json }} - {% if mongodb_major_version is version_compare("3.0", ">=") -%} engine: {{ mongodb_storage_engine }} - {% endif -%} journal: enabled: {{ mongodb_storage_journal_enabled | to_nice_json }} {% if mongodb_storage_engine == 'mmapv1' -%} diff --git a/templates/mongod_init.conf.j2 b/templates/mongod_init.conf.j2 index 9ce98cdb..b32538fe 100644 --- a/templates/mongod_init.conf.j2 +++ b/templates/mongod_init.conf.j2 @@ -2,7 +2,7 @@ net: bindIp: '127.0.0.1' - {% if mongodb_major_version | version_compare("3.6", "<") -%} + {% if mongodb_major_version is version("3.6", "<") -%} http: enabled: {{ mongodb_net_http_enabled | to_nice_json }} {% endif -%} @@ -22,9 +22,7 @@ security: storage: dbPath: {{ mongodb_storage_dbpath }} directoryPerDB: {{ mongodb_storage_dirperdb | to_nice_json }} - {% if mongodb_major_version | version_compare("3.0", ">=") -%} engine: {{ mongodb_storage_engine }} - {% endif -%} journal: enabled: {{ mongodb_storage_journal_enabled | to_nice_json }} {% if mongodb_storage_engine == 'mmapv1' -%} diff --git a/templates/mongodb.repo.j2 b/templates/mongodb.repo.j2 index a030d21c..727f2cb1 100644 --- a/templates/mongodb.repo.j2 +++ b/templates/mongodb.repo.j2 @@ -1,9 +1,9 @@ -[mongodb-org-{{ mongodb_version }}] -name=MongoDB {{ mongodb_version }} Repository -baseurl={{ mongodb_repository[item] }} -{% if mongodb_repository_gpgkey[item] is defined and mongodb_repository_gpgkey[item] != '' %} +[mongodb-org-{{ mongodb_major_version }}] +name=MongoDB {{ mongodb_major_version }} Repository +baseurl={{ mongodb_repository[version_item] }} +{% if mongodb_repository_gpgkey[version_item] is defined and mongodb_repository_gpgkey[version_item] != '' %} gpgcheck=1 -gpgkey={{ mongodb_repository_gpgkey[item] }} +gpgkey={{ mongodb_repository_gpgkey[version_item] }} {% else %} gpgcheck=0 {% endif %} diff --git a/tests/host_vars/mongo3.yml b/tests/host_vars/mongo3.yml index 6f6b6f6f..a63fa4c3 100644 --- a/tests/host_vars/mongo3.yml +++ b/tests/host_vars/mongo3.yml @@ -1,6 +1,6 @@ --- mongodb_net_port: 30000 -mongodb_storage_journal_enabled: "{{ mongodb_major_version | version_compare('4.0', '>=') }}" +mongodb_storage_journal_enabled: "{{ mongodb_major_version is version('4.0', '>=') }}" mongodb_storage_smallfiles: true mongodb_storage_prealloc: false mongodb_replication_params: