From 99c5b408fec1517059f59d8f0344dee4bdbcce99 Mon Sep 17 00:00:00 2001 From: nadeemshahzad Date: Tue, 23 Apr 2024 11:51:14 +0500 Subject: [PATCH] feat: add roles for mongo 6.0 and 7.0 --- playbooks/edx_continuous_integration.yml | 5 + playbooks/mongo_6_0.yml | 29 ++ playbooks/mongo_7_0.yml | 29 ++ playbooks/roles/mongo_6_0/defaults/main.yml | 111 +++++ .../disable-transparent-hugepages.service | 11 + playbooks/roles/mongo_6_0/meta/main.yml | 5 + playbooks/roles/mongo_6_0/tasks/main.yml | 404 ++++++++++++++++++ .../templates/log-mongo-serverStatus.sh.j2 | 3 + .../mongo_6_0/templates/mongo_logrotate.j2 | 46 ++ .../roles/mongo_6_0/templates/mongod.conf.j2 | 46 ++ playbooks/roles/mongo_7_0/defaults/main.yml | 111 +++++ .../disable-transparent-hugepages.service | 11 + playbooks/roles/mongo_7_0/meta/main.yml | 5 + playbooks/roles/mongo_7_0/tasks/main.yml | 404 ++++++++++++++++++ .../templates/log-mongo-serverStatus.sh.j2 | 3 + .../mongo_7_0/templates/mongo_logrotate.j2 | 46 ++ .../roles/mongo_7_0/templates/mongod.conf.j2 | 40 ++ util/jenkins/ansible-provision.sh | 22 + 18 files changed, 1331 insertions(+) create mode 100644 playbooks/mongo_6_0.yml create mode 100644 playbooks/mongo_7_0.yml create mode 100644 playbooks/roles/mongo_6_0/defaults/main.yml create mode 100644 playbooks/roles/mongo_6_0/files/etc/systemd/system/disable-transparent-hugepages.service create mode 100644 playbooks/roles/mongo_6_0/meta/main.yml create mode 100644 playbooks/roles/mongo_6_0/tasks/main.yml create mode 100644 playbooks/roles/mongo_6_0/templates/log-mongo-serverStatus.sh.j2 create mode 100644 playbooks/roles/mongo_6_0/templates/mongo_logrotate.j2 create mode 100644 playbooks/roles/mongo_6_0/templates/mongod.conf.j2 create mode 100644 playbooks/roles/mongo_7_0/defaults/main.yml create mode 100644 playbooks/roles/mongo_7_0/files/etc/systemd/system/disable-transparent-hugepages.service create mode 100644 playbooks/roles/mongo_7_0/meta/main.yml create mode 100644 playbooks/roles/mongo_7_0/tasks/main.yml create mode 100644 playbooks/roles/mongo_7_0/templates/log-mongo-serverStatus.sh.j2 create mode 100644 playbooks/roles/mongo_7_0/templates/mongo_logrotate.j2 create mode 100644 playbooks/roles/mongo_7_0/templates/mongod.conf.j2 diff --git a/playbooks/edx_continuous_integration.yml b/playbooks/edx_continuous_integration.yml index ff75ba6bbcf..fdc34ee3841 100644 --- a/playbooks/edx_continuous_integration.yml +++ b/playbooks/edx_continuous_integration.yml @@ -26,6 +26,11 @@ tags: edxlocal - memcache - role: mongo_5_0 + when: MONGO_5_0_ENABLED + - role: mongo_6_0 + when: MONGO_6_0_ENABLED + - role: mongo_7_0 + when: MONGO_7_0_ENABLED - role: redis - { role: "edxapp", celery_worker: True, when: edxapp_containerized is defined and not edxapp_containerized } - { role: "edxapp", when: edxapp_containerized is defined and not edxapp_containerized } diff --git a/playbooks/mongo_6_0.yml b/playbooks/mongo_6_0.yml new file mode 100644 index 00000000000..6799b7ec7bc --- /dev/null +++ b/playbooks/mongo_6_0.yml @@ -0,0 +1,29 @@ +# Manages a mongo cluster. +# To set up a new mongo cluster, make sure you've configured MONGO_RS_CONFIG +# as used by mongo_replica_set in the mongo_6_0 role. +# +# If you are initializing a cluster, your command might look like: +# ansible-playbook mongo_6_0.yml -i 203.0.113.11,203.0.113.12,203.0.113.13 -e@/path/to/edx.yml -e@/path/to/ed.yml +# If you just want to deploy an updated replica set config, you can run +# ansible-playbook mongo_6_0.yml -i any-cluster-ip -e@/path/to/edx.yml -e@/path/to/ed.yml --tags configure_replica_set +# +# ADDING A NEW CLUSTER MEMBER +# If you are adding a member to a cluster, you must be sure that the new machine is not first in your inventory +# ansible-playbook mongo_6_0.yml -i 203.0.113.11,203.0.113.12,new-machine-ip -e@/path/to/edx.yml -e@/path/to/ed.yml +- name: Deploy MongoDB + hosts: all + become: True + gather_facts: True + roles: + - role: aws + when: COMMON_ENABLE_AWS_ROLE + - mongo_6_0 + - munin_node + - role: datadog + when: COMMON_ENABLE_DATADOG + - role: splunkforwarder + when: COMMON_ENABLE_SPLUNKFORWARDER + - role: newrelic_infrastructure + when: COMMON_ENABLE_NEWRELIC_INFRASTRUCTURE + - role: datadog-uninstall + when: not COMMON_ENABLE_DATADOG diff --git a/playbooks/mongo_7_0.yml b/playbooks/mongo_7_0.yml new file mode 100644 index 00000000000..1fd4c6aa8e9 --- /dev/null +++ b/playbooks/mongo_7_0.yml @@ -0,0 +1,29 @@ +# Manages a mongo cluster. +# To set up a new mongo cluster, make sure you've configured MONGO_RS_CONFIG +# as used by mongo_replica_set in the mongo_7_0 role. +# +# If you are initializing a cluster, your command might look like: +# ansible-playbook mongo_7_0.yml -i 203.0.113.11,203.0.113.12,203.0.113.13 -e@/path/to/edx.yml -e@/path/to/ed.yml +# If you just want to deploy an updated replica set config, you can run +# ansible-playbook mongo_7_0.yml -i any-cluster-ip -e@/path/to/edx.yml -e@/path/to/ed.yml --tags configure_replica_set +# +# ADDING A NEW CLUSTER MEMBER +# If you are adding a member to a cluster, you must be sure that the new machine is not first in your inventory +# ansible-playbook mongo_7_0.yml -i 203.0.113.11,203.0.113.12,new-machine-ip -e@/path/to/edx.yml -e@/path/to/ed.yml +- name: Deploy MongoDB + hosts: all + become: True + gather_facts: True + roles: + - role: aws + when: COMMON_ENABLE_AWS_ROLE + - mongo_7_0 + - munin_node + - role: datadog + when: COMMON_ENABLE_DATADOG + - role: splunkforwarder + when: COMMON_ENABLE_SPLUNKFORWARDER + - role: newrelic_infrastructure + when: COMMON_ENABLE_NEWRELIC_INFRASTRUCTURE + - role: datadog-uninstall + when: not COMMON_ENABLE_DATADOG diff --git a/playbooks/roles/mongo_6_0/defaults/main.yml b/playbooks/roles/mongo_6_0/defaults/main.yml new file mode 100644 index 00000000000..a842e1ca6ed --- /dev/null +++ b/playbooks/roles/mongo_6_0/defaults/main.yml @@ -0,0 +1,111 @@ +mongo_logappend: true + +#This way, when mongod receives a SIGUSR1, it'll close and reopen its log file handle +mongo_logrotate: reopen + +MONGO_VERSION_MAJOR_MINOR: "6.0" +MONGO_VERSION_PATCH: "15" +PYMONGO_VERSION: "4.4.1" +MONGO_VERSION: "{{ MONGO_VERSION_MAJOR_MINOR }}.{{ MONGO_VERSION_PATCH }}" +mongo_port: "27017" +mongo_extra_conf: '' +mongo_key_file: '/etc/mongodb_key' + +mongo_data_dir: "{{ COMMON_DATA_DIR }}/mongo" +mongo_log_dir: "{{ COMMON_LOG_DIR }}/mongo" +mongo_journal_dir: "{{ COMMON_DATA_DIR }}/mongo/mongodb/journal" +mongo_user: mongodb + +MONGODB_REPO: "deb http://repo.mongodb.org/apt/ubuntu {{ ansible_distribution_release }}/mongodb-org/{{ MONGO_VERSION_MAJOR_MINOR }} multiverse" + +mongodb_debian_pkgs: + - "mongodb-org={{ MONGO_VERSION }}" + - "mongodb-org-server={{ MONGO_VERSION }}" + - "mongodb-org-shell={{ MONGO_VERSION }}" + - "mongodb-org-mongos={{ MONGO_VERSION }}" + - "mongodb-org-tools={{ MONGO_VERSION }}" + + + +mongo_configure_replica_set: true + +# Vars Meant to be overridden +MONGO_ADMIN_USER: 'admin' +MONGO_ADMIN_PASSWORD: 'password' +MONGO_USERS: + - user: cs_comments_service + password: password + database: cs_comments_service + roles: readWrite + - user: edxapp + password: password + database: edxapp + roles: readWrite + +# This default setting is approriate for a single machine installation +# This will need to be overridden for setups where mongo is on its own server +# and/or you are configuring mongo replication. If the override value is +# 0.0.0.0 mongo will listen on all IPs. The value may also be set to a +# specific IP. +MONGO_BIND_IP: 127.0.0.1 + +MONGO_REPL_SET: "rs0" +MONGO_AUTH: true + +MONGO_CLUSTER_KEY: "CHANGEME" + +# Cluster member configuration +# Fed directly into mongodb_replica_set module +MONGO_RS_CONFIG: + _id: '{{ MONGO_REPL_SET }}' + members: + - host: '127.0.0.1' + +# Storage engine options in 3.2: "mmapv1" or "wiredTiger" +# 3.2 and 3.4 default to wiredTiger +MONGO_STORAGE_ENGINE: "wiredTiger" + +# List of dictionaries as described in the mount_ebs role's default +# for the volumes. +# Useful if you want to store your mongo data and/or journal on separate +# disks from the root volume. By default, they will end up mongo_data_dir +# on the root disk. +MONGO_VOLUMES: [] + +# WiredTiger takes a number of optional configuration settings +# which can be defined as a yaml structure in your secure configuration. +MONGO_STORAGE_ENGINE_OPTIONS: !!null + +mongo_logpath: "{{ mongo_log_dir }}/mongodb.log" +mongo_dbpath: "{{ mongo_data_dir }}/mongodb" + +# In environments that do not require durability (devstack / Jenkins) +# you can disable the journal to reduce disk usage +mongo_enable_journal: true + +MONGO_LOG_SERVERSTATUS: true + +# Vars for configuring a mongo backup node. If enabled, this node will be provisioned with a script that uses mongodump +# to backup the database to an ebs volume at a period set by mongo_backup_cron. +# Set MONGO_BACKUP_ENABLED to true to enable. If enabled, all the other MONGO_BACKUP_ vars must be set according to your +# setup. +MONGO_BACKUP_ENABLED: false +MONGO_BACKUP_NODE: "" # note: most likely the ip address of the instance on which to perform the backups +MONGO_BACKUP_EBS_VOLUME_DEVICE: "" +MONGO_BACKUP_EBS_VOLUME_ID: "" +MONGO_BACKUP_AUTH_DATABASE: "" +MONGO_BACKUP_PRUNE_OLDER_THAN_DATE: "" # passed to `date -d`; should be a relative date like "-30days" +MONGO_BACKUP_SNITCH_URL: "" # Optional URL that will be used to ping a monitoring service (such as Dead Man's Snitch) upon successful completion of a backup. +MONGO_BACKUP_VOLUME_MOUNT_PATH: "/mnt/mongo-backup" +MONGO_BACKUP_SNAPSHOT_DESC: "mongo-backup" +mongo_backup_script_path: "/usr/local/sbin/backup-mongo.sh" +mongo_backup_cron: + minute: '12' + hour: '*/12' + day: '*' + month: '*' + weekday: '*' + +# Internal variable set to true dynamically if backups enabled and playbook running on MONGO_BACKUP_NODE. Do not +# manually override. +is_backup_node: false diff --git a/playbooks/roles/mongo_6_0/files/etc/systemd/system/disable-transparent-hugepages.service b/playbooks/roles/mongo_6_0/files/etc/systemd/system/disable-transparent-hugepages.service new file mode 100644 index 00000000000..282c9e122c3 --- /dev/null +++ b/playbooks/roles/mongo_6_0/files/etc/systemd/system/disable-transparent-hugepages.service @@ -0,0 +1,11 @@ +[Unit] +Description="Disable Transparent Hugepage before MongoDB boots" +Before=mongod.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' + +[Install] +RequiredBy=mongod.service diff --git a/playbooks/roles/mongo_6_0/meta/main.yml b/playbooks/roles/mongo_6_0/meta/main.yml new file mode 100644 index 00000000000..d7223454526 --- /dev/null +++ b/playbooks/roles/mongo_6_0/meta/main.yml @@ -0,0 +1,5 @@ +--- +dependencies: + - common + - role: mount_ebs + volumes: "{{ MONGO_VOLUMES }}" diff --git a/playbooks/roles/mongo_6_0/tasks/main.yml b/playbooks/roles/mongo_6_0/tasks/main.yml new file mode 100644 index 00000000000..10dd2484cdf --- /dev/null +++ b/playbooks/roles/mongo_6_0/tasks/main.yml @@ -0,0 +1,404 @@ +--- +- name: Add disable transparent huge pages systemd service (http://docs.mongodb.org/manual/tutorial/transparent-huge-pages/) + copy: + src: etc/systemd/system/disable-transparent-hugepages.service + dest: "/etc/systemd/system/disable-transparent-hugepages.service" + owner: root + group: root + mode: 0644 + tags: + - "hugepages" + - "install" + - "install:configuration" + +- name: Enable/start disable transparent huge pages service (http://docs.mongodb.org/manual/tutorial/transparent-huge-pages/) + service: + name: disable-transparent-hugepages + enabled: yes + state: started + tags: + - "hugepages" + - "manage" + - "manage:start" + +- name: install python pymongo for mongo_user ansible module + pip: + name: pymongo + state: present + version: "{{ PYMONGO_VERSION }}" + extra_args: "-i {{ COMMON_PYPI_MIRROR_URL }}" + tags: + - "install" + - "install:app-requirements" + +- name: add the mongodb signing key + apt_key: + url: "https://www.mongodb.org/static/pgp/server-{{ MONGO_VERSION_MAJOR_MINOR }}.asc" + state: present + retries: 3 + register: add_mongo_signing_key + tags: + - "install" + - "install:app-requirements" + until: add_mongo_signing_key is succeeded + +- name: add the mongodb repo to the sources list + apt_repository: + repo: "{{ MONGODB_REPO }}" + state: present + tags: + - "install" + - "install:app-requirements" + - "mongo_packages" + +- name: install mongo server and recommends + apt: + pkg: "{{ item }}" + state: present + install_recommends: yes + force: yes + update_cache: yes + register: install_mongo_package + with_items: "{{ mongodb_debian_pkgs }}" + tags: + - "install" + - "install:app-requirements" + - "mongo_packages" + +- name: create mongo dirs + file: + path: "{{ item }}" + state: directory + owner: "{{ mongo_user }}" + group: "{{ mongo_user }}" + with_items: + - "{{ mongo_data_dir }}" + - "{{ mongo_dbpath }}" + - "{{ mongo_log_dir }}" + - "{{ mongo_journal_dir }}" + tags: + - "install" + - "install:app-configuration" + +# This will error when run on a new replica set, so we ignore_errors +# and connect anonymously next. +- name: determine if there is a replica set already + mongodb_rs_status: + host: "{{ ansible_lo['ipv4']['address'] }}" + username: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + run_once: true + register: authed_replica_set_already_configured + ignore_errors: true + tags: + - "manage" + - "manage:db-replication" + +- name: Try checking the replica set with no user/pass in case this is a new box + mongodb_rs_status: + host: "{{ ansible_lo['ipv4']['address'] }}" + run_once: true + register: unauthed_replica_set_already_configured + when: authed_replica_set_already_configured.failed is defined + ignore_errors: true + tags: + - "manage" + - "manage:db-replication" + +# We use these in the templates but also to control a whole bunch of logic +- name: set facts that default to not initializing a replica set + set_fact: + initialize_replica_set: false + skip_replica_set: false + tags: + - "install" + - "install:app-configuration" + - "update_mongod_conf" + - "manage" + - "manage:db-replication" + +# If either auth or unauthed access comes back with a replica set, we +# do not want to initialize one. Since initialization requires a bunch +# of extra templating and restarting, it's not something we want to do on +# existing boxes. +- name: track if you have a replica set + set_fact: + initialize_replica_set: true + skip_replica_set: true + when: authed_replica_set_already_configured.status is not defined + and unauthed_replica_set_already_configured.status is not defined + tags: + - "manage" + - "manage:db-replication" + +- name: warn about unconfigured replica sets + debug: msg="You do not appear to have a Replica Set configured, deploying one for you" + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: copy mongodb key file + copy: + content: "{{ MONGO_CLUSTER_KEY }}" + dest: "{{ mongo_key_file }}" + mode: 0600 + owner: mongodb + group: mongodb + register: update_mongod_key + tags: + - "manage" + - "manage:db-replication" + - "mongodb_key" + +# If skip_replica_set is true, this template will not contain a replica set stanza +# because of the fact above. +- name: copy configuration template + template: + src: mongod.conf.j2 + dest: /etc/mongod.conf + backup: yes + register: update_mongod_conf + tags: + - "install" + - "install:app-configuration" + - "manage" + - "manage:db-replication" + - "update_mongod_conf" + +# This sets the is_backup_node var by checking whether +# mongo backups are enabled AND we're currently running against the designated mongo backup node. +# This allows backup-related tasks below to determine whether or not they should run on the current mongo node. +- name: determine if backup tasks should run + set_fact: + is_backup_node: true + when: MONGO_BACKUP_ENABLED and '{{ ansible_default_ipv4.address|default(ansible_all_ipv4_addresses[0]) }}' == '{{ MONGO_BACKUP_NODE }}' + tags: + - "backup:mongo" + +- name: install logrotate configuration + template: + src: mongo_logrotate.j2 + dest: /etc/logrotate.d/hourly/mongo + tags: + - "backup:mongo" + - "install" + - "install:app-configuration" + - "logrotate" + +- name: install prereqs for backup script + apt: + pkg: "{{ item }}" + state: present + update_cache: yes + with_items: + - jq + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + - "install:app-requirements" + - "mongo_packages" + +- name: install backup script + template: + src: backup-mongo.sh.j2 + dest: "{{ mongo_backup_script_path }}" + mode: 0700 + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + +- name: add mongo backup script to cron + cron: + name: mongo backup job + minute: "{{ mongo_backup_cron.minute | default('12') }}" + hour: "{{ mongo_backup_cron.hour | default('*/12') }}" + day: "{{ mongo_backup_cron.day | default('*') }}" + month: "{{ mongo_backup_cron.month | default('*') }}" + weekday: "{{ mongo_backup_cron.weekday | default('*') }}" + job: "{{ mongo_backup_script_path }} >> {{ mongo_log_dir }}/mongo-backup.log 2>&1" + become: yes + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + +- name: format mongo backup volume + filesystem: + dev: "{{ MONGO_BACKUP_EBS_VOLUME_DEVICE }}" + fstype: ext4 + force: true + ignore_errors: true + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + +- name: restart mongo service if we changed our configuration or upgraded mongo + service: + name: mongod + state: restarted + when: update_mongod_conf.changed or update_mongod_key.changed or install_mongo_package.changed + tags: + - "manage" + - "manage:start" + - "manage:db-replication" + +- name: wait for mongo server to start + wait_for: + port: 27017 + delay: 2 + tags: + - "manage" + - "manage:start" + - "manage:db-replication" + +# We only try passwordless superuser creation when +# we're initializing the replica set and need to use +# the localhost exemption to create a user who will be +# able to initialize the replica set. +# We can only create the users on one machine, the one +# where we will initialize the replica set. If we +# create users on multiple hosts, then they will fail +# to come into the replica set. +- name: create super user + mongodb_user: + name: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + database: admin + roles: root + when: initialize_replica_set + run_once: true + tags: + - "manage" + - "manage:db-replication" + +# Now that the localhost exemption has been used to create the superuser, we need +# to add replica set to our configuration. This will never happen if we detected +# a replica set in the 'determine if there is a replica set already' task. +- name: Unset our skip initializing replica set fact so that mongod.conf gets a replica set + set_fact: + skip_replica_set: false + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: re-copy configuration template with replica set enabled + template: + src: mongod.conf.j2 + dest: /etc/mongod.conf + backup: yes + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: restart mongo service + service: + name: mongod + state: restarted + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: wait for mongo server to start + wait_for: + port: 27017 + delay: 2 + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: configure replica set + mongodb_replica_set: + username: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + rs_config: "{{ MONGO_RS_CONFIG }}" + run_once: true + register: replset_status + when: mongo_configure_replica_set + tags: + - "manage" + - "manage:db" + - "manage:db-replication" + - "manage:db-replication-configuration" + +# During initial replica set configuration, it can take a few seconds to vote +# a primary and for all members to reflect that status. During that window, +# use creation or other writes can fail. The best wait/check seems to be repeatedly +# checking the replica set status until we see a PRIMARY in the results. +- name: Wait for the replica set to update and (if needed) elect a primary + mongodb_rs_status: + host: "{{ ansible_lo['ipv4']['address'] }}" + username: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + register: status + until: status.status is defined and 'PRIMARY' in status.status.members|map(attribute='stateStr')|list + when: mongo_configure_replica_set + retries: 5 + delay: 2 + run_once: true + tags: + - "manage" + - "manage:db" + - "manage:db-replication" + +- name: create mongodb users in a replica set + mongodb_user: + database: "{{ item.database }}" + login_database: 'admin' + login_user: "{{ MONGO_ADMIN_USER }}" + login_password: "{{ MONGO_ADMIN_PASSWORD }}" + name: "{{ item.user }}" + password: "{{ item.password }}" + roles: "{{ item.roles }}" + state: present + replica_set: "{{ MONGO_REPL_SET }}" + with_items: "{{ MONGO_USERS }}" + run_once: true + when: mongo_configure_replica_set + tags: + - "manage" + - "manage:db" + - "manage:db-users" + - "manage:db-replication" + +- name: ensure mongo starts at boot time + service: + name: mongod + enabled: yes + tags: + - "manage" + - "manage:start" + +- name: add serverStatus logging script + template: + src: "log-mongo-serverStatus.sh.j2" + dest: "{{ COMMON_BIN_DIR }}/log-mongo-serverStatus.sh" + owner: "{{ mongo_user }}" + group: "{{ mongo_user }}" + mode: 0700 + when: MONGO_LOG_SERVERSTATUS + tags: + - "install" + - "install:app-configuration" + +- name: add serverStatus logging script to cron + cron: + name: mongostat logging job + minute: "*/3" + job: /edx/bin/log-mongo-serverStatus.sh >> {{ mongo_log_dir }}/serverStatus.log 2>&1 + become: yes + when: MONGO_LOG_SERVERSTATUS + tags: + - "install" + - "install:app-configuration" diff --git a/playbooks/roles/mongo_6_0/templates/log-mongo-serverStatus.sh.j2 b/playbooks/roles/mongo_6_0/templates/log-mongo-serverStatus.sh.j2 new file mode 100644 index 00000000000..04649d55ad1 --- /dev/null +++ b/playbooks/roles/mongo_6_0/templates/log-mongo-serverStatus.sh.j2 @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Using JSON.stringify forces output of normal JSON, as opposed to Mongo's weird non-compliant extended JSON +/usr/bin/mongo -u {{ MONGO_ADMIN_USER }} --authenticationDatabase admin -p '{{ MONGO_ADMIN_PASSWORD }}' --quiet <<< 'JSON.stringify(db.serverStatus())' diff --git a/playbooks/roles/mongo_6_0/templates/mongo_logrotate.j2 b/playbooks/roles/mongo_6_0/templates/mongo_logrotate.j2 new file mode 100644 index 00000000000..f2fb4483566 --- /dev/null +++ b/playbooks/roles/mongo_6_0/templates/mongo_logrotate.j2 @@ -0,0 +1,46 @@ +{{ mongo_log_dir }}/serverStatus.log { + create + compress + copytruncate + delaycompress + dateext + dateformat -%Y%m%d-%s + missingok + notifempty + daily + rotate 90 + size 1M +} + +{% if is_backup_node %} +{{ mongo_log_dir }}/mongo-backup.log { + create + compress + copytruncate + delaycompress + dateext + dateformat -%Y%m%d-%s + missingok + notifempty + daily + rotate 90 + size 1M +} +{% endif %} + +{{ mongo_log_dir }}/mongodb.log { + create + compress + copytruncate + delaycompress + dateext + dateformat -%Y%m%d-%s + missingok + notifempty + daily + rotate 90 + size 1M + postrotate + /usr/bin/killall -USR1 mongod + endscript +} diff --git a/playbooks/roles/mongo_6_0/templates/mongod.conf.j2 b/playbooks/roles/mongo_6_0/templates/mongod.conf.j2 new file mode 100644 index 00000000000..b7d4b4a1efe --- /dev/null +++ b/playbooks/roles/mongo_6_0/templates/mongod.conf.j2 @@ -0,0 +1,46 @@ +# {{ ansible_managed }} +# mongodb.conf + + +storage: + # Where to store the data. + dbPath: {{ mongo_dbpath }} + # Storage Engine + engine: {{ MONGO_STORAGE_ENGINE }} + # Enable journaling, http://www.mongodb.org/display/DOCS/Journaling + journal: +{% if mongo_enable_journal %} + enabled: true +{% else %} + enabled: false +{% endif %} +{% if MONGO_STORAGE_ENGINE_OPTIONS %} + {{ MONGO_STORAGE_ENGINE_OPTIONS | to_nice_yaml }} +{% endif %} + +systemLog: + #where to log + destination: file + path: "{{ mongo_logpath }}" +{% if mongo_logappend %} + logAppend: true +{% else %} + logAppend: false +{% endif %} + logRotate: {{ mongo_logrotate }} + +{% if not skip_replica_set %} +replication: + replSetName: {{ MONGO_REPL_SET }} + +security: + authorization: {{ MONGO_AUTH | ternary("enabled", "disabled") }} + keyFile: {{ mongo_key_file }} + +{% endif %} +net: + bindIp: {{ MONGO_BIND_IP }} + port: {{ mongo_port }} + + +{{ mongo_extra_conf }} diff --git a/playbooks/roles/mongo_7_0/defaults/main.yml b/playbooks/roles/mongo_7_0/defaults/main.yml new file mode 100644 index 00000000000..393c0e43603 --- /dev/null +++ b/playbooks/roles/mongo_7_0/defaults/main.yml @@ -0,0 +1,111 @@ +mongo_logappend: true + +#This way, when mongod receives a SIGUSR1, it'll close and reopen its log file handle +mongo_logrotate: reopen + +MONGO_VERSION_MAJOR_MINOR: "7.0" +MONGO_VERSION_PATCH: "8" +PYMONGO_VERSION: "4.4.1" +MONGO_VERSION: "{{ MONGO_VERSION_MAJOR_MINOR }}.{{ MONGO_VERSION_PATCH }}" +mongo_port: "27017" +mongo_extra_conf: '' +mongo_key_file: '/etc/mongodb_key' + +mongo_data_dir: "{{ COMMON_DATA_DIR }}/mongo" +mongo_log_dir: "{{ COMMON_LOG_DIR }}/mongo" +mongo_journal_dir: "{{ COMMON_DATA_DIR }}/mongo/mongodb/journal" +mongo_user: mongodb + +MONGODB_REPO: "deb http://repo.mongodb.org/apt/ubuntu {{ ansible_distribution_release }}/mongodb-org/{{ MONGO_VERSION_MAJOR_MINOR }} multiverse" + +mongodb_debian_pkgs: + - "mongodb-org={{ MONGO_VERSION }}" + - "mongodb-org-server={{ MONGO_VERSION }}" + - "mongodb-org-shell={{ MONGO_VERSION }}" + - "mongodb-org-mongos={{ MONGO_VERSION }}" + - "mongodb-org-tools={{ MONGO_VERSION }}" + + + +mongo_configure_replica_set: true + +# Vars Meant to be overridden +MONGO_ADMIN_USER: 'admin' +MONGO_ADMIN_PASSWORD: 'password' +MONGO_USERS: + - user: cs_comments_service + password: password + database: cs_comments_service + roles: readWrite + - user: edxapp + password: password + database: edxapp + roles: readWrite + +# This default setting is approriate for a single machine installation +# This will need to be overridden for setups where mongo is on its own server +# and/or you are configuring mongo replication. If the override value is +# 0.0.0.0 mongo will listen on all IPs. The value may also be set to a +# specific IP. +MONGO_BIND_IP: 127.0.0.1 + +MONGO_REPL_SET: "rs0" +MONGO_AUTH: true + +MONGO_CLUSTER_KEY: "CHANGEME" + +# Cluster member configuration +# Fed directly into mongodb_replica_set module +MONGO_RS_CONFIG: + _id: '{{ MONGO_REPL_SET }}' + members: + - host: '127.0.0.1' + +# Storage engine options in 3.2: "mmapv1" or "wiredTiger" +# 3.2 and 3.4 default to wiredTiger +MONGO_STORAGE_ENGINE: "wiredTiger" + +# List of dictionaries as described in the mount_ebs role's default +# for the volumes. +# Useful if you want to store your mongo data and/or journal on separate +# disks from the root volume. By default, they will end up mongo_data_dir +# on the root disk. +MONGO_VOLUMES: [] + +# WiredTiger takes a number of optional configuration settings +# which can be defined as a yaml structure in your secure configuration. +MONGO_STORAGE_ENGINE_OPTIONS: !!null + +mongo_logpath: "{{ mongo_log_dir }}/mongodb.log" +mongo_dbpath: "{{ mongo_data_dir }}/mongodb" + +# In environments that do not require durability (devstack / Jenkins) +# you can disable the journal to reduce disk usage +mongo_enable_journal: true + +MONGO_LOG_SERVERSTATUS: true + +# Vars for configuring a mongo backup node. If enabled, this node will be provisioned with a script that uses mongodump +# to backup the database to an ebs volume at a period set by mongo_backup_cron. +# Set MONGO_BACKUP_ENABLED to true to enable. If enabled, all the other MONGO_BACKUP_ vars must be set according to your +# setup. +MONGO_BACKUP_ENABLED: false +MONGO_BACKUP_NODE: "" # note: most likely the ip address of the instance on which to perform the backups +MONGO_BACKUP_EBS_VOLUME_DEVICE: "" +MONGO_BACKUP_EBS_VOLUME_ID: "" +MONGO_BACKUP_AUTH_DATABASE: "" +MONGO_BACKUP_PRUNE_OLDER_THAN_DATE: "" # passed to `date -d`; should be a relative date like "-30days" +MONGO_BACKUP_SNITCH_URL: "" # Optional URL that will be used to ping a monitoring service (such as Dead Man's Snitch) upon successful completion of a backup. +MONGO_BACKUP_VOLUME_MOUNT_PATH: "/mnt/mongo-backup" +MONGO_BACKUP_SNAPSHOT_DESC: "mongo-backup" +mongo_backup_script_path: "/usr/local/sbin/backup-mongo.sh" +mongo_backup_cron: + minute: '12' + hour: '*/12' + day: '*' + month: '*' + weekday: '*' + +# Internal variable set to true dynamically if backups enabled and playbook running on MONGO_BACKUP_NODE. Do not +# manually override. +is_backup_node: false diff --git a/playbooks/roles/mongo_7_0/files/etc/systemd/system/disable-transparent-hugepages.service b/playbooks/roles/mongo_7_0/files/etc/systemd/system/disable-transparent-hugepages.service new file mode 100644 index 00000000000..282c9e122c3 --- /dev/null +++ b/playbooks/roles/mongo_7_0/files/etc/systemd/system/disable-transparent-hugepages.service @@ -0,0 +1,11 @@ +[Unit] +Description="Disable Transparent Hugepage before MongoDB boots" +Before=mongod.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' + +[Install] +RequiredBy=mongod.service diff --git a/playbooks/roles/mongo_7_0/meta/main.yml b/playbooks/roles/mongo_7_0/meta/main.yml new file mode 100644 index 00000000000..d7223454526 --- /dev/null +++ b/playbooks/roles/mongo_7_0/meta/main.yml @@ -0,0 +1,5 @@ +--- +dependencies: + - common + - role: mount_ebs + volumes: "{{ MONGO_VOLUMES }}" diff --git a/playbooks/roles/mongo_7_0/tasks/main.yml b/playbooks/roles/mongo_7_0/tasks/main.yml new file mode 100644 index 00000000000..10dd2484cdf --- /dev/null +++ b/playbooks/roles/mongo_7_0/tasks/main.yml @@ -0,0 +1,404 @@ +--- +- name: Add disable transparent huge pages systemd service (http://docs.mongodb.org/manual/tutorial/transparent-huge-pages/) + copy: + src: etc/systemd/system/disable-transparent-hugepages.service + dest: "/etc/systemd/system/disable-transparent-hugepages.service" + owner: root + group: root + mode: 0644 + tags: + - "hugepages" + - "install" + - "install:configuration" + +- name: Enable/start disable transparent huge pages service (http://docs.mongodb.org/manual/tutorial/transparent-huge-pages/) + service: + name: disable-transparent-hugepages + enabled: yes + state: started + tags: + - "hugepages" + - "manage" + - "manage:start" + +- name: install python pymongo for mongo_user ansible module + pip: + name: pymongo + state: present + version: "{{ PYMONGO_VERSION }}" + extra_args: "-i {{ COMMON_PYPI_MIRROR_URL }}" + tags: + - "install" + - "install:app-requirements" + +- name: add the mongodb signing key + apt_key: + url: "https://www.mongodb.org/static/pgp/server-{{ MONGO_VERSION_MAJOR_MINOR }}.asc" + state: present + retries: 3 + register: add_mongo_signing_key + tags: + - "install" + - "install:app-requirements" + until: add_mongo_signing_key is succeeded + +- name: add the mongodb repo to the sources list + apt_repository: + repo: "{{ MONGODB_REPO }}" + state: present + tags: + - "install" + - "install:app-requirements" + - "mongo_packages" + +- name: install mongo server and recommends + apt: + pkg: "{{ item }}" + state: present + install_recommends: yes + force: yes + update_cache: yes + register: install_mongo_package + with_items: "{{ mongodb_debian_pkgs }}" + tags: + - "install" + - "install:app-requirements" + - "mongo_packages" + +- name: create mongo dirs + file: + path: "{{ item }}" + state: directory + owner: "{{ mongo_user }}" + group: "{{ mongo_user }}" + with_items: + - "{{ mongo_data_dir }}" + - "{{ mongo_dbpath }}" + - "{{ mongo_log_dir }}" + - "{{ mongo_journal_dir }}" + tags: + - "install" + - "install:app-configuration" + +# This will error when run on a new replica set, so we ignore_errors +# and connect anonymously next. +- name: determine if there is a replica set already + mongodb_rs_status: + host: "{{ ansible_lo['ipv4']['address'] }}" + username: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + run_once: true + register: authed_replica_set_already_configured + ignore_errors: true + tags: + - "manage" + - "manage:db-replication" + +- name: Try checking the replica set with no user/pass in case this is a new box + mongodb_rs_status: + host: "{{ ansible_lo['ipv4']['address'] }}" + run_once: true + register: unauthed_replica_set_already_configured + when: authed_replica_set_already_configured.failed is defined + ignore_errors: true + tags: + - "manage" + - "manage:db-replication" + +# We use these in the templates but also to control a whole bunch of logic +- name: set facts that default to not initializing a replica set + set_fact: + initialize_replica_set: false + skip_replica_set: false + tags: + - "install" + - "install:app-configuration" + - "update_mongod_conf" + - "manage" + - "manage:db-replication" + +# If either auth or unauthed access comes back with a replica set, we +# do not want to initialize one. Since initialization requires a bunch +# of extra templating and restarting, it's not something we want to do on +# existing boxes. +- name: track if you have a replica set + set_fact: + initialize_replica_set: true + skip_replica_set: true + when: authed_replica_set_already_configured.status is not defined + and unauthed_replica_set_already_configured.status is not defined + tags: + - "manage" + - "manage:db-replication" + +- name: warn about unconfigured replica sets + debug: msg="You do not appear to have a Replica Set configured, deploying one for you" + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: copy mongodb key file + copy: + content: "{{ MONGO_CLUSTER_KEY }}" + dest: "{{ mongo_key_file }}" + mode: 0600 + owner: mongodb + group: mongodb + register: update_mongod_key + tags: + - "manage" + - "manage:db-replication" + - "mongodb_key" + +# If skip_replica_set is true, this template will not contain a replica set stanza +# because of the fact above. +- name: copy configuration template + template: + src: mongod.conf.j2 + dest: /etc/mongod.conf + backup: yes + register: update_mongod_conf + tags: + - "install" + - "install:app-configuration" + - "manage" + - "manage:db-replication" + - "update_mongod_conf" + +# This sets the is_backup_node var by checking whether +# mongo backups are enabled AND we're currently running against the designated mongo backup node. +# This allows backup-related tasks below to determine whether or not they should run on the current mongo node. +- name: determine if backup tasks should run + set_fact: + is_backup_node: true + when: MONGO_BACKUP_ENABLED and '{{ ansible_default_ipv4.address|default(ansible_all_ipv4_addresses[0]) }}' == '{{ MONGO_BACKUP_NODE }}' + tags: + - "backup:mongo" + +- name: install logrotate configuration + template: + src: mongo_logrotate.j2 + dest: /etc/logrotate.d/hourly/mongo + tags: + - "backup:mongo" + - "install" + - "install:app-configuration" + - "logrotate" + +- name: install prereqs for backup script + apt: + pkg: "{{ item }}" + state: present + update_cache: yes + with_items: + - jq + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + - "install:app-requirements" + - "mongo_packages" + +- name: install backup script + template: + src: backup-mongo.sh.j2 + dest: "{{ mongo_backup_script_path }}" + mode: 0700 + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + +- name: add mongo backup script to cron + cron: + name: mongo backup job + minute: "{{ mongo_backup_cron.minute | default('12') }}" + hour: "{{ mongo_backup_cron.hour | default('*/12') }}" + day: "{{ mongo_backup_cron.day | default('*') }}" + month: "{{ mongo_backup_cron.month | default('*') }}" + weekday: "{{ mongo_backup_cron.weekday | default('*') }}" + job: "{{ mongo_backup_script_path }} >> {{ mongo_log_dir }}/mongo-backup.log 2>&1" + become: yes + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + +- name: format mongo backup volume + filesystem: + dev: "{{ MONGO_BACKUP_EBS_VOLUME_DEVICE }}" + fstype: ext4 + force: true + ignore_errors: true + when: + - is_backup_node + tags: + - "backup:mongo" + - "install" + +- name: restart mongo service if we changed our configuration or upgraded mongo + service: + name: mongod + state: restarted + when: update_mongod_conf.changed or update_mongod_key.changed or install_mongo_package.changed + tags: + - "manage" + - "manage:start" + - "manage:db-replication" + +- name: wait for mongo server to start + wait_for: + port: 27017 + delay: 2 + tags: + - "manage" + - "manage:start" + - "manage:db-replication" + +# We only try passwordless superuser creation when +# we're initializing the replica set and need to use +# the localhost exemption to create a user who will be +# able to initialize the replica set. +# We can only create the users on one machine, the one +# where we will initialize the replica set. If we +# create users on multiple hosts, then they will fail +# to come into the replica set. +- name: create super user + mongodb_user: + name: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + database: admin + roles: root + when: initialize_replica_set + run_once: true + tags: + - "manage" + - "manage:db-replication" + +# Now that the localhost exemption has been used to create the superuser, we need +# to add replica set to our configuration. This will never happen if we detected +# a replica set in the 'determine if there is a replica set already' task. +- name: Unset our skip initializing replica set fact so that mongod.conf gets a replica set + set_fact: + skip_replica_set: false + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: re-copy configuration template with replica set enabled + template: + src: mongod.conf.j2 + dest: /etc/mongod.conf + backup: yes + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: restart mongo service + service: + name: mongod + state: restarted + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: wait for mongo server to start + wait_for: + port: 27017 + delay: 2 + when: initialize_replica_set + tags: + - "manage" + - "manage:db-replication" + +- name: configure replica set + mongodb_replica_set: + username: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + rs_config: "{{ MONGO_RS_CONFIG }}" + run_once: true + register: replset_status + when: mongo_configure_replica_set + tags: + - "manage" + - "manage:db" + - "manage:db-replication" + - "manage:db-replication-configuration" + +# During initial replica set configuration, it can take a few seconds to vote +# a primary and for all members to reflect that status. During that window, +# use creation or other writes can fail. The best wait/check seems to be repeatedly +# checking the replica set status until we see a PRIMARY in the results. +- name: Wait for the replica set to update and (if needed) elect a primary + mongodb_rs_status: + host: "{{ ansible_lo['ipv4']['address'] }}" + username: "{{ MONGO_ADMIN_USER }}" + password: "{{ MONGO_ADMIN_PASSWORD }}" + register: status + until: status.status is defined and 'PRIMARY' in status.status.members|map(attribute='stateStr')|list + when: mongo_configure_replica_set + retries: 5 + delay: 2 + run_once: true + tags: + - "manage" + - "manage:db" + - "manage:db-replication" + +- name: create mongodb users in a replica set + mongodb_user: + database: "{{ item.database }}" + login_database: 'admin' + login_user: "{{ MONGO_ADMIN_USER }}" + login_password: "{{ MONGO_ADMIN_PASSWORD }}" + name: "{{ item.user }}" + password: "{{ item.password }}" + roles: "{{ item.roles }}" + state: present + replica_set: "{{ MONGO_REPL_SET }}" + with_items: "{{ MONGO_USERS }}" + run_once: true + when: mongo_configure_replica_set + tags: + - "manage" + - "manage:db" + - "manage:db-users" + - "manage:db-replication" + +- name: ensure mongo starts at boot time + service: + name: mongod + enabled: yes + tags: + - "manage" + - "manage:start" + +- name: add serverStatus logging script + template: + src: "log-mongo-serverStatus.sh.j2" + dest: "{{ COMMON_BIN_DIR }}/log-mongo-serverStatus.sh" + owner: "{{ mongo_user }}" + group: "{{ mongo_user }}" + mode: 0700 + when: MONGO_LOG_SERVERSTATUS + tags: + - "install" + - "install:app-configuration" + +- name: add serverStatus logging script to cron + cron: + name: mongostat logging job + minute: "*/3" + job: /edx/bin/log-mongo-serverStatus.sh >> {{ mongo_log_dir }}/serverStatus.log 2>&1 + become: yes + when: MONGO_LOG_SERVERSTATUS + tags: + - "install" + - "install:app-configuration" diff --git a/playbooks/roles/mongo_7_0/templates/log-mongo-serverStatus.sh.j2 b/playbooks/roles/mongo_7_0/templates/log-mongo-serverStatus.sh.j2 new file mode 100644 index 00000000000..04649d55ad1 --- /dev/null +++ b/playbooks/roles/mongo_7_0/templates/log-mongo-serverStatus.sh.j2 @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# Using JSON.stringify forces output of normal JSON, as opposed to Mongo's weird non-compliant extended JSON +/usr/bin/mongo -u {{ MONGO_ADMIN_USER }} --authenticationDatabase admin -p '{{ MONGO_ADMIN_PASSWORD }}' --quiet <<< 'JSON.stringify(db.serverStatus())' diff --git a/playbooks/roles/mongo_7_0/templates/mongo_logrotate.j2 b/playbooks/roles/mongo_7_0/templates/mongo_logrotate.j2 new file mode 100644 index 00000000000..f2fb4483566 --- /dev/null +++ b/playbooks/roles/mongo_7_0/templates/mongo_logrotate.j2 @@ -0,0 +1,46 @@ +{{ mongo_log_dir }}/serverStatus.log { + create + compress + copytruncate + delaycompress + dateext + dateformat -%Y%m%d-%s + missingok + notifempty + daily + rotate 90 + size 1M +} + +{% if is_backup_node %} +{{ mongo_log_dir }}/mongo-backup.log { + create + compress + copytruncate + delaycompress + dateext + dateformat -%Y%m%d-%s + missingok + notifempty + daily + rotate 90 + size 1M +} +{% endif %} + +{{ mongo_log_dir }}/mongodb.log { + create + compress + copytruncate + delaycompress + dateext + dateformat -%Y%m%d-%s + missingok + notifempty + daily + rotate 90 + size 1M + postrotate + /usr/bin/killall -USR1 mongod + endscript +} diff --git a/playbooks/roles/mongo_7_0/templates/mongod.conf.j2 b/playbooks/roles/mongo_7_0/templates/mongod.conf.j2 new file mode 100644 index 00000000000..211d34cebe3 --- /dev/null +++ b/playbooks/roles/mongo_7_0/templates/mongod.conf.j2 @@ -0,0 +1,40 @@ +# {{ ansible_managed }} +# mongodb.conf + + +storage: + # Where to store the data. + dbPath: {{ mongo_dbpath }} + # Storage Engine + engine: {{ MONGO_STORAGE_ENGINE }} +{% endif %} +{% if MONGO_STORAGE_ENGINE_OPTIONS %} + {{ MONGO_STORAGE_ENGINE_OPTIONS | to_nice_yaml }} +{% endif %} + +systemLog: + #where to log + destination: file + path: "{{ mongo_logpath }}" +{% if mongo_logappend %} + logAppend: true +{% else %} + logAppend: false +{% endif %} + logRotate: {{ mongo_logrotate }} + +{% if not skip_replica_set %} +replication: + replSetName: {{ MONGO_REPL_SET }} + +security: + authorization: {{ MONGO_AUTH | ternary("enabled", "disabled") }} + keyFile: {{ mongo_key_file }} + +{% endif %} +net: + bindIp: {{ MONGO_BIND_IP }} + port: {{ mongo_port }} + + +{{ mongo_extra_conf }} diff --git a/util/jenkins/ansible-provision.sh b/util/jenkins/ansible-provision.sh index 63e462652c2..8a2a23634e6 100644 --- a/util/jenkins/ansible-provision.sh +++ b/util/jenkins/ansible-provision.sh @@ -520,6 +520,28 @@ EOF_AUTH fi +if [[ $mongo_version == "5.0" ]]; then + cat << MONGO_VERSION >> $extra_vars_file +MONGO_5_0_ENABLED: True +MONGO_6_0_ENABLED: False +MONGO_7_0_ENABLED: False +MONGO_VERSION +fi +if [[ $mongo_version == "6.0" ]]; then + cat << MONGO_VERSION >> $extra_vars_file +MONGO_5_0_ENABLED: False +MONGO_6_0_ENABLED: True +MONGO_7_0_ENABLED: False +MONGO_VERSION +fi +if [[ $mongo_version == "7.0" ]]; then + cat << MONGO_VERSION >> $extra_vars_file +MONGO_5_0_ENABLED: False +MONGO_6_0_ENABLED: False +MONGO_7_0_ENABLED: True +MONGO_VERSION +fi + if [[ -n $nginx_users ]]; then cat << EOF_AUTH >> $extra_vars_file NGINX_USERS: $nginx_users