resource-agents/SOURCES/RHEL-113813-podman-etcd-wrap-ipv6-address-in-brackets.patch

194 lines
8.0 KiB
Diff

From 11cdff8c886c72c83c26e48e46a8620c06e4c2f0 Mon Sep 17 00:00:00 2001
From: E Hila <ehila@redhat.com>
Date: Tue, 9 Sep 2025 06:06:12 -0400
Subject: [PATCH] OCPBUGS-60977: podman-etcd: wrap ipv6 address in brackets for
attribute_node_ip (#2068)
When trying to determine the node ip address we need to make sure we account for ipv6 and dualstack deployments, and accordingly wrap ipv6 in brackets so it correctly resolves. Since the node ip mapping is provided by the controller, we parse out the IP address of the node from there and use a helper function for building URLs with ports to correctly use brackets for ipv6 ip addresses.
Signed-off-by: ehila <ehila@redhat.com>
---
heartbeat/podman-etcd | 77 ++++++++++++++++++++++++++++---------------
1 file changed, 51 insertions(+), 26 deletions(-)
diff --git a/heartbeat/podman-etcd b/heartbeat/podman-etcd
index 884b7c579..4969fbaaf 100755
--- a/heartbeat/podman-etcd
+++ b/heartbeat/podman-etcd
@@ -347,21 +347,41 @@ remove_container()
return $rc
}
+# Correctly wraps an ipv6 in [] for url otherwise use return normal ipv4 address.
+ip_url() {
+ local ip_addr=$1
+ local value
+ if echo "$ip_addr" | grep -q ":" ; then
+ value="[$ip_addr]"
+ else
+ value="$ip_addr"
+ fi
+ echo "https://$value"
+}
+
attribute_node_ip()
{
local action="$1"
local attribute="node_ip"
- local value
+ local ip_addr name
- if ! value=$(ip -brief addr show "$OCF_RESKEY_nic" | awk '{gsub("/.*", "", $3); print $3}'); then
- rc=$?
- ocf_log err "could not get node ip, error code: $rc"
- return "$rc"
+ for node in $(echo "$OCF_RESKEY_node_ip_map" | sed "s/\s//g;s/;/ /g"); do
+ name=$(echo "$node" | cut -d: -f1)
+ # ignore other nodes
+ if [ "$name" != "$NODENAME" ]; then
+ continue
+ fi
+ ip_addr=$(echo "$node" | cut -d: -f2-) # Grab everything after the first : this covers ipv4/ipv6
+ done
+
+ if [ -z "$ip_addr" ]; then
+ ocf_log err "ip address was empty when querying (getent ahosts) for hostname: $(hostname -f)"
+ return 1
fi
case "$action" in
get)
- echo "$value"
+ echo "$ip_addr"
;;
update)
if ! crm_attribute --type nodes --node "$NODENAME" --name "$attribute" --update "$value"; then
@@ -409,26 +429,28 @@ get_env_from_manifest() {
}
prepare_env() {
- local name ip standalone_node
+ local name ip ipurl standalone_node
NODEIP="$(attribute_node_ip get)"
+ NODEIPURL=$(ip_url $NODEIP)
if is_force_new_cluster; then
- ALL_ETCD_ENDPOINTS="https://$NODEIP:2379"
+ ALL_ETCD_ENDPOINTS="$NODEIPURL:2379"
ETCD_INITIAL_CLUSTER_STATE="new"
- ETCD_INITIAL_CLUSTER="$NODENAME=https://$NODEIP:2380"
+ ETCD_INITIAL_CLUSTER="$NODENAME=$NODEIPURL:2380"
else
ETCD_INITIAL_CLUSTER_STATE="existing"
for node in $(echo "$OCF_RESKEY_node_ip_map" | sed "s/\s//g;s/;/ /g"); do
- name=$(echo "$node" | awk -F":" '{print $1}')
- ip=$(echo "$node" | awk -F":" '{print $2}')
+ name=$(echo "$node" | cut -d: -f1)
+ ip=$(echo "$node" | cut -d: -f2-) # Grab everything after the first : this covers ipv4/ipv6
+ ipurl="$(ip_url $ip)"
if [ -z "$name" ] || [ -z "$ip" ]; then
ocf_exit_reason "name or ip missing for 1 or more nodes"
exit $OCF_ERR_CONFIGURED
fi
- [ -z "$ALL_ETCD_ENDPOINTS" ] && ALL_ETCD_ENDPOINTS="https://$ip:2379" || ALL_ETCD_ENDPOINTS="$ALL_ETCD_ENDPOINTS,https://$ip:2379"
- [ -z "$ETCD_INITIAL_CLUSTER" ] && ETCD_INITIAL_CLUSTER="$name=https://$ip:2380" || ETCD_INITIAL_CLUSTER="$ETCD_INITIAL_CLUSTER,$name=https://$ip:2380"
+ [ -z "$ALL_ETCD_ENDPOINTS" ] && ALL_ETCD_ENDPOINTS="$ipurl:2379" || ALL_ETCD_ENDPOINTS="$ALL_ETCD_ENDPOINTS,$ipurl:2379"
+ [ -z "$ETCD_INITIAL_CLUSTER" ] && ETCD_INITIAL_CLUSTER="$name=$ipurl:2380" || ETCD_INITIAL_CLUSTER="$ETCD_INITIAL_CLUSTER,$name=$ipurl:2380"
done
fi
@@ -609,9 +631,11 @@ add_member_as_learner()
local rc
local member_name=$1
local member_ip=$2
+ local endpoint_url=$(ip_url $(attribute_node_ip get))
+ local peer_url=$(ip_url $member_ip)
ocf_log info "add $member_name ($member_ip) to the member list as learner"
- out=$(podman exec "${CONTAINER}" etcdctl --endpoints="https://$(attribute_node_ip get):2379" member add "$member_name" --peer-urls="https://$member_ip:2380" --learner)
+ out=$(podman exec "${CONTAINER}" etcdctl --endpoints="$endpoint_url:2379" member add "$member_name" --peer-urls="$peer_url:2380" --learner)
rc=$?
if [ $rc -ne 0 ]; then
ocf_log err "could not add $member_name as learner, error code: $rc"
@@ -806,14 +830,15 @@ get_peer_node_name() {
get_all_etcd_endpoints() {
for node in $(echo "$OCF_RESKEY_node_ip_map" | sed "s/\s//g;s/;/ /g"); do
- name=$(echo "$node" | awk -F":" '{print $1}')
- ip=$(echo "$node" | awk -F":" '{print $2}')
+ name=$(echo "$node" | cut -d: -f1)
+ ip=$(echo "$node" | cut -d: -f2-) # Grab everything after the first : this covers ipv4/ipv6
+ ipurl="$(ip_url $ip)"
if [ -z "$name" ] || [ -z "$ip" ]; then
ocf_exit_reason "name or ip missing for 1 or more nodes"
exit $OCF_ERR_CONFIGURED
fi
- [ -z "$ALL_ETCD_ENDPOINTS" ] && ALL_ETCD_ENDPOINTS="https://$ip:2379" || ALL_ETCD_ENDPOINTS="$ALL_ETCD_ENDPOINTS,https://$ip:2379"
+ [ -z "$ALL_ETCD_ENDPOINTS" ] && ALL_ETCD_ENDPOINTS="$ipurl:2379" || ALL_ETCD_ENDPOINTS="$ALL_ETCD_ENDPOINTS,$ipurl:2379"
done
echo "$ALL_ETCD_ENDPOINTS"
}
@@ -831,7 +856,7 @@ get_member_list_json() {
# Get the list of members visible to the current node
local this_node_endpoint
- this_node_endpoint="https://$(attribute_node_ip get):2379"
+ this_node_endpoint="$(ip_url $(attribute_node_ip get)):2379"
podman exec "${CONTAINER}" etcdctl member list --endpoints="$this_node_endpoint" -w json
}
@@ -886,14 +911,14 @@ check_peers()
# ]
# }
for node in $(echo "$OCF_RESKEY_node_ip_map" | sed "s/\s//g;s/;/ /g"); do
- name=$(echo "$node" | awk -F":" '{print $1}')
+ name=$(echo "$node" | cut -d: -f1)
# do not check itself
if [ "$name" = "$NODENAME" ]; then
continue
fi
# Check by IP instead of Name since "learner" members appear only in peerURLs, not by Name.
- ip=$(echo "$node" | awk -F":" '{print $2}')
+ ip=$(echo "$node" | cut -d: -f2-) # Grab everything after the first : this covers ipv4/ipv6
id=$(printf "%s" "$member_list_json" | jq -r ".members[] | select( .peerURLs | map(test(\"$ip\")) | any).ID")
if [ -z "$id" ]; then
ocf_log info "$name is not in the members list"
@@ -1307,7 +1332,7 @@ podman_start()
--log-level=info \
--experimental-initial-corrupt-check=true \
--snapshot-count=10000 \
- --initial-advertise-peer-urls=https://${NODEIP}:2380 \
+ --initial-advertise-peer-urls=$NODEIPURL:2380 \
--cert-file=/etc/kubernetes/static-pod-certs/secrets/etcd-all-certs/etcd-serving-${NODENAME}.crt \
--key-file=/etc/kubernetes/static-pod-certs/secrets/etcd-all-certs/etcd-serving-${NODENAME}.key \
--trusted-ca-file=$SERVER_CACERT \
@@ -1316,11 +1341,11 @@ podman_start()
--peer-key-file=$ETCD_PEER_KEY \
--peer-trusted-ca-file=$SERVER_CACERT \
--peer-client-cert-auth=true \
- --advertise-client-urls=https://${NODEIP}:2379 \
- --listen-client-urls=https://${LISTEN_CLIENT_URLS}:2379,unixs://${NODEIP}:0 \
- --listen-peer-urls=https://${LISTEN_PEER_URLS}:2380 \
+ --advertise-client-urls=$NODEIPURL:2379 \
+ --listen-client-urls=$(ip_url ${LISTEN_CLIENT_URLS}):2379,unixs://${NODEIP}:0 \
+ --listen-peer-urls=$(ip_url ${LISTEN_PEER_URLS}):2380 \
--metrics=extensive \
- --listen-metrics-urls=https://${LISTEN_METRICS_URLS}:9978"
+ --listen-metrics-urls=$(ip_url ${LISTEN_METRICS_URLS}):9978"
if [ -n "$OCF_RESKEY_run_cmd_opts" ]; then
OCF_RESKEY_run_cmd="$OCF_RESKEY_run_cmd $OCF_RESKEY_run_cmd_opts"
fi
@@ -1430,7 +1455,7 @@ podman_stop()
ocf_log info "last member. Not leaving the member list"
else
ocf_log info "leaving members list as member with ID $member_id"
- endpoint="https://$(attribute_node_ip get):2379"
+ endpoint="$(ip_url $(attribute_node_ip get)):2379"
if ! ocf_run podman exec "$CONTAINER" etcdctl member remove "$member_id" --endpoints="$endpoint"; then
rc=$?
ocf_log err "error leaving members list, error code: $rc"