From 7613ce036ccca287477bb6b3064900699e853d47 Mon Sep 17 00:00:00 2001 From: fracappa Date: Thu, 18 Jun 2026 10:51:25 +0200 Subject: [PATCH] feat: add macAddress as alternative identifier for fencing credentials Introduce FENCING_CREDENTIALS_IDENTIFIER env var to control whether fencing credentials identify nodes by hostname (default) or macAddress. --- agent/05_agent_configure.sh | 8 ++++++ .../install-config_baremetal_yaml.j2 | 17 +++++++----- agent/roles/manifests/vars/main.yml | 2 ++ common.sh | 8 ++++++ config_example.sh | 8 ++++++ utils.sh | 26 +++++++++++++------ 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/agent/05_agent_configure.sh b/agent/05_agent_configure.sh index c0bc75fb4..3afae4bfd 100755 --- a/agent/05_agent_configure.sh +++ b/agent/05_agent_configure.sh @@ -130,6 +130,9 @@ function configure_node() { AGENT_NODES_IPSV6+=("$ipv6") fi AGENT_NODES_MACS+=("$node_mac") + if [[ "$node_type" == "master" ]]; then + AGENT_MASTER_MACS+=("$node_mac") + fi if [[ ! -z "${BOND_PRIMARY_INTERFACE:-}" ]]; then # For a bond, a random mac is added for the 2nd interface AGENT_NODES_MACS+=("$(sudo virsh domiflist "${cluster_name}" | grep "${BAREMETAL_NETWORK_NAME}" | grep -v "${node_mac}" | awk '{print $5}')") @@ -152,6 +155,7 @@ function get_static_ips_and_macs() { AGENT_NODES_IPSV6=() AGENT_NODES_MACS=() AGENT_NODES_HOSTNAMES=() + AGENT_MASTER_MACS=() AGENT_EXTRA_WORKERS_IPS=() AGENT_EXTRA_WORKERS_IPSV6=() AGENT_EXTRA_WORKERS_MACS=() @@ -188,6 +192,7 @@ function get_baremetal_ips_and_macs() { AGENT_NODES_MACS=() AGENT_NODES_HOSTNAMES=() AGENT_MASTER_HOSTNAMES=() + AGENT_MASTER_MACS=() AGENT_EXTRA_WORKERS_IPS=() AGENT_EXTRA_WORKERS_IPSV6=() AGENT_EXTRA_WORKERS_MACS=() @@ -219,6 +224,7 @@ function get_baremetal_ips_and_macs() { AGENT_NODES_MACS+=("$mac") AGENT_NODES_HOSTNAMES+=("$hostname") AGENT_MASTER_HOSTNAMES+=("$hostname") + AGENT_MASTER_MACS+=("$mac") else AGENT_EXTRA_WORKERS_IPS+=("$ip") AGENT_EXTRA_WORKERS_MACS+=("$mac") @@ -361,6 +367,8 @@ function generate_cluster_manifests() { master_hostnames=$(printf '%s,' "${AGENT_MASTER_HOSTNAMES[@]}") export AGENT_MASTER_HOSTNAMES_STR=${master_hostnames::-1} + master_macs=$(printf '%s,' "${AGENT_MASTER_MACS[@]}") + export AGENT_MASTER_MACS_STR=${master_macs::-1} master_bmc_usernames=$(printf '%s,' "${AGENT_MASTER_BMC_USERNAMES[@]}") export AGENT_MASTER_BMC_USERNAMES_STR=${master_bmc_usernames::-1} master_bmc_passwords=$(printf '%s,' "${AGENT_MASTER_BMC_PASSWORDS[@]}") diff --git a/agent/roles/manifests/templates/install-config_baremetal_yaml.j2 b/agent/roles/manifests/templates/install-config_baremetal_yaml.j2 index 8d9f9dc9f..33e601bb2 100644 --- a/agent/roles/manifests/templates/install-config_baremetal_yaml.j2 +++ b/agent/roles/manifests/templates/install-config_baremetal_yaml.j2 @@ -37,18 +37,23 @@ controlPlane: replicas: {{ num_masters }} {% if enable_two_node_fencing %} {% set master_hostnames = agent_master_hostnames.split(',') %} +{% set master_macs = agent_master_macs.split(',') %} {% set master_bmc_addresses = agent_master_bmc_addresses.split(',') %} {% set master_bmc_usernames = agent_master_bmc_usernames.split(',') %} {% set master_bmc_passwords = agent_master_bmc_passwords.split(',') %} {% set master_bmc_verify_cas = agent_master_bmc_verify_cas.split(',') %} fencing: credentials: -{% for hostname in master_hostnames %} - - hostname: {{hostname}} - address: {{ master_bmc_addresses[loop.index0] }} - username: {{ master_bmc_usernames[loop.index0] }} - password: {{ master_bmc_passwords[loop.index0] }} - certificateVerification: {{ 'Disabled' if bmc_verify_cas[loop.index0] == "False" else 'Enabled' }} +{% for i in range(master_hostnames | length) %} +{% if fencing_credential_identifier == "macAddress" %} + - macAddress: {{ master_macs[i] }} +{% else %} + - hostname: {{ master_hostnames[i] }} +{% endif %} + address: {{ master_bmc_addresses[i] }} + username: {{ master_bmc_usernames[i] }} + password: {{ master_bmc_passwords[i] }} + certificateVerification: {{ 'Disabled' if master_bmc_verify_cas[i] == "False" else 'Enabled' }} {% endfor %} {% endif %} fips: {{ fips_mode }} diff --git a/agent/roles/manifests/vars/main.yml b/agent/roles/manifests/vars/main.yml index cdeef1fb7..c2f1fd87a 100644 --- a/agent/roles/manifests/vars/main.yml +++ b/agent/roles/manifests/vars/main.yml @@ -31,6 +31,7 @@ cluster_subnet_v4: "{{ lookup('env', 'CLUSTER_SUBNET_V4') }}" cluster_subnet_v6: "{{ lookup('env', 'CLUSTER_SUBNET_V6') }}" enable_local_registry: "{{ lookup('env', 'ENABLE_LOCAL_REGISTRY') != '' }}" enable_two_node_fencing: "{{ lookup('env', 'ENABLE_TWO_NODE_FENCING', default='') == 'true' }}" +fencing_credential_identifier: "{{ lookup('env', 'FENCING_CREDENTIAL_IDENTIFIER', default='hostname') }}" external_subnet_v4: "{{ lookup('env', 'EXTERNAL_SUBNET_V4') }}" external_subnet_v6: "{{ lookup('env', 'EXTERNAL_SUBNET_V6') }}" external_subnet_v4_prefixlen: "{{ lookup('env', 'EXTERNAL_SUBNET_V4') | ansible.utils.ipaddr('prefix') }}" @@ -73,6 +74,7 @@ service_subnet_v4: "{{ lookup('env', 'SERVICE_SUBNET_V4') }}" service_subnet_v6: "{{ lookup('env', 'SERVICE_SUBNET_V6') }}" version: "{{ lookup('env', 'VERSION') }}" agent_master_hostnames: "{{ lookup('env', 'AGENT_MASTER_HOSTNAMES_STR') }}" +agent_master_macs: "{{ lookup('env', 'AGENT_MASTER_MACS_STR') }}" agent_master_bmc_addresses: "{{ lookup('env', 'AGENT_MASTER_BMC_ADDRESSES_STR') }}" agent_master_bmc_passwords: "{{ lookup('env', 'AGENT_MASTER_BMC_PASSWORDS_STR') }}" agent_master_bmc_usernames: "{{ lookup('env', 'AGENT_MASTER_BMC_USERNAMES_STR') }}" diff --git a/common.sh b/common.sh index 4bd9161d2..2304c9926 100644 --- a/common.sh +++ b/common.sh @@ -412,6 +412,14 @@ if [[ -z ${AGENT_E2E_TEST_SCENARIO:-} ]] && [[ ${NUM_ARBITERS} -eq 0 ]] && [[ ${ export ENABLE_TWO_NODE_FENCING="true" fi +# Controls whether fencing credentials use "hostname" or "macAddress" to identify nodes +export FENCING_CREDENTIAL_IDENTIFIER=${FENCING_CREDENTIAL_IDENTIFIER:-hostname} + +if [[ "${FENCING_CREDENTIAL_IDENTIFIER}" != "hostname" ]] && [[ "${FENCING_CREDENTIAL_IDENTIFIER}" != "macAddress" ]]; then + printf "FENCING_CREDENTIAL_IDENTIFIER must be 'hostname' or 'macAddress', got '%s'\n" "${FENCING_CREDENTIAL_IDENTIFIER}" + exit 1 +fi + # Only redfish BMC driver is supported for two node fencing if [[ "${BMC_DRIVER}" != "redfish" ]] && [[ "${ENABLE_TWO_NODE_FENCING:-}" == "true" ]]; then printf "Only redfish BMC driver is supported for Two Node Fencing deployments: BMC_DRIVER=%s, ENABLE_TWO_NODE_FENCING=%s" "${BMC_DRIVER}" "${ENABLE_TWO_NODE_FENCING}" diff --git a/config_example.sh b/config_example.sh index ef41c477a..20a2a02dc 100755 --- a/config_example.sh +++ b/config_example.sh @@ -665,6 +665,14 @@ set -x #export ARBITER_DISK=50 #export ARBITER_VCPU=2 +# FENCING_CREDENTIAL_IDENTIFIER - +# Controls the identifier used in fencing credentials for Two Node Fencing. +# Set to "hostname" to identify nodes by hostname (default), or "macAddress" +# to identify nodes by their boot MAC address. +# Default: "hostname" +# +#export FENCING_CREDENTIAL_IDENTIFIER=hostname + # WORKER_HOSTNAME_FORMAT - # Set a custom hostname format for workers. This is a format string that should # include one %d field, which will be replaced with the number of the node. diff --git a/utils.sh b/utils.sh index 2acd1133e..4957f41da 100755 --- a/utils.sh +++ b/utils.sh @@ -468,19 +468,29 @@ function node_map_to_install_config_fencing_credentials() { credentials: EOF for ((idx=0; idx < NUM_MASTERS ; idx++)); do - # shellcheck disable=SC2059 - hostname="$(printf "$MASTER_HOSTNAME_FORMAT" ${idx})" - # IP V6 and DualStack will force FQDN hostname for the VMs, we need to update - # this here to correctly set the hostname for the fencing credentials. - if [[ $IP_STACK != 'v4' ]]; then - hostname="${hostname}.${CLUSTER_DOMAIN}" - fi username=$(node_val ${idx} "driver_info.username") password=$(node_val ${idx} "driver_info.password") address=$(node_val ${idx} "driver_info.address") + if [[ "${FENCING_CREDENTIAL_IDENTIFIER}" == "macAddress" ]]; then + identifier_key="macAddress" + identifier_value=$(node_val ${idx} "ports[0].address") + if [[ "${identifier_value}" == "null" || -z "${identifier_value}" ]]; then + printf "ports[0].address not found for node %d in %s\n" "${idx}" "${NODES_FILE}" >&2 + exit 1 + fi + else + # shellcheck disable=SC2059 + identifier_value="$(printf "$MASTER_HOSTNAME_FORMAT" ${idx})" + # IPv6 and DualStack force FQDN hostnames for VMs + if [[ $IP_STACK != 'v4' ]]; then + identifier_value="${identifier_value}.${CLUSTER_DOMAIN}" + fi + identifier_key="hostname" + fi + cat <