From 218f5e4e8d2c67431008135f2b0bf860f43921b4 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Thu, 30 Jul 2026 15:43:42 -0400 Subject: [PATCH 1/4] agent: add static networking support for ISO_NO_REGISTRY mode Add TUI automation to configure static IPs, hostnames, and DNS via nmtui for agent-based ISO_NO_REGISTRY installations. Creates a NEW NetworkManager connection (rather than editing the existing DHCP one) to ensure --copy-network is triggered by coreos-installer, preserving the static config across reboots. Co-Authored-By: Claude Opus 4.6 --- agent/06_agent_create_cluster.sh | 50 +++++- agent/common.sh | 8 + .../automate-no-registry-agent-tui-static.sh | 165 ++++++++++++++++++ agent/e2e/agent-tui/utils.sh | 12 +- config_example.sh | 8 + 5 files changed, 236 insertions(+), 7 deletions(-) create mode 100755 agent/e2e/agent-tui/automate-no-registry-agent-tui-static.sh diff --git a/agent/06_agent_create_cluster.sh b/agent/06_agent_create_cluster.sh index d44e0ce6e..ca067e54c 100755 --- a/agent/06_agent_create_cluster.sh +++ b/agent/06_agent_create_cluster.sh @@ -335,6 +335,44 @@ function automate_rendezvousIP_selection(){ done } +function automate_static_networking(){ + local node_type=$1 + local node_count=$2 + local base_ip=80 + + # Compute IP offset: masters start at 80, workers continue after masters, + # arbiters continue after workers + local offset=0 + case "$node_type" in + master) offset=0 ;; + worker) offset=$NUM_MASTERS ;; + arbiter) offset=$(( NUM_MASTERS + NUM_WORKERS )) ;; + esac + + local hostname_format + case "$node_type" in + master) hostname_format="$MASTER_HOSTNAME_FORMAT" ;; + worker) hostname_format="$WORKER_HOSTNAME_FORMAT" ;; + arbiter) hostname_format="$ARBITER_HOSTNAME_FORMAT" ;; + esac + + for (( n=0; n, +# , and at the bottom. +# +pressDown "Navigate to " 3 "$node_name" +pressEnter "Select ''" "" "$node_name" + +# +# Phase 2: Add a new Ethernet connection with static IP in nmtui +# Creating a NEW connection (rather than editing the existing one) ensures +# a new .nmconnection file is created with a birth time after agent-tui start. +# This triggers the --copy-network flag in coreos-installer, which preserves +# the static networking config into the installed system. +# +# nmtui opens with: "Edit a connection", "Activate a connection", +# "Set system hostname", "Radio" (4.16+), "Quit" +# +pressEnter "Select 'Edit a connection'" "" "$node_name" + +# Tab from connection list to button. +# Connection list is one widget; Tab goes to buttons: , , , +pressTab "Goto button" 1 "$node_name" +pressEnter "Select '' button" "" "$node_name" + +# New Connection type dialog: DSL is selected by default. +# Navigate down to Ethernet, then tab past to and confirm. +pressDown "Select Ethernet" 1 "$node_name" +pressTab "Goto button" 1 "$node_name" +pressTab "Goto button" 1 "$node_name" +pressEnter "Create new Ethernet connection" "" "$node_name" + +# Edit Connection form opens with cursor on Profile name field. +# Leave default profile name, tab to Device field and enter interface name. +pressTab "Goto Device field" 1 "$node_name" +pressKeys "Enter device name" "enp2s0" "$node_name" + +# Tab past ETHERNET , 802.1X SECURITY to IPv4 +pressTab "Goto IPv4 CONFIGURATION mode" 3 "$node_name" +pressEnter "Open IPv4 mode selector" "" "$node_name" +# Modes are: Disabled, Automatic, Link-Local, Manual +# From Automatic, Manual is two DOWNs +pressDown "Select Manual" 2 "$node_name" +pressEnter "Confirm Manual" "" "$node_name" + +# After selecting Manual, expand to reveal address fields. +# From the mode selector, is the next tab stop. +pressTab "Goto " 1 "$node_name" +pressEnter "Expand IPv4 details" "" "$node_name" + +# Tab to the Addresses field and enter the static IP. +pressTab "Goto Addresses " 1 "$node_name" +pressEnter "Activate Addresses field" "" "$node_name" +pressKeys "Enter static IP address" "${node_ip}/24" "$node_name" + +# Tab past and to Gateway field +pressTab "Goto Gateway field" 3 "$node_name" +pressKeys "Enter gateway" "192.168.111.1" "$node_name" + +# Tab to DNS servers field +pressTab "Goto DNS servers " 1 "$node_name" +pressEnter "Activate DNS servers field" "" "$node_name" +pressKeys "Enter DNS server" "192.168.111.1" "$node_name" + +# Tab to button +# From DNS servers, tab past: , , Search domains , +# Routing (No custom routes) , +# [ ] Never use this network for default route, +# [ ] Ignore automatically obtained routes, +# [ ] Ignore automatically obtained DNS parameters, +# [ ] Require IPv4 addressing for this connection, +# IPv6 CONFIGURATION , +# [X] Automatically connect, [X] Available to all users, +# , +pressTab "Goto button" 14 "$node_name" +pressEnter "Select '' button" "" "$node_name" + +# +# Phase 3: Activate the new static connection +# After OK we're back at the connection list. Go Back to main menu, +# then activate the new connection (which deactivates the old DHCP one). +# +pressTab "Goto button" 4 "$node_name" +pressEnter "Select '' button" "" "$node_name" +pressDown "Select 'Activate a connection'" 1 "$node_name" +pressEnter "Select 'Activate a connection' menu item" "" "$node_name" +# Activate a connection list layout: +# Ethernet (enp1s0) +# Wired connection 1 <- cursor starts here +# Ethernet (enp2s0) +# * Wired connection 2 <- active DHCP (DOWN 1) +# Ethernet connection 1 <- our new static (DOWN 2) +# Navigate down 2 to our new static connection and activate it. +# NM auto-deactivates the old DHCP connection on the same device. +pressDown "Select 'Ethernet connection 1'" 2 "$node_name" +pressEnter "Activate new static connection" "" "$node_name" +sleep 3 + +# +# Phase 4: Set system hostname in nmtui +# After "Activate a connection" Back, we're at the main menu. +# Menu items: "Edit a connection", "Activate a connection" (cursor here), +# "Set system hostname", "Radio" (4.16+), "Quit" +# +pressTab "Goto button" 2 "$node_name" +pressEnter "Select '' button" "" "$node_name" +pressDown "Select 'Set system hostname'" 1 "$node_name" +pressEnter "Select 'Set system hostname' menu item" "" "$node_name" + +# Clear any existing hostname and enter the new one. +# The dialog has: hostname text field, , . +# Press End to ensure cursor is at end of any existing text, +# then Ctrl+U to clear the line. +pressKey "Goto end of hostname field" KEY_END 1 "$node_name" +echo "Clear hostname field" +sudo virsh send-key "$node_name" KEY_LEFTCTRL KEY_U +sleep 1 +pressKeys "Enter hostname" "$node_hostname" "$node_name" + +# Tab past to and confirm +pressTab "Goto button" 2 "$node_name" +pressEnter "Confirm hostname" "" "$node_name" + +# +# Phase 5: Exit nmtui back to TUI first screen +# After setting hostname, we're back at the main menu on "Set system hostname". +# From here: "Radio" is 1 down, "Quit" is 2 down. +# +pressDown "Select Quit" 2 "$node_name" +pressEnter "Select 'Quit' menu item" "" "$node_name" +pressEsc "Esc from network tree view" 2 "$node_name" +sleep 3 + +# Wait for TUI checks to update after network reconfiguration +sleep 10 + +# +# Phase 6: Save rendezvous IP on the TUI first screen +# After returning from nmtui, cursor is back on the Rendezvous IP field. +# All nodes enter the same rendezvous IP. The rendezvous node recognizes +# the IP as its own; other nodes use it to find the rendezvous. +# +rendezvousIP=$(getRendezvousIP) +pressKeys "Entering rendezvous IP address" "$rendezvousIP" "$node_name" +# After typing in the text field, the first TAB is absorbed, so we need +# 2 TABs to reach : 1 absorbed + 1 to +pressTab "Goto " 2 "$node_name" +pressEnter "" "" "$node_name" +pressEnter "Save and Continue" "" "$node_name" diff --git a/agent/e2e/agent-tui/utils.sh b/agent/e2e/agent-tui/utils.sh index 960781c25..8d1d0e7a2 100644 --- a/agent/e2e/agent-tui/utils.sh +++ b/agent/e2e/agent-tui/utils.sh @@ -35,7 +35,7 @@ function pressKey() { echo "$msg" fi - local node_name=$4 + local node_name=${4:-} for i in $(seq 1 "$numReps"); do _pressKey "$keyCode" "$node_name" done @@ -46,7 +46,7 @@ function pressEnter() { } function pressTab() { - pressKey "$1" KEY_TAB "$2" + pressKey "$1" KEY_TAB "$2" "${3:-}" } function pressDown() { @@ -54,11 +54,11 @@ function pressDown() { } function pressBackspace() { - pressKey "$1" KEY_BACKSPACE "$2" + pressKey "$1" KEY_BACKSPACE "$2" "${3:-}" } function pressEsc() { - pressKey "$1" KEY_ESC "$2" + pressKey "$1" KEY_ESC "$2" "${3:-}" } function pressKeys(){ @@ -85,6 +85,10 @@ function pressKeys(){ c="DOT" elif [[ $c =~ [':'] ]]; then c="LEFTSHIFT KEY_SEMICOLON" + elif [[ $c =~ ['/'] ]]; then + c="SLASH" + elif [[ $c == '-' ]]; then + c="MINUS" fi local keyCode="KEY_"$c diff --git a/config_example.sh b/config_example.sh index f99617c35..614442838 100755 --- a/config_example.sh +++ b/config_example.sh @@ -994,6 +994,14 @@ set -x # As the size of the ISO increases in future, increase the expected ISO size accordingly. # export AGENT_OVE_ISO_SIZE=40 +# AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING controls whether the ISO_NO_REGISTRY +# test configures static networking on each node via the TUI (nmtui) instead of +# using DHCP. When set to 'true', the TUI automation script will navigate nmtui +# to configure a static IP on each node before proceeding with rendezvous IP +# selection. Static IPs are assigned starting at 192.168.111.80 (rendezvous node), +# incrementing by 1 for each additional node. +# Requires: AGENT_E2E_TEST_BOOT_MODE=ISO_NO_REGISTRY +# export AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING=true # Uncomment and set the following value to "true" to enable a test scenario # where the DNS is disabled on the hosts by setting its IP address to an incorrect value. From c7de956e175a08b4ec9906f8b3eb1617bd6b6cc7 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Fri, 14 Aug 2026 13:32:40 -0400 Subject: [PATCH 2/4] agent: address review feedback for static networking test - Activate the static networking scenario via the existing AGENT_TEST_CASES mechanism ('static_ip') instead of a dedicated config var, matching the 'bad_dns' approach. - Add an end-of-installation verification step that ssh's to each node at its assigned static IP and confirms the hostname, so the scenario is a complete test (configure via TUI, then verify). - Rename automate-no-registry-agent-tui-static.sh to test-static-ip.sh and add a header describing what the script does. - Centralize static IP assignment in staticIPForNode (agent/common.sh) and reuse it for rendezvous IP, configuration and verification. Co-Authored-By: Claude Opus 4.8 --- agent/06_agent_create_cluster.sh | 76 ++++++++++++++----- agent/common.sh | 29 +++++-- ...-agent-tui-static.sh => test-static-ip.sh} | 17 ++++- config_example.sh | 22 +++--- 4 files changed, 110 insertions(+), 34 deletions(-) rename agent/e2e/agent-tui/{automate-no-registry-agent-tui-static.sh => test-static-ip.sh} (89%) diff --git a/agent/06_agent_create_cluster.sh b/agent/06_agent_create_cluster.sh index ca067e54c..5a68481f8 100755 --- a/agent/06_agent_create_cluster.sh +++ b/agent/06_agent_create_cluster.sh @@ -335,44 +335,72 @@ function automate_rendezvousIP_selection(){ done } +function hostname_format_for_node_type(){ + case "$1" in + master) echo "$MASTER_HOSTNAME_FORMAT" ;; + worker) echo "$WORKER_HOSTNAME_FORMAT" ;; + arbiter) echo "$ARBITER_HOSTNAME_FORMAT" ;; + esac +} + +# Configuration step of the 'static_ip' test case: drive the agent TUI to +# assign a static IP and hostname to each node of the given type. The static +# IPs are derived from staticIPForNode (see agent/common.sh). function automate_static_networking(){ local node_type=$1 local node_count=$2 - local base_ip=80 - - # Compute IP offset: masters start at 80, workers continue after masters, - # arbiters continue after workers - local offset=0 - case "$node_type" in - master) offset=0 ;; - worker) offset=$NUM_MASTERS ;; - arbiter) offset=$(( NUM_MASTERS + NUM_WORKERS )) ;; - esac local hostname_format - case "$node_type" in - master) hostname_format="$MASTER_HOSTNAME_FORMAT" ;; - worker) hostname_format="$WORKER_HOSTNAME_FORMAT" ;; - arbiter) hostname_format="$ARBITER_HOSTNAME_FORMAT" ;; - esac + hostname_format="$(hostname_format_for_node_type "$node_type")" for (( n=0; n/dev/null); then + echo "ERROR: static_ip test case failed - could not ssh to ${node_type}-${n} at static IP ${node_ip}" + return 1 + fi + # Compare the short hostname (strip any domain suffix) + if [[ "${actual_hostname%%.*}" != "${expected_hostname}" ]]; then + echo "ERROR: static_ip test case failed - node at ${node_ip} has hostname '${actual_hostname}', expected '${expected_hostname}'" + return 1 + fi + echo "Verified ${node_type}-${n}: reachable at ${node_ip} with hostname ${expected_hostname}" + done +} + function check_assisted_install_UI(){ local rendezvousIP rendezvousIP=$(getRendezvousIP) @@ -876,7 +904,7 @@ case "${AGENT_E2E_TEST_BOOT_MODE}" in echo "aarch64: CDROM media ejected from all VMs" fi - if [[ "${AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING:-false}" == "true" ]]; then + if [[ "${AGENT_TEST_CASES:-}" =~ "static_ip" ]]; then automate_static_networking master "$NUM_MASTERS" automate_static_networking worker "$NUM_WORKERS" automate_static_networking arbiter "$NUM_ARBITERS" @@ -896,6 +924,18 @@ case "${AGENT_E2E_TEST_BOOT_MODE}" in pushd agent/isobuilder/ui_driven_cluster_installation RENDEZVOUS_IP=$rendezvousIP OCP_DIR=$ocp_dir_abs_path INGRESS_VIPS=$INGRESS_VIPS API_VIPS=$API_VIPS go run main.go popd + + # Verification step of the 'static_ip' test case: now that installation has + # completed, confirm each node came up with the static IP and hostname that + # were configured via the agent TUI. + if [[ "${AGENT_TEST_CASES:-}" =~ "static_ip" ]]; then + echo "Running test scenario: verify static IPs configured via agent-tui" + verify_static_networking master "$NUM_MASTERS" + verify_static_networking worker "$NUM_WORKERS" + verify_static_networking arbiter "$NUM_ARBITERS" + echo "Finished verifying static networking on all nodes" + fi + exit 0 ;; esac diff --git a/agent/common.sh b/agent/common.sh index 63f81846c..c4499bd7d 100644 --- a/agent/common.sh +++ b/agent/common.sh @@ -97,15 +97,32 @@ if [ "${AGENT_E2E_TEST_BOOT_MODE}" == "ISO_NO_REGISTRY" ] ; then if [[ -z "${NETWORKING_MODE}" ]]; then export NETWORKING_MODE="DHCP" fi - # When true, static IPs are configured via nmtui in the TUI - # instead of using DHCP addresses - export AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING=${AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING:-false} fi +# Static IP assignment for the 'static_ip' agent TUI test case. +# The rendezvous node (first master) is assigned .80 and each subsequent node +# increments by one, ordered masters, then workers, then arbiters. +export AGENT_STATIC_IP_PREFIX="192.168.111" +export AGENT_STATIC_IP_BASE=80 + +# staticIPForNode - echo the static IP assigned to a node. +function staticIPForNode() { + local node_type=$1 + local index=$2 + local offset=0 + case "${node_type}" in + master) offset=0 ;; + worker) offset=${NUM_MASTERS} ;; + arbiter) offset=$(( NUM_MASTERS + NUM_WORKERS )) ;; + esac + echo "${AGENT_STATIC_IP_PREFIX}.$(( AGENT_STATIC_IP_BASE + offset + index ))" +} + function getRendezvousIP() { - # When static networking is configured via TUI, the rendezvous IP is known - if [[ "${AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING:-false}" == "true" ]]; then - echo "192.168.111.80" + # For the 'static_ip' test case the rendezvous node is assigned a known + # static IP via the agent TUI, so return that directly. + if [[ "${AGENT_TEST_CASES:-}" =~ "static_ip" ]]; then + staticIPForNode master 0 return fi if [[ "${NODES_PLATFORM}" == "baremetal" ]]; then diff --git a/agent/e2e/agent-tui/automate-no-registry-agent-tui-static.sh b/agent/e2e/agent-tui/test-static-ip.sh similarity index 89% rename from agent/e2e/agent-tui/automate-no-registry-agent-tui-static.sh rename to agent/e2e/agent-tui/test-static-ip.sh index e50147e4b..ab243730f 100755 --- a/agent/e2e/agent-tui/automate-no-registry-agent-tui-static.sh +++ b/agent/e2e/agent-tui/test-static-ip.sh @@ -1,5 +1,20 @@ #!/bin/bash - +# +# test-static-ip.sh - first step of the 'static_ip' e2e test case. +# +# This script performs the *configuration* step of the static IP test: for a +# single node it drives the agent TUI (and nmtui within it) via "virsh send-key" +# to assign a static IPv4 address and hostname, then enters the rendezvous IP. +# It creates a NEW NetworkManager connection (rather than editing the existing +# DHCP one) so that coreos-installer's --copy-network preserves the static +# config into the installed system. +# +# The matching *verification* step runs at the end of the installation (see +# verify_static_networking in agent/06_agent_create_cluster.sh), which confirms +# each node is reachable at its assigned static IP with the expected hostname. +# +# Usage: test-static-ip.sh +# SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../../" && pwd )" source "$SCRIPTDIR/common.sh" source "$SCRIPTDIR/agent/common.sh" diff --git a/config_example.sh b/config_example.sh index 614442838..b552e5072 100755 --- a/config_example.sh +++ b/config_example.sh @@ -994,15 +994,6 @@ set -x # As the size of the ISO increases in future, increase the expected ISO size accordingly. # export AGENT_OVE_ISO_SIZE=40 -# AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING controls whether the ISO_NO_REGISTRY -# test configures static networking on each node via the TUI (nmtui) instead of -# using DHCP. When set to 'true', the TUI automation script will navigate nmtui -# to configure a static IP on each node before proceeding with rendezvous IP -# selection. Static IPs are assigned starting at 192.168.111.80 (rendezvous node), -# incrementing by 1 for each additional node. -# Requires: AGENT_E2E_TEST_BOOT_MODE=ISO_NO_REGISTRY -# export AGENT_ISO_NO_REGISTRY_STATIC_NETWORKING=true - # Uncomment and set the following value to "true" to enable a test scenario # where the DNS is disabled on the hosts by setting its IP address to an incorrect value. # Uncomment and set the following value to one or more test cases below. @@ -1019,6 +1010,19 @@ set -x # then the wait-for commands should timeout and fail. # This test case is only supported when IP_STACK=v4. # +# 2. 'static_ip' test case: +# Configures static networking on the nodes via the agent TUI (nmtui) instead of +# using DHCP, then verifies at the end of the installation that each node came up +# with the configured static IP and hostname. During the agent TUI automation a +# new NetworkManager connection is created on each node with a static IPv4 +# address and hostname; static IPs are assigned starting at 192.168.111.80 +# (rendezvous node), incrementing by 1 for each additional node. After the +# installation completes, the test ssh's to each node at its assigned static IP +# and confirms the hostname matches, failing the deployment if any node is not +# reachable at its static IP. +# This test case requires AGENT_E2E_TEST_BOOT_MODE=ISO_NO_REGISTRY and is only +# supported when IP_STACK=v4. +# # export AGENT_TEST_CASES='bad_dns' # Uncomment the following line to deploy the cluster using the appliance model From 2270615e281ff76c09e55eb1e28458008cb86cb8 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Fri, 14 Aug 2026 16:12:14 -0400 Subject: [PATCH 3/4] agent: retry ssh in static_ip verification for node reboot window verify_static_networking ran a single ssh attempt immediately after the UI reported the console URL as available, but at that point the nodes are still rebooting and finalizing (applying the static IP via coreos-installer --copy-network), so the static IP is not yet reachable and the check failed even though the node came up moments later. Retry the ssh check (up to ~20 min) until the node is reachable at its static IP before failing. Also drop the redundant `timeout 60` wrapper since the SSH command already sets ConnectTimeout. Co-Authored-By: Claude Opus 4.8 --- agent/06_agent_create_cluster.sh | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/agent/06_agent_create_cluster.sh b/agent/06_agent_create_cluster.sh index 5a68481f8..cff176508 100755 --- a/agent/06_agent_create_cluster.sh +++ b/agent/06_agent_create_cluster.sh @@ -387,8 +387,24 @@ function verify_static_networking(){ expected_hostname="$(printf "$hostname_format" "$n")" echo "Verifying ${node_type}-${n} is reachable at static IP ${node_ip} with hostname ${expected_hostname}" - local actual_hostname - if ! actual_hostname=$(timeout 60 ${SSH} "core@${node_ip}" hostname 2>/dev/null); then + + # The UI reports the console URL as soon as it is available, but the + # nodes are still rebooting and finalizing (applying the static IP via + # coreos-installer --copy-network) at that point, so the static IP is not + # immediately reachable. Retry until the node comes up before failing. + local actual_hostname="" + local retries=40 # up to ~20 min at 30s interval + local i + for (( i=1; i<=retries; i++ )); do + if actual_hostname=$(${SSH} "core@${node_ip}" hostname 2>/dev/null) && [[ -n "${actual_hostname}" ]]; then + break + fi + actual_hostname="" + echo "Waiting for ${node_type}-${n} to be reachable at ${node_ip} (attempt ${i}/${retries})" + sleep 30 + done + + if [[ -z "${actual_hostname}" ]]; then echo "ERROR: static_ip test case failed - could not ssh to ${node_type}-${n} at static IP ${node_ip}" return 1 fi From 61f772d24c91f8e4ae85e785cffa3bab493153d9 Mon Sep 17 00:00:00 2001 From: Bob Fournier Date: Fri, 14 Aug 2026 19:17:21 -0400 Subject: [PATCH 4/4] agent: shorten static_ip verification retry budget to ~5 min Nodes are reachable on the first attempt once the console URL is available, so the ~20 min retry budget was excessive. Reduce to ~5 min (10 attempts at 30s), which still leaves headroom for a slightly slower node. Co-Authored-By: Claude Opus 4.8 --- agent/06_agent_create_cluster.sh | 35 ++++--- agent/e2e/agent-tui/test-static-ip.sh | 137 +++++++++----------------- 2 files changed, 70 insertions(+), 102 deletions(-) diff --git a/agent/06_agent_create_cluster.sh b/agent/06_agent_create_cluster.sh index cff176508..9aba601c5 100755 --- a/agent/06_agent_create_cluster.sh +++ b/agent/06_agent_create_cluster.sh @@ -346,7 +346,7 @@ function hostname_format_for_node_type(){ # Configuration step of the 'static_ip' test case: drive the agent TUI to # assign a static IP and hostname to each node of the given type. The static # IPs are derived from staticIPForNode (see agent/common.sh). -function automate_static_networking(){ +function test_case_do_static_ip(){ local node_type=$1 local node_count=$2 @@ -373,7 +373,7 @@ function automate_static_networking(){ # Verification step of the 'static_ip' test case: confirm each node of the given # type is reachable at the static IP it was assigned via the agent TUI, and that # its hostname was applied. Exits non-zero if any node fails verification. -function verify_static_networking(){ +function test_case_verify_static_ip(){ local node_type=$1 local node_count=$2 @@ -393,7 +393,7 @@ function verify_static_networking(){ # coreos-installer --copy-network) at that point, so the static IP is not # immediately reachable. Retry until the node comes up before failing. local actual_hostname="" - local retries=40 # up to ~20 min at 30s interval + local retries=10 # up to ~5 min at 30s interval local i for (( i=1; i<=retries; i++ )); do if actual_hostname=$(${SSH} "core@${node_ip}" hostname 2>/dev/null) && [[ -n "${actual_hostname}" ]]; then @@ -636,8 +636,11 @@ function mce_complete_deployment() { mce_apply_postinstallation_manifests "${mceManifests}" } -function run_agent_test_cases() { - if [[ $AGENT_TEST_CASES =~ "bad_dns" ]]; then +# Configuration step of the 'bad_dns' test case: wait for the nodes to reach the +# agent-tui check screen (failing because of the bad DNS record injected into +# agent-config.yaml), then fix the DNS on master-0 via agent-tui so the +# installation can proceed. +function test_case_do_bad_dns() { # wait 5 minutes for VMs to load and arrive at agent-tui check screen echo "Running test scenario: bad DNS record(s) in agent-config.yaml" echo "Waiting for 5 mins to arrive at agent-tui check screen" @@ -659,6 +662,11 @@ function run_agent_test_cases() { sudo virsh screenshot "$name" "${OCP_DIR}/${name}_console_screenshot_after_dns_fix.ppm" echo "Finished fixing DNS through agent-tui" +} + +function run_agent_test_cases() { + if [[ $AGENT_TEST_CASES =~ "bad_dns" ]]; then + test_case_do_bad_dns fi } @@ -921,9 +929,14 @@ case "${AGENT_E2E_TEST_BOOT_MODE}" in fi if [[ "${AGENT_TEST_CASES:-}" =~ "static_ip" ]]; then - automate_static_networking master "$NUM_MASTERS" - automate_static_networking worker "$NUM_WORKERS" - automate_static_networking arbiter "$NUM_ARBITERS" + # The static_ip test case configures IPv4 static addresses only. + if [[ "${IP_STACK}" != "v4" ]]; then + echo "ERROR: the 'static_ip' test case is only supported with IP_STACK=v4 (got '${IP_STACK}')" + exit 1 + fi + test_case_do_static_ip master "$NUM_MASTERS" + test_case_do_static_ip worker "$NUM_WORKERS" + test_case_do_static_ip arbiter "$NUM_ARBITERS" else automate_rendezvousIP_selection master "$NUM_MASTERS" automate_rendezvousIP_selection worker "$NUM_WORKERS" @@ -946,9 +959,9 @@ case "${AGENT_E2E_TEST_BOOT_MODE}" in # were configured via the agent TUI. if [[ "${AGENT_TEST_CASES:-}" =~ "static_ip" ]]; then echo "Running test scenario: verify static IPs configured via agent-tui" - verify_static_networking master "$NUM_MASTERS" - verify_static_networking worker "$NUM_WORKERS" - verify_static_networking arbiter "$NUM_ARBITERS" + test_case_verify_static_ip master "$NUM_MASTERS" + test_case_verify_static_ip worker "$NUM_WORKERS" + test_case_verify_static_ip arbiter "$NUM_ARBITERS" echo "Finished verifying static networking on all nodes" fi diff --git a/agent/e2e/agent-tui/test-static-ip.sh b/agent/e2e/agent-tui/test-static-ip.sh index ab243730f..bc508e1a8 100755 --- a/agent/e2e/agent-tui/test-static-ip.sh +++ b/agent/e2e/agent-tui/test-static-ip.sh @@ -1,17 +1,23 @@ #!/bin/bash # -# test-static-ip.sh - first step of the 'static_ip' e2e test case. -# -# This script performs the *configuration* step of the static IP test: for a -# single node it drives the agent TUI (and nmtui within it) via "virsh send-key" -# to assign a static IPv4 address and hostname, then enters the rendezvous IP. -# It creates a NEW NetworkManager connection (rather than editing the existing -# DHCP one) so that coreos-installer's --copy-network preserves the static -# config into the installed system. -# -# The matching *verification* step runs at the end of the installation (see -# verify_static_networking in agent/06_agent_create_cluster.sh), which confirms -# each node is reachable at its assigned static IP with the expected hostname. +# test-static-ip.sh - configuration step of the 'static_ip' e2e test case. +# +# Drives the agent TUI (and nmtui within it) via "virsh send-key" to assign a +# static IPv4 address and hostname to a single node, creating a NEW +# NetworkManager connection so coreos-installer's --copy-network preserves the +# static config into the installed system. The matching verification step runs +# at the end of the install (see test_case_verify_static_ip in +# agent/06_agent_create_cluster.sh). +# +# Example configuration applied to a node: +# ┌───────────────┬─────────────────┐ +# │ Interface │ enp2s0 │ +# │ IP address │ /24 │ +# │ Gateway │ 192.168.111.1 │ +# │ DNS server │ 192.168.111.1 │ +# │ Hostname │ │ +# │ Rendezvous IP │ │ +# └───────────────┴─────────────────┘ # # Usage: test-static-ip.sh # @@ -26,155 +32,104 @@ node_name=$1 node_ip=$2 node_hostname=$3 -# The following commands send key presses through "virsh send-key" to interact -# with agent-tui and nmtui to configure static networking. +# All interaction below is via "virsh send-key" into agent-tui and nmtui. -# -# Phase 1: Navigate from TUI first screen to nmtui -# The TUI first screen has: Rendezvous IP field, , -# , and at the bottom. -# +# Phase 1: from the TUI first screen navigate to . pressDown "Navigate to " 3 "$node_name" pressEnter "Select ''" "" "$node_name" -# -# Phase 2: Add a new Ethernet connection with static IP in nmtui -# Creating a NEW connection (rather than editing the existing one) ensures -# a new .nmconnection file is created with a birth time after agent-tui start. -# This triggers the --copy-network flag in coreos-installer, which preserves -# the static networking config into the installed system. -# -# nmtui opens with: "Edit a connection", "Activate a connection", -# "Set system hostname", "Radio" (4.16+), "Quit" -# +# Phase 2: add a new Ethernet connection with a static IP in nmtui. A NEW +# connection (not editing the existing one) gives a .nmconnection file with a +# birth time after agent-tui start, which triggers coreos-installer --copy-network. pressEnter "Select 'Edit a connection'" "" "$node_name" -# Tab from connection list to button. -# Connection list is one widget; Tab goes to buttons: , , , +# Tab from the connection list to the button. pressTab "Goto button" 1 "$node_name" pressEnter "Select '' button" "" "$node_name" -# New Connection type dialog: DSL is selected by default. -# Navigate down to Ethernet, then tab past to and confirm. +# Connection type dialog: select Ethernet, then tab to and confirm. pressDown "Select Ethernet" 1 "$node_name" pressTab "Goto button" 1 "$node_name" pressTab "Goto button" 1 "$node_name" pressEnter "Create new Ethernet connection" "" "$node_name" -# Edit Connection form opens with cursor on Profile name field. -# Leave default profile name, tab to Device field and enter interface name. +# Leave default profile name, tab to the Device field and enter the interface. pressTab "Goto Device field" 1 "$node_name" pressKeys "Enter device name" "enp2s0" "$node_name" -# Tab past ETHERNET , 802.1X SECURITY to IPv4 +# Tab past ETHERNET/802.1X to the IPv4 CONFIGURATION mode. pressTab "Goto IPv4 CONFIGURATION mode" 3 "$node_name" pressEnter "Open IPv4 mode selector" "" "$node_name" -# Modes are: Disabled, Automatic, Link-Local, Manual -# From Automatic, Manual is two DOWNs +# From Automatic, Manual is two DOWNs (Disabled, Automatic, Link-Local, Manual). pressDown "Select Manual" 2 "$node_name" pressEnter "Confirm Manual" "" "$node_name" -# After selecting Manual, expand to reveal address fields. -# From the mode selector, is the next tab stop. +# Expand to reveal the address fields. pressTab "Goto " 1 "$node_name" pressEnter "Expand IPv4 details" "" "$node_name" -# Tab to the Addresses field and enter the static IP. +# Enter the static IP in the Addresses field. pressTab "Goto Addresses " 1 "$node_name" pressEnter "Activate Addresses field" "" "$node_name" pressKeys "Enter static IP address" "${node_ip}/24" "$node_name" -# Tab past and to Gateway field +# Tab past / to the Gateway field. pressTab "Goto Gateway field" 3 "$node_name" pressKeys "Enter gateway" "192.168.111.1" "$node_name" -# Tab to DNS servers field +# Enter the DNS server. pressTab "Goto DNS servers " 1 "$node_name" pressEnter "Activate DNS servers field" "" "$node_name" pressKeys "Enter DNS server" "192.168.111.1" "$node_name" -# Tab to button -# From DNS servers, tab past: , , Search domains , -# Routing (No custom routes) , -# [ ] Never use this network for default route, -# [ ] Ignore automatically obtained routes, -# [ ] Ignore automatically obtained DNS parameters, -# [ ] Require IPv4 addressing for this connection, -# IPv6 CONFIGURATION , -# [X] Automatically connect, [X] Available to all users, -# , +# Tab past the remaining DNS/search/routing/IPv6 options and checkboxes to +# (14 stops: , , Search domains, Routing, 4 route/DNS checkboxes, +# IPv6 /, 2 connect checkboxes, , ). pressTab "Goto button" 14 "$node_name" pressEnter "Select '' button" "" "$node_name" -# -# Phase 3: Activate the new static connection -# After OK we're back at the connection list. Go Back to main menu, -# then activate the new connection (which deactivates the old DHCP one). -# +# Phase 3: back at the connection list, go Back to the main menu and activate +# the new static connection (NM auto-deactivates the old DHCP one). pressTab "Goto button" 4 "$node_name" pressEnter "Select '' button" "" "$node_name" pressDown "Select 'Activate a connection'" 1 "$node_name" pressEnter "Select 'Activate a connection' menu item" "" "$node_name" -# Activate a connection list layout: -# Ethernet (enp1s0) -# Wired connection 1 <- cursor starts here -# Ethernet (enp2s0) -# * Wired connection 2 <- active DHCP (DOWN 1) -# Ethernet connection 1 <- our new static (DOWN 2) -# Navigate down 2 to our new static connection and activate it. -# NM auto-deactivates the old DHCP connection on the same device. +# Our new static connection is 2 DOWN (past the active '* Wired connection 2'). pressDown "Select 'Ethernet connection 1'" 2 "$node_name" pressEnter "Activate new static connection" "" "$node_name" sleep 3 -# -# Phase 4: Set system hostname in nmtui -# After "Activate a connection" Back, we're at the main menu. -# Menu items: "Edit a connection", "Activate a connection" (cursor here), -# "Set system hostname", "Radio" (4.16+), "Quit" -# +# Phase 4: set the system hostname in nmtui. pressTab "Goto button" 2 "$node_name" pressEnter "Select '' button" "" "$node_name" pressDown "Select 'Set system hostname'" 1 "$node_name" pressEnter "Select 'Set system hostname' menu item" "" "$node_name" -# Clear any existing hostname and enter the new one. -# The dialog has: hostname text field, , . -# Press End to ensure cursor is at end of any existing text, -# then Ctrl+U to clear the line. +# Clear any existing hostname (End then Ctrl+U) and enter the new one. pressKey "Goto end of hostname field" KEY_END 1 "$node_name" echo "Clear hostname field" sudo virsh send-key "$node_name" KEY_LEFTCTRL KEY_U sleep 1 pressKeys "Enter hostname" "$node_hostname" "$node_name" -# Tab past to and confirm +# Tab past to and confirm. pressTab "Goto button" 2 "$node_name" pressEnter "Confirm hostname" "" "$node_name" -# -# Phase 5: Exit nmtui back to TUI first screen -# After setting hostname, we're back at the main menu on "Set system hostname". -# From here: "Radio" is 1 down, "Quit" is 2 down. -# +# Phase 5: exit nmtui back to the TUI first screen (Quit is 2 DOWN from hostname). pressDown "Select Quit" 2 "$node_name" pressEnter "Select 'Quit' menu item" "" "$node_name" pressEsc "Esc from network tree view" 2 "$node_name" sleep 3 -# Wait for TUI checks to update after network reconfiguration +# Wait for TUI checks to update after network reconfiguration. sleep 10 -# -# Phase 6: Save rendezvous IP on the TUI first screen -# After returning from nmtui, cursor is back on the Rendezvous IP field. -# All nodes enter the same rendezvous IP. The rendezvous node recognizes -# the IP as its own; other nodes use it to find the rendezvous. -# +# Phase 6: save the rendezvous IP on the TUI first screen. All nodes enter the +# same rendezvous IP; the rendezvous node recognizes it as its own. rendezvousIP=$(getRendezvousIP) pressKeys "Entering rendezvous IP address" "$rendezvousIP" "$node_name" -# After typing in the text field, the first TAB is absorbed, so we need -# 2 TABs to reach : 1 absorbed + 1 to +# After typing, the first TAB is absorbed, so 2 TABs reach . pressTab "Goto " 2 "$node_name" pressEnter "" "" "$node_name" pressEnter "Save and Continue" "" "$node_name"