#!/usr/bin/env bash # Copyright (c) 2026 Sidero Labs, Inc. # # Use of this software is governed by the Business Source License # included in the LICENSE file. set -eoux pipefail # Omni is served from "https://my-instance.omni.localhost:8099" # Exposed services through workload proxying follow the pattern: "https://sngmph-my-instance.proxy-us.omni.localhost:8099/" # The TLS key and cert, hack/certs/localhost-key.pem and hack/certs/localhost.pem contain the SANs: # - localhost # - *.localhost # - my-instance.omni.localhost # - *.my-instance.omni.localhost # # Write "my-instance.omni.localhost" to /etc/hosts to avoid problems with the name resolution. echo "127.0.0.1 my-instance.omni.localhost" | tee -a /etc/hosts echo "127.0.0.1 omni.localhost" | tee -a /etc/hosts # Settings. LATEST_STABLE_OMNI=$(git tag -l --sort=-version:refname HEAD "v*" | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | head -n 1) export TALOS_VERSION=1.12.6 export KUBERNETES_VERSION=1.35.3 # To use in: # - Omni upgrade tests, to prevent Talos changes interfering with Omni changes # - Talos minor upgrade tests export STABLE_TALOS_VERSION=1.11.6 export ANOTHER_OMNI_VERSION="${ANOTHER_OMNI_VERSION:-$LATEST_STABLE_OMNI}" export ANOTHER_KUBERNETES_VERSION=1.34.6 export INTEGRATION_PREPARE_TEST_ARGS="${INTEGRATION_PREPARE_TEST_ARGS:-}" export ARTIFACTS=_out export JOIN_TOKEN=testonly export TEST_OUTPUTS_DIR=${GITHUB_WORKSPACE:-/tmp}/integration-test export SLEEP_AFTER_FAILURE=${SLEEP_AFTER_FAILURE:-0} export CI="${CI}" export BASE_URL=https://my-instance.omni.localhost:8099/ export VAULT_ADDR=http://127.0.0.1:8200 export VAULT_TOKEN=dev-o-token export AUTH_USERNAME="${AUTH0_TEST_USERNAME}" export AUTH_PASSWORD="${AUTH0_TEST_PASSWORD}" export AUTH0_CLIENT_ID="${AUTH0_CLIENT_ID}" export AUTH0_DOMAIN="${AUTH0_DOMAIN}" export OMNI_CONFIG="${TEST_OUTPUTS_DIR}/config.yaml" export MAX_USERS="${MAX_USERS:-0}" export MAX_SERVICE_ACCOUNTS="${MAX_SERVICE_ACCOUNTS:-0}" export MAX_REGISTERED_MACHINES="${MAX_REGISTERED_MACHINES:-0}" export REGISTRY_MIRROR_FLAGS=() export REGISTRY_MIRROR_CONFIG="" export IMPORTED_CLUSTER_ARGS=() RUN_DIR=$(pwd) export RUN_DIR # Determine the local IP SideroLink API will listen on LOCAL_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p') export LOCAL_IP mkdir -p "$TEST_OUTPUTS_DIR" export ENABLE_TALOS_PRERELEASE_VERSIONS=true VAULT_DOCKER_IMAGE=hashicorp/vault:1.18 MINIO_DOCKER_IMAGE=minio/minio export WIREGUARD_IP=$LOCAL_IP if [[ "${CI:-false}" == "true" ]]; then WIREGUARD_IP=172.20.0.1 fi # Prepare schematic with kernel args function prepare_kernel_args_schematic() { KERNEL_ARGS_SCHEMATIC=$(envsubst "${OMNI_CONFIG}" } PARTIAL_CONFIG_SERVER_PID=0 function prepare_partial_config() { export PARTIAL_CONFIG_PORT=12345 local partial_config_dir="${ARTIFACTS}/partial-config" mkdir -p "${partial_config_dir}" envsubst "${partial_config_dir}/config.yaml" # Start a simple HTTP server to serve the partial config python3 -m http.server "$PARTIAL_CONFIG_PORT" --bind "0.0.0.0" --directory "$partial_config_dir" >/dev/null 2>&1 & PARTIAL_CONFIG_SERVER_PID=$! # capture the PID to kill it in cleanup local schematic schematic=$(envsubst &2 return 1 fi ( IFS=, echo "${result[*]}" ) } function create_machines() { # args: name, count, cidr, secure_boot (true/false), uki (true/false), use_partial_config (true/false), talos_version, kernel_args_schematic_id, partial_config_schematic_id declare -A args for arg in "$@"; do key="${arg%%=*}" val="${arg#*=}" args["$key"]="$val" done local name="${args[name]}" local count="${args[count]}" local cidr="${args[cidr]}" local secure_boot="${args[secure_boot]}" local uki="${args[uki]}" local use_partial_config="${args[use_partial_config]}" local talos_version="${args[talos_version]}" local kernel_args_schematic_id="${args[kernel_args_schematic_id]}" local partial_config_schematic_id="${args[partial_config_schematic_id]}" local schematic_id="${kernel_args_schematic_id}" if [[ "${use_partial_config}" == "true" ]]; then schematic_id="${partial_config_schematic_id}" fi if [[ "${secure_boot}" == "true" && "${uki}" == "false" ]]; then echo "Error: secure_boot cannot be true when uki is false, as it always uses UKI" >&2 return 1 fi if [[ "${count}" -le 0 ]]; then return fi local non_masquerade_cidrs non_masquerade_cidrs=$(generate_non_masquerade_cidrs "${cidr}") local cluster_create_args=( "--provisioner=qemu" "--name=${name}" "--controlplanes=${count}" "--workers=0" "--mtu=1430" "--memory=3072" "--memory-workers=3072" "--cpus=3" "--cpus-workers=3" "--with-uuid-hostnames" "--cidr=${cidr}" "--no-masquerade-cidrs=${non_masquerade_cidrs}" "--skip-injecting-config" "--skip-injecting-extra-cmdline" "--wait=false" ) if [[ "${uki}" == "false" ]]; then cluster_create_args+=("--with-uefi=false") fi if [[ "${secure_boot}" == "true" ]]; then cluster_create_args+=( "--with-tpm2" "--disk-encryption-key-types=tpm" "--iso-path=https://factory.talos.dev/image/${schematic_id}/v${talos_version}/metal-amd64-secureboot.iso" ) else cluster_create_args+=("--iso-path=https://factory.talos.dev/image/${schematic_id}/v${talos_version}/metal-amd64.iso") fi "${ARTIFACTS}/talosctl" cluster create dev \ "${cluster_create_args[@]}" } function create_talos_cluster { # args: name, cp_count, wk_count, cidr, talos_version, skip_kubeconfig (true/false), allow_scheduling_on_control_planes (true/false) declare -A args for arg in "$@"; do key="${arg%%=*}" val="${arg#*=}" args["$key"]="$val" done local name="${args[name]}" local cp_count="${args[cp_count]}" local wk_count="${args[wk_count]:-0}" local cidr="${args[cidr]}" local talos_version="${args[talos_version]}" local skip_kubeconfig="${args[skip_kubeconfig]:-false}" local allow_scheduling_on_control_planes="${args[allow_scheduling_on_control_planes]:-false}" local non_masquerade_cidrs non_masquerade_cidrs=$(generate_non_masquerade_cidrs "${cidr}") local schematic_id schematic_id=$(prepare_talos_image) local cluster_create_args=( "--provisioner=qemu" "--name=${name}" "--controlplanes=${cp_count}" "--workers=${wk_count}" "--mtu=1430" "--memory=3072" "--memory-workers=3072" "--cpus=3" "--cpus-workers=3" "--with-uuid-hostnames" "--cidr=${cidr}" "--no-masquerade-cidrs=${non_masquerade_cidrs}" "--talosconfig=${TEST_OUTPUTS_DIR}/${name}/talosconfig" "--skip-kubeconfig=${skip_kubeconfig}" "--skip-injecting-extra-cmdline" "--with-apply-config" "--with-bootloader" "--kubernetes-version=${KUBERNETES_VERSION}" "--talos-version=${talos_version}" "--install-image=factory.talos.dev/metal-installer/${schematic_id}:v${talos_version}" "--iso-path=https://factory.talos.dev/image/${schematic_id}/v${talos_version}/metal-amd64.iso" ) if [[ "${allow_scheduling_on_control_planes}" == "true" ]]; then cluster_create_args+=("--config-patch-control-plane={\"cluster\":{\"allowSchedulingOnControlPlanes\":true}}") fi "${ARTIFACTS}/talosctl" cluster create dev \ "${cluster_create_args[@]}" \ "${REGISTRY_MIRROR_FLAGS[@]}" IMPORTED_CLUSTER_ARGS+=("--talos.config-path=${TEST_OUTPUTS_DIR}/${name}/talosconfig") IMPORTED_CLUSTER_ARGS+=("--talos.cluster-state-path=${HOME}/.talos/clusters/${name}/state.yaml") } # No cleanup here, as it runs in the CI as a container in a pod.