From 97a3776d8e977a94ef0daafa7ca119b2f8906c4d Mon Sep 17 00:00:00 2001 From: Max Gautier Date: Mon, 10 Nov 2025 11:52:56 +0000 Subject: [PATCH] Remove etcd member by peerURLs (#12682) * Remove etcd member by peerURLs The way to obtain the IP of a particular member is convoluted and depend on multiple variables. The match is also textual and it's not clear against what we're matching It's also broken for etcd member which are not also Kubernetes nodes, because the "Lookup node IP in kubernetes" task will fail and abort the play. Instead, match against 'peerURLs', which does not need new variable, and use json output. * Add testcase for etcd removal on external etcd * do not merge * fixup! Remove etcd member by peerURLs * fixup! Remove etcd member by peerURLs --- .gitlab-ci.yml | 2 +- .../remove-etcd-node/tasks/main.yml | 21 ++----------------- tests/files/ubuntu24-ha-separate-etcd | 2 ++ tests/scripts/testcases_run.sh | 2 +- 4 files changed, 6 insertions(+), 21 deletions(-) create mode 100644 tests/files/ubuntu24-ha-separate-etcd diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 256e0b52f..a3cca0015 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ variables: ANSIBLE_REMOTE_USER: kubespray ANSIBLE_PRIVATE_KEY_FILE: /tmp/id_rsa ANSIBLE_INVENTORY: /tmp/inventory - ANSIBLE_STDOUT_CALLBACK: "debug" + ANSIBLE_STDOUT_CALLBACK: "default" RESET_CHECK: "false" REMOVE_NODE_CHECK: "false" UPGRADE_TEST: "false" diff --git a/roles/remove-node/remove-etcd-node/tasks/main.yml b/roles/remove-node/remove-etcd-node/tasks/main.yml index d4efed01c..2b8fc24cd 100644 --- a/roles/remove-node/remove-etcd-node/tasks/main.yml +++ b/roles/remove-node/remove-etcd-node/tasks/main.yml @@ -1,14 +1,4 @@ --- -- name: Lookup node IP in kubernetes - command: > - {{ kubectl }} get nodes {{ node }} - -o jsonpath-as-json='{.status.addresses[?(@.type=="InternalIP")].address}' - register: k8s_node_ips - changed_when: false - when: - - groups['kube_control_plane'] | length > 0 - delegate_to: "{{ groups['kube_control_plane'] | first }}" - - name: Remove etcd member from cluster environment: ETCDCTL_API: "3" @@ -19,25 +9,18 @@ delegate_to: "{{ groups['etcd'] | first }}" block: - name: Lookup members infos - command: "{{ bin_dir }}/etcdctl member list" + command: "{{ bin_dir }}/etcdctl member list -w json" register: etcd_members changed_when: false check_mode: false tags: - facts - name: Remove member from cluster - vars: - node_ip: >- - {%- if not ipv4_stack -%} - {{ ip6 if ip6 is defined else (access_ip6 if access_ip6 is defined else (k8s_node_ips.stdout | from_json)[0]) | ansible.utils.ipwrap }} - {%- else -%} - {{ ip if ip is defined else (access_ip if access_ip is defined else (k8s_node_ips.stdout | from_json)[0]) | ansible.utils.ipwrap }} - {%- endif -%} command: argv: - "{{ bin_dir }}/etcdctl" - member - remove - - "{{ ((etcd_members.stdout_lines | select('contains', '//' + node_ip + ':'))[0] | split(','))[0] }}" + - "{{ '%x' | format(((etcd_members.stdout | from_json).members | selectattr('peerURLs.0', '==', etcd_peer_url))[0].ID) }}" register: etcd_removal_output changed_when: "'Removed member' in etcd_removal_output.stdout" diff --git a/tests/files/ubuntu24-ha-separate-etcd b/tests/files/ubuntu24-ha-separate-etcd new file mode 100644 index 000000000..9a1bffe1a --- /dev/null +++ b/tests/files/ubuntu24-ha-separate-etcd @@ -0,0 +1,2 @@ +REMOVE_NODE_CHECK=true +REMOVE_NODE_NAME=etcd[2] diff --git a/tests/scripts/testcases_run.sh b/tests/scripts/testcases_run.sh index edca43361..04b9c9d4a 100755 --- a/tests/scripts/testcases_run.sh +++ b/tests/scripts/testcases_run.sh @@ -92,7 +92,7 @@ ansible-playbook \ # Test node removal procedure if [ "${REMOVE_NODE_CHECK}" = "true" ]; then - run_playbook remove-node -e skip_confirmation=yes -e node=${REMOVE_NODE_NAME} + run_playbook remove-node -e skip_confirmation=yes -e node="${REMOVE_NODE_NAME}" fi # Clean up at the end, this is to allow stage1 tests to include cleanup test