diff --git a/agent/06_agent_create_cluster.sh b/agent/06_agent_create_cluster.sh index d44e0ce6e..7fd727043 100755 --- a/agent/06_agent_create_cluster.sh +++ b/agent/06_agent_create_cluster.sh @@ -808,20 +808,28 @@ case "${AGENT_E2E_TEST_BOOT_MODE}" in # Run a script from agent-installer-utils which internally uses openshift-appliance asset_dir=$SCRIPTDIR/$OCP_DIR/iso_builder mkdir -p "${asset_dir}" - create_agent_iso_no_registry "${asset_dir}" - assert_agent_no_registry_iso_size + if [[ -n "${AGENT_OVE_ISO_SOURCE}" ]]; then + # A pre-built OVE ISO was provided - fetch it instead of building one locally. + fetch_agent_iso_no_registry "${asset_dir}" - if [[ "$AGENT_CLEANUP_ISO_BUILDER_CACHE_LOCAL_DEV" == "true" ]]; then - # reclaim disk space by deleting unwanted cache, other files - cleanup_diskspace_agent_iso_noregistry "${asset_dir}" - fi + assert_agent_no_registry_iso_size + else + create_agent_iso_no_registry "${asset_dir}" + + assert_agent_no_registry_iso_size - # Clean up registry data to save disk space after ISO is created - if [[ "${MIRROR_IMAGES}" == "true" ]]; then - echo "Cleaning up registry data at ${REGISTRY_DIR} to save disk space" - sudo rm -rf "${REGISTRY_DIR}/data" - echo "Registry data cleanup complete" + if [[ "$AGENT_CLEANUP_ISO_BUILDER_CACHE_LOCAL_DEV" == "true" ]]; then + # reclaim disk space by deleting unwanted cache, other files + cleanup_diskspace_agent_iso_noregistry "${asset_dir}" + fi + + # Clean up registry data to save disk space after ISO is created + if [[ "${MIRROR_IMAGES}" == "true" ]]; then + echo "Cleaning up registry data at ${REGISTRY_DIR} to save disk space" + sudo rm -rf "${REGISTRY_DIR}/data" + echo "Registry data cleanup complete" + fi fi attach_agent_iso_no_registry master "$NUM_MASTERS" diff --git a/agent/common.sh b/agent/common.sh index dbea26bdc..df27d1285 100644 --- a/agent/common.sh +++ b/agent/common.sh @@ -18,6 +18,16 @@ export AGENT_MINIMAL_ISO=${AGENT_MINIMAL_ISO:-"false"} # OVE ISO build method: "script" uses build-ove-image.sh, "container" uses Dockerfile-based build export AGENT_ISO_NO_REGISTRY_BUILD_METHOD=${AGENT_ISO_NO_REGISTRY_BUILD_METHOD:-"script"} +# Optional: use a pre-built OVE ISO instead of building one locally (ISO_NO_REGISTRY mode). +# When set, the ISO build (create_agent_iso_no_registry) is skipped and the ISO is obtained +# from this source. Accepts one of: +# - a quay.io/redhat-user-workloads/... container image ref (ISO extracted from the image) +# - a local path/filename to an already-downloaded ISO +# Direct https downloads (mirror.openshift.com / Red Hat content-gateway) are not supported +# because they require Red Hat SSO authentication; download those ISOs separately and pass +# the resulting local file path here. +export AGENT_OVE_ISO_SOURCE=${AGENT_OVE_ISO_SOURCE:-""} + export BOND_CONFIG=${BOND_CONFIG:-"none"} export ISCSI_NETWORK="iscsi" diff --git a/agent/iso_no_registry.sh b/agent/iso_no_registry.sh index 276a7ba37..9a7ac1855 100755 --- a/agent/iso_no_registry.sh +++ b/agent/iso_no_registry.sh @@ -57,6 +57,104 @@ function build_ove_iso_container() { mv "./output-iso/${iso_name}" "${asset_dir}" } +# Inject the local SSH public key into a pre-built OVE ISO's embedded live ignition. +# +# Locally-built ISOs (build-ove-image.sh --ssh-key-file) but a pre-built ISO +# fetched via AGENT_OVE_ISO_SOURCE may not. This adds the key to the 'core' user. +# Note that if the pre-built ISO already has the ssh key this will not create +# a duplicate but it will overwrite the current key. +function inject_ssh_key_into_ove_iso() { + local iso="${1}" + local dir base tmp ssh_pub coreos_installer + + if [[ ! -f "${SSH_KEY_FILE}" ]]; then + echo "Warning: SSH_KEY_FILE (${SSH_KEY_FILE}) not found; skipping SSH key injection." >&2 + return 0 + fi + + dir=$(dirname "${iso}") + base=$(basename "${iso}") + ssh_pub=$(cat "${SSH_KEY_FILE}") + tmp=$(mktemp -d) + + echo "Injecting SSH key from ${SSH_KEY_FILE} into ${iso}" + + coreos_installer=(sudo podman run --privileged --rm -v /run/udev:/run/udev + -v "${dir}:/data" -v "${tmp}:/cfg" -w /data quay.io/coreos/coreos-installer:release) + + # Extract the ISO's existing embedded live ignition so we can preserve it. + if ! "${coreos_installer[@]}" iso ignition show "/data/${base}" > "${tmp}/iso.ign" 2>/dev/null \ + || ! jq -e . "${tmp}/iso.ign" >/dev/null 2>&1; then + # No embedded ignition (or unreadable) - start from a minimal 3.2.0 config. + echo '{"ignition":{"version":"3.2.0"}}' > "${tmp}/iso.ign" + fi + + # Append our key to the 'core' user (create it if absent), keeping any existing keys. + jq --arg key "${ssh_pub}" ' + .passwd = (.passwd // {}) | + .passwd.users = (.passwd.users // []) | + if any(.passwd.users[]; .name == "core") + then .passwd.users |= map( + if .name == "core" + then .sshAuthorizedKeys = ((.sshAuthorizedKeys // []) + [$key] | unique) + else . end) + else .passwd.users += [{"name": "core", "sshAuthorizedKeys": [$key]}] + end + ' "${tmp}/iso.ign" > "${tmp}/iso-ssh.ign" + + # Re-embed the augmented ignition in place (-f overwrites the existing one). + "${coreos_installer[@]}" iso ignition embed -f -i "/cfg/iso-ssh.ign" "/data/${base}" + + rm -rf "${tmp}" + echo "SSH key injected into ${iso}" +} + +# Obtain a pre-built OVE ISO from AGENT_OVE_ISO_SOURCE instead of building it locally. +# The resulting ISO is placed at "${asset_dir}/agent-ove.${ARCH}.iso", where +# get_agent_iso_no_registry looks for it. The source may be: +# - a quay.io/redhat-user-workloads/... container image (ISO extracted from the image) +# - a local path/filename to an already-downloaded ISO +# +# Direct https downloads (e.g. mirror.openshift.com / the Red Hat content-gateway) are +# not supported here because they require Red Hat SSO authentication. Download such ISOs +# separately and pass the resulting local file path as AGENT_OVE_ISO_SOURCE. +function fetch_agent_iso_no_registry() { + local asset_dir=${1} + local dest="${asset_dir}/agent-ove.${ARCH}.iso" + + mkdir -p "${asset_dir}" + + if [[ "${AGENT_OVE_ISO_SOURCE}" == *"redhat-user-workloads"* ]]; then + # Intermediate build published as a container image - extract the ISO from it. + echo "Extracting OVE ISO from container image ${AGENT_OVE_ISO_SOURCE}" + local id + id=$(sudo podman create --arch amd64 "${AGENT_OVE_ISO_SOURCE}") + sudo podman cp "${id}:/agent-ove.x86_64.iso" "${dest}" + sudo podman rm "${id}" + elif [[ "${AGENT_OVE_ISO_SOURCE}" =~ ^https?:// ]]; then + # Direct URLs are not supported - they require Red Hat SSO authentication. + echo "Error: direct URL downloads are not supported for AGENT_OVE_ISO_SOURCE." >&2 + echo " The content-gateway/mirror URLs require Red Hat SSO authentication." >&2 + echo " Download the ISO separately and set AGENT_OVE_ISO_SOURCE to the local file path," >&2 + echo " or use a quay.io/redhat-user-workloads/... container image reference." >&2 + exit 1 + else + # Treat as a local path/filename to an already-downloaded ISO. + echo "Using local OVE ISO ${AGENT_OVE_ISO_SOURCE}" + if [[ ! -f "${AGENT_OVE_ISO_SOURCE}" ]]; then + echo "Error: OVE ISO file not found: ${AGENT_OVE_ISO_SOURCE}" >&2 + exit 1 + fi + cp "${AGENT_OVE_ISO_SOURCE}" "${dest}" + fi + + # A pre-built ISO has no SSH key baked in - add ours so we can ssh into the + # live/bootstrap OVE environment (and the installed nodes once it propagates). + inject_ssh_key_into_ove_iso "${dest}" + + echo "OVE ISO available at ${dest}" +} + # Create agent ISO without registry (OVE ISO) function create_agent_iso_no_registry() { local asset_dir=${1} diff --git a/agent/isobuilder/ui_driven_cluster_installation/main.go b/agent/isobuilder/ui_driven_cluster_installation/main.go index a7f344429..2df329abb 100644 --- a/agent/isobuilder/ui_driven_cluster_installation/main.go +++ b/agent/isobuilder/ui_driven_cluster_installation/main.go @@ -612,7 +612,29 @@ func networkingDetails(page *rod.Page, path string) error { } } - page.MustElement("#form-input-sshPublicKey-field").MustInput(sshPublicKey) + // The "Host SSH Public Key" section offers a "Use the same host discovery SSH key" + // checkbox. When it is checked - e.g. the boot ISO already provided a host discovery + // SSH key (as with a pre-built OVE ISO) - the manual key text field is not rendered, + // so unconditionally waiting for it would hang forever. Only enter the key if the + // field is actually present and empty; otherwise the cluster already has an SSH key. + sshField, sshErr := page.Timeout(15 * time.Second).Element("#form-input-sshPublicKey-field") + if sshErr != nil || sshField == nil { + logrus.Info("SSH public key field not present (using host discovery SSH key); skipping input") + } else { + sshField.MustScrollIntoView() + existing := strings.TrimSpace(sshField.MustProperty("value").String()) + if existing == "" { + if inputErr := rod.Try(func() { + sshField.Timeout(30 * time.Second).MustWaitInteractable().MustInput(sshPublicKey) + }); inputErr != nil { + _ = saveFullPageScreenshot(page, timestampedPath(path, "ssh-input-failed")) + logrus.Warnf("skipping SSH key input (field not interactable): %v", inputErr) + } + } else { + logrus.Info("SSH public key already populated; skipping input") + } + } + page.MustElement(`button[name="next"]`).MustWaitEnabled() err = saveFullPageScreenshot(page, timestampedPath(path, "end")) diff --git a/config_example.sh b/config_example.sh index ef41c477a..62275159d 100755 --- a/config_example.sh +++ b/config_example.sh @@ -1015,6 +1015,19 @@ set -x # As the size of the ISO increases in future, increase the expected ISO size accordingly. # export AGENT_OVE_ISO_SIZE=40 +# AGENT_OVE_ISO_SOURCE lets you use a pre-built OVE ISO instead of building one locally when +# AGENT_E2E_TEST_BOOT_MODE is set to ISO_NO_REGISTRY. When set, the local ISO build +# (create_agent_iso_no_registry) is skipped and the ISO is obtained from this source. +# Accepts one of: +# - a quay.io/redhat-user-workloads/... container image ref; the ISO is extracted from the image via: +# id=$(sudo podman create --arch amd64 ) && sudo podman cp "$id:/agent-ove.x86_64.iso" . +# - a local path/filename to an already-downloaded ISO +# Direct https URLs (e.g. mirror.openshift.com / the Red Hat content-gateway) are not supported +# here because they require Red Hat SSO authentication. Download such ISOs separately (via a +# browser logged in to Red Hat SSO) and pass the resulting local file path. +# export AGENT_OVE_ISO_SOURCE=/path/to/agent-ove.x86_64.iso +# export AGENT_OVE_ISO_SOURCE=quay.io/redhat-user-workloads/@sha256: + # 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.