# Upgrades a full mongo cluster, starting with the hidden members, then the # secondary, and finally steps down the primary and upgrades it. It checks along # the way for a healthy cluster, failing if that is not true. # # This play expects to have access to a config file where MONGO_RS_CONFIG, as described # in the mongo_3_0 role, is defined, as well as MONGO_ADMIN_USER and MONGO_ADMIN_PASSWORD. # # ansible-playbook -i 127.0.0.1, mongo_rolling_upgrade.yml -e@/path/to/config-file.yml # # This play uses MONGO_RS_CONFIG to find a host to connect to and fetch replset config and build an # inventory, so you can just target localhost. # # If there are no hidden secondaries, the 'Upgrade hidden members' task block will just skip. # # This will process a hidden secondary twice - first as a 'hidden' server, then as a 'secondary' but # this is effectively a no-op except for apt checking the versions and then checking that mongo is running. # It is valid to have other types of hidden machines, so this seemed better than skipping. # # If you wish to avoid updating the primary, you can add -e 'SKIP_PRIMARY=true' to your ansible # invocation. - name: Find hidden secondaries hosts: 127.0.0.1 connection: local gather_facts: False vars: - SKIP_PRIMARY: False tasks: - name: Get configuration of mongo cluster mongodb_rs_config: host: "{{ (MONGO_RS_CONFIG.members|map(attribute='host')|list)[0] }}" username: "{{ MONGO_ADMIN_USER }}" password: "{{ MONGO_ADMIN_PASSWORD }}" register: rs_config - name: Build inventory of hidden members add_host: hostname: "{{ (item.host.split(':'))[0] }}" instance_id: "{{ item._id }}" groups: hidden_hosts ansible_ssh_user: ubuntu with_items: - "{{ rs_config.hidden }}" - name: Build inventory of secondary members add_host: hostname: "{{ (item.host.split(':'))[0] }}" instance_id: "{{ item._id }}" groups: secondary_hosts ansible_ssh_user: ubuntu with_items: - "{{ rs_config.secondary }}" - name: Build inventory of primary members add_host: hostname: "{{ (item.host.split(':'))[0] }}" instance_id: "{{ item._id }}" groups: primary_hosts ansible_ssh_user: ubuntu with_items: - "{{ rs_config.primary }}" when: not SKIP_PRIMARY - name: Upgrade hidden members hosts: hidden_hosts gather_facts: True become: True vars_files: - ../roles/mongo_3_0/defaults/main.yml tasks: - name: install mongo server and recommends apt: pkg: "{{ item }}" state: present install_recommends: yes force: yes update_cache: yes with_items: "{{ mongodb_debian_pkgs }}" - name: wait for mongo server to start wait_for: port: 27017 delay: 2 - name: Wait for the replica set to update and (if needed) elect a primary mongodb_rs_status: host: "{{ ansible_default_ipv4['address'] }}" username: "{{ MONGO_ADMIN_USER }}" password: "{{ MONGO_ADMIN_PASSWORD }}" register: status # This ensures that no servers are in a state other than PRIMARY or SECONDARY. https://docs.mongodb.com/manual/reference/replica-states/ until: status.status is defined and not (['PRIMARY','SECONDARY'] | symmetric_difference(status.status.members|map(attribute='stateStr')|list|unique)) retries: 5 delay: 2 - name: Upgrade secondary members hosts: secondary_hosts gather_facts: True become: True serial: 1 vars_files: - ../roles/mongo_3_0/defaults/main.yml tasks: - name: install mongo server and recommends apt: pkg: "{{ item }}" state: present install_recommends: yes force: yes update_cache: yes with_items: "{{ mongodb_debian_pkgs }}" - name: wait for mongo server to start wait_for: port: 27017 delay: 2 - name: Wait for the replica set to update and (if needed) elect a primary mongodb_rs_status: host: "{{ ansible_default_ipv4['address'] }}" username: "{{ MONGO_ADMIN_USER }}" password: "{{ MONGO_ADMIN_PASSWORD }}" register: status # This ensures that no servers are in a state other than PRIMARY or SECONDARY. https://docs.mongodb.com/manual/reference/replica-states/ until: status.status is defined and not (['PRIMARY','SECONDARY'] | symmetric_difference(status.status.members|map(attribute='stateStr')|list|unique)) retries: 5 delay: 2 - name: Upgrade primary members hosts: primary_hosts gather_facts: True become: True vars_files: - ../roles/mongo_3_0/defaults/main.yml tasks: - name: Step down (this can take up to a minute to complete while the primary waits on a secondary) mongodb_step_down: host: "{{ ansible_default_ipv4['address'] }}" username: "{{ MONGO_ADMIN_USER }}" password: "{{ MONGO_ADMIN_PASSWORD }}" - name: install mongo server and recommends apt: pkg: "{{ item }}" state: present install_recommends: yes force: yes update_cache: yes with_items: "{{ mongodb_debian_pkgs }}" - name: wait for mongo server to start wait_for: port: 27017 delay: 2 - name: Wait for the replica set to update and (if needed) elect a primary mongodb_rs_status: host: "{{ ansible_default_ipv4['address'] }}" username: "{{ MONGO_ADMIN_USER }}" password: "{{ MONGO_ADMIN_PASSWORD }}" register: status # This ensures that no servers are in a state other than PRIMARY or SECONDARY. https://docs.mongodb.com/manual/reference/replica-states/ until: status.status is defined and not (['PRIMARY','SECONDARY'] | symmetric_difference(status.status.members|map(attribute='stateStr')|list|unique)) retries: 5 delay: 2