# The problem might be having a different size in the number of controller # nodes (that should be decommissioned, and the number of target nodes: we # need to establish rules and block the process if it's not possible to # complete the migration (either because of cardinality of just because we # don't have enough nodes). - name: Setup a Ceph client to the first node ansible.builtin.include_tasks: ceph_client.yaml vars: # Use the inventory as source of truth to make sure we **always** # select mon[0] as client. If we stick on decomm_nodes nodes we # might end up selecting a different node on multiple runs. client_node: "{{ groups['mon'][0] | default(decomm_nodes | list | sort | first) }}" os_net_conf_path: "/etc/os-net-config/tripleo_config.yaml" tags: - ceph_client - ceph_rbd # Extend mgr deployment to help with failover - name: MGR - Migrate RBD node ansible.builtin.include_tasks: mgr.yaml tags: - ceph_mgr - ceph_rbd # Normalize the mon spec to use labels instead of hosts as placement - name: MON - Load Spec from the orchestrator ansible.builtin.set_fact: mon_spec: "{{ mon }}" vars: mon: |- {% set mon = {} %} {% for item in servicemap %} {% if item.service_type == 'mon' %} {% set _ = mon.__setitem__('service_type', item.service_type) %} {% set _ = mon.__setitem__('service_name', item.service_name) %} {% set _ = mon.__setitem__('spec', {}) %} {% endif %} {% endfor %} {{ mon }} tags: - ceph_rbd # We add labels in advance to the target node to make sure we are able to # deploy a tmp mon that will be replaced with the right one (on the desired # network). By adding an additional mon at this stage we can ensure we always # have quorum and at least 3 active mons while migrating the src daemon to the # target node. - name: Expand MON labels to the overcloud nodes ansible.builtin.import_tasks: labels.yaml vars: nodes: "{{ hostmap.keys() }}" act: "add" labels: - "mon" - "_admin" - name: Normalize the mon spec to use labels # root privileges required to run cephadm # and apply the new spec become: true ceph_mkspec: service_type: "{% set st = mon_spec.get('service_type', 'mon') %}{{ st }}" cluster: ceph apply: true label: "mon" render_path: "{{ ceph_spec_render_dir }}" register: spc environment: CEPH_CONTAINER_IMAGE: "{{ ceph_container }}" CEPH_CONTAINER_BINARY: "{{ ceph_container_cli }}" tags: - ceph_rbd # Wait for new mons as a result of the spec apply: we already have three mons # deployed on decomm_nodes, we should now see three more on target_node(s) - name: RBD - wait new daemons to be available ansible.builtin.include_tasks: wait_daemons.yaml vars: daemon: mon daemon_id: "{{ node.split('.')[0] }}" loop: "{{ target_nodes }}" loop_control: loop_var: node # we need to serially migrate mons, so we loop over the nodes and run the # procedure provided by mon.yaml - name: MON - Migrate RBD node tags: - ceph_rbd block: - name: MON - Migrate RBD node ansible.builtin.include_tasks: mon.yaml vars: cur_mon: "{{ node.0 }}" target_node: "{{ node.1 }}" client_node: "{{ groups['mon'][0] | default(decomm_nodes | list | sort | first) }}" # This condition might be a different one loop: "{{ decomm_nodes | zip(target_nodes) }}" loop_control: loop_var: node # Sleep before moving to the next mon: this ensures that we give time to # cephadm to converge to a state that sees the new data. We can replace # this check later in time with a dynamic wait() based on cephadm - name: Sleep before moving to the next mon ansible.builtin.pause: seconds: "{{ ceph_timeout }}"