From 3bea3baa8891c97ab3f0c2e3d63f47bac70919a0 Mon Sep 17 00:00:00 2001 From: David Schroeder Date: Tue, 28 Jul 2026 22:09:13 -0500 Subject: [PATCH] update --- README.md | 18 ++++++++---- defaults.inc | 2 +- inc/deploy-iso-nfs-lxc.sh | 35 ++++++++++++++--------- inc/deploy-pulse-lxc.sh | 44 +++++++++++++++++++++++----- inc/fleet.inc | 49 ++++++++++++++++++++------------ inc/virtio-helpers.inc | 14 +++++++++ proxmenu-scripts.sh | 35 +++++++++++++++++++++-- tests/test-fleet.sh | 60 +++++++++++++++++++++++++++++++++++++-- tests/test-git-update.sh | 3 ++ tests/test-iso-nfs.sh | 12 ++++++++ tests/test-pulse.sh | 4 +++ tests/test-virtio.sh | 9 ++++++ 12 files changed, 236 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index d8560c4..ba816d4 100644 --- a/README.md +++ b/README.md @@ -177,12 +177,18 @@ a default company URL. V2 creates a random installation UUID and 256-bit credential in `/var/lib/ta-proxmenu/identity.env`. The directory is mode `0700` and the file -is mode `0600`. On each interactive launch, TA-ProxMenu makes best-effort HTTPS -calls to the configured broker to record the hostname, installation/upgrade -state, start and completion status, duration, TA-ProxMenu and Git versions, -PVE/OS/kernel versions, architecture, and whether the host is clustered. No -background service is installed, and broker availability never prevents the -menu from running. +is mode `0600`. The first successful launch enrolls the host with the broker. +Later launches make one best-effort HTTPS call on completion or failure to +record the hostname, duration, result, TA-ProxMenu and Git versions, +PVE/OS/kernel versions, architecture, and whether the host is clustered. A +failed event schedules re-enrollment on the next invocation instead of adding +another retry to the current run. No background service is installed, and +broker availability never prevents the menu from running. + +Automatic Git update checks and the stable VirtIO release lookup are cached for +24 hours. Their explicit **Check again** and **Refresh** actions bypass the +cache. Installer, package-repository, and vendor download traffic occurs only +after a technician selects the corresponding action. The hostname is treated as a limited operational identifier. The registry does not send machine IDs, MAC addresses, usernames, VM/container inventory, diff --git a/defaults.inc b/defaults.inc index bbd56cc..c32651b 100755 --- a/defaults.inc +++ b/defaults.inc @@ -3,7 +3,7 @@ action="${1:-}" FOLDER='/opt/idssys/ta-proxmenu' -VERS='2026.7.28-8' +VERS='2026.7.28-9' noupdate=' ' diff --git a/inc/deploy-iso-nfs-lxc.sh b/inc/deploy-iso-nfs-lxc.sh index 189ee3a..7634d3e 100644 --- a/inc/deploy-iso-nfs-lxc.sh +++ b/inc/deploy-iso-nfs-lxc.sh @@ -49,6 +49,15 @@ TAPM_ISO_NFS_FAIL() { return 1 } +TAPM_ISO_NFS_LOCAL_TEMPLATE() { + local storage="$1" + + pveam list "$storage" 2>/dev/null | + awk 'NR > 1 && $1 ~ /:vztmpl\/debian-(13|12)-standard_/ { print $1 }' | + sort -V | + tail -1 +} + TAPM_ISO_NFS_SELECT_STORAGE() { local variable="$1" local label="$2" @@ -198,19 +207,19 @@ TAPM_DEPLOY_ISO_NFS_LXC() { } echo -e "\n${idsCL[LightCyan]}Locating a Debian container template...${idsCL[Default]}" - pveam update || { TAPM_ISO_NFS_FAIL "Could not refresh the template catalog."; return 1; } - template_name="$( - pveam available --section system | - awk '$2 ~ /^debian-(13|12)-standard_/ { print $2 }' | - sort -V | - tail -1 - )" - [[ -n "$template_name" ]] || - { TAPM_ISO_NFS_FAIL "No supported Debian 12/13 standard template was found."; return 1; } - template_path="${template_storage}:vztmpl/${template_name}" - if ! pveam list "$template_storage" 2>/dev/null | - awk 'NR > 1 { print $1 }' | - grep -Fxq -- "$template_path"; then + template_path="$(TAPM_ISO_NFS_LOCAL_TEMPLATE "$template_storage")" + if [[ -z "$template_path" ]]; then + pveam update || + { TAPM_ISO_NFS_FAIL "Could not refresh the template catalog."; return 1; } + template_name="$( + pveam available --section system | + awk '$2 ~ /^debian-(13|12)-standard_/ { print $2 }' | + sort -V | + tail -1 + )" + [[ -n "$template_name" ]] || + { TAPM_ISO_NFS_FAIL "No supported Debian 12/13 standard template was found."; return 1; } + template_path="${template_storage}:vztmpl/${template_name}" pveam download "$template_storage" "$template_name" || { TAPM_ISO_NFS_FAIL "The Debian template download failed."; return 1; } fi diff --git a/inc/deploy-pulse-lxc.sh b/inc/deploy-pulse-lxc.sh index 842c227..b1547d5 100644 --- a/inc/deploy-pulse-lxc.sh +++ b/inc/deploy-pulse-lxc.sh @@ -60,6 +60,28 @@ TAPM_PULSE_VALID_NONNEGATIVE_INTEGER() { [[ "${1:-}" =~ ^[0-9]+$ ]] } +TAPM_PULSE_BACKOFF_NEXT() { + local current="${1:-1}" + local maximum="${2:-8}" + local next + + [[ "$current" =~ ^[1-9][0-9]*$ && + "$maximum" =~ ^[1-9][0-9]*$ ]] || return 1 + next=$((current * 2)) + (( next > maximum )) && next="$maximum" + printf '%s\n' "$next" +} + +TAPM_PULSE_BACKOFF_SLEEP() { + local deadline="$1" + local delay="$2" + local remaining=$((deadline - SECONDS)) + + (( remaining > 0 )) || return 0 + (( delay > remaining )) && delay="$remaining" + sleep "$delay" +} + TAPM_PULSE_VALID_PORT() { [[ "${1:-}" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 )) } @@ -498,7 +520,8 @@ TAPM_PULSE_CONFIGURE_SECURITY() { local token_variable="$6" local requested_password="${7:-}" local bootstrap_output bootstrap_token generated_username generated_password generated_api_token - local request_file curl_config response security_ready='no' attempt + local request_file curl_config response security_ready='no' + local deadline delay generated_username='admin' if [[ -n "$requested_password" ]]; then @@ -577,7 +600,9 @@ raise SystemExit(0 if success is True else 1) { printf 'header = "X-API-Token: %s"\n' "$generated_api_token" } >"$curl_config" || return 1 - for (( attempt = 1; attempt <= 15; attempt++ )); do + deadline=$((SECONDS + 30)) + delay=1 + while (( SECONDS < deadline )); do if curl --fail --silent --show-error \ --connect-timeout 3 --max-time 5 \ --config "$curl_config" \ @@ -585,7 +610,8 @@ raise SystemExit(0 if success is True else 1) security_ready='yes' break fi - sleep 2 + TAPM_PULSE_BACKOFF_SLEEP "$deadline" "$delay" + delay="$(TAPM_PULSE_BACKOFF_NEXT "$delay" 4)" done if [[ "$security_ready" != 'yes' ]]; then unset generated_password generated_api_token @@ -796,7 +822,8 @@ TAPM_PULSE_WAIT_AGENT_REGISTERED() { local node="$3" local temp_dir="$4" local curl_config="${temp_dir}/agent-${node}-verify.curl" - local encoded_node response attempt + local encoded_node response + local deadline delay printf 'header = "X-API-Token: %s"\n' "$token" >"$curl_config" || return 1 chmod 0600 "$curl_config" || return 1 @@ -809,8 +836,10 @@ print(urllib.parse.quote(os.environ["TAPM_PULSE_NODE_NAME"], safe="")) # Pulse v6.1.1 completes its Proxmox setup before sending the first host # report. Its built-in registration retries can span at least 135 seconds, - # so allow up to four minutes before treating the active agent as unconfirmed. - for (( attempt = 1; attempt <= 80; attempt++ )); do + # so allow up to four minutes while backing off repeated local lookups. + deadline=$((SECONDS + 240)) + delay=1 + while (( SECONDS < deadline )); do response="$( curl --fail --silent --show-error \ --connect-timeout 3 --max-time 5 \ @@ -821,7 +850,8 @@ print(urllib.parse.quote(os.environ["TAPM_PULSE_NODE_NAME"], safe="")) if TAPM_PULSE_AGENT_REGISTERED_FROM_RESPONSE "$response"; then return 0 fi - sleep 3 + TAPM_PULSE_BACKOFF_SLEEP "$deadline" "$delay" + delay="$(TAPM_PULSE_BACKOFF_NEXT "$delay" 8)" done return 1 } diff --git a/inc/fleet.inc b/inc/fleet.inc index 3d1ed02..9ed1876 100644 --- a/inc/fleet.inc +++ b/inc/fleet.inc @@ -5,6 +5,7 @@ TAPM_FLEET_IDENTITY_FILE="${TAPM_FLEET_IDENTITY_FILE:-${TAPM_FLEET_STATE_DIR}/id TAPM_FLEET_INSTALLATION_ID='' TAPM_FLEET_CREDENTIAL='' TAPM_FLEET_LAST_VERSION='' +TAPM_FLEET_ENROLLED=0 TAPM_FLEET_REGISTERED=0 TAPM_FLEET_STARTED_AT=0 TAPM_FLEET_VERSION='' @@ -26,6 +27,8 @@ TAPM_FLEET_LOAD_IDENTITY() { TAPM_FLEET_INSTALLATION_ID="$(TAPM_FLEET_READ_VALUE INSTALLATION_ID)" TAPM_FLEET_CREDENTIAL="$(TAPM_FLEET_READ_VALUE CREDENTIAL)" TAPM_FLEET_LAST_VERSION="$(TAPM_FLEET_READ_VALUE LAST_VERSION)" + TAPM_FLEET_ENROLLED="$(TAPM_FLEET_READ_VALUE ENROLLED)" + [[ "$TAPM_FLEET_ENROLLED" == 1 ]] || TAPM_FLEET_ENROLLED=0 } TAPM_FLEET_VALID_IDENTITY() { @@ -43,6 +46,7 @@ TAPM_FLEET_WRITE_IDENTITY() { printf 'INSTALLATION_ID=%s\n' "$TAPM_FLEET_INSTALLATION_ID" printf 'CREDENTIAL=%s\n' "$TAPM_FLEET_CREDENTIAL" printf 'LAST_VERSION=%s\n' "$TAPM_FLEET_LAST_VERSION" + printf 'ENROLLED=%s\n' "$TAPM_FLEET_ENROLLED" } >"$temporary_file" || ! chmod 0600 "$temporary_file" || ! mv -f "$temporary_file" "$TAPM_FLEET_IDENTITY_FILE"; then @@ -64,6 +68,7 @@ TAPM_FLEET_ENSURE_IDENTITY() { fi TAPM_FLEET_CREDENTIAL="$(openssl rand -hex 32)" || return 1 TAPM_FLEET_LAST_VERSION='' + TAPM_FLEET_ENROLLED=0 TAPM_FLEET_WRITE_IDENTITY } @@ -155,23 +160,27 @@ TAPM_FLEET_EVENT_SEND() { local duration="${4:-0}" local event_payload='' - (( TAPM_FLEET_REGISTERED == 1 )) || return 0 - event_payload="$(mktemp "${TMPDIR:-/tmp}/tapm-fleet-event.XXXXXX")" || return 0 + (( TAPM_FLEET_REGISTERED == 1 )) || return 1 + event_payload="$(mktemp "${TMPDIR:-/tmp}/tapm-fleet-event.XXXXXX")" || return 1 chmod 0600 "$event_payload" 2>/dev/null || { rm -f "$event_payload" - return 0 + return 1 } if ! TAPM_FLEET_JSON "$event" "$result" "$error_code" "$duration" >"$event_payload"; then rm -f "$event_payload" - return 0 + return 1 fi - printf 'header = "Content-Type: application/json"\nheader = "Authorization: Bearer %s"\nurl = "%s/api/v1/hosts/events"\n' \ + if printf 'header = "Content-Type: application/json"\nheader = "Authorization: Bearer %s"\nurl = "%s/api/v1/hosts/events"\n' \ "$TAPM_FLEET_CREDENTIAL" "$TAPM_BROKER_URL" | curl --fail --silent --show-error \ --connect-timeout 3 --max-time 10 \ --config - --data-binary "@${event_payload}" \ - >/dev/null 2>&1 || true + >/dev/null 2>&1; then + rm -f "$event_payload" + return 0 + fi rm -f "$event_payload" + return 1 } TAPM_FLEET_START() { @@ -181,34 +190,38 @@ TAPM_FLEET_START() { command -v python3 >/dev/null 2>&1 || return 0 command -v curl >/dev/null 2>&1 || return 0 TAPM_FLEET_COLLECT_METADATA - if TAPM_FLEET_REGISTER; then + if (( TAPM_FLEET_ENROLLED == 1 )); then TAPM_FLEET_REGISTERED=1 - else - return 0 + elif TAPM_FLEET_REGISTER; then + TAPM_FLEET_REGISTERED=1 + TAPM_FLEET_ENROLLED=1 + TAPM_FLEET_WRITE_IDENTITY || true fi - if [[ -n "$TAPM_FLEET_LAST_VERSION" && - "$TAPM_FLEET_LAST_VERSION" != "$TAPM_FLEET_VERSION" ]]; then - TAPM_FLEET_EVENT_SEND upgraded success - fi - TAPM_FLEET_EVENT_SEND run_started started } TAPM_FLEET_FINISH() { local exit_status="${1:-0}" local duration=0 + local event_sent=0 if [[ "$TAPM_FLEET_STARTED_AT" =~ ^[0-9]+$ ]] && (( TAPM_FLEET_STARTED_AT > 0 )); then duration="$(( $(date +%s) - TAPM_FLEET_STARTED_AT ))" fi if (( exit_status == 0 )); then - TAPM_FLEET_EVENT_SEND run_completed success '' "$duration" + TAPM_FLEET_EVENT_SEND run_completed success '' "$duration" && + event_sent=1 else - TAPM_FLEET_EVENT_SEND run_failed failure exit_nonzero "$duration" + TAPM_FLEET_EVENT_SEND run_failed failure exit_nonzero "$duration" && + event_sent=1 fi - if (( TAPM_FLEET_REGISTERED == 1 )) && TAPM_FLEET_VALID_IDENTITY; then + if (( event_sent == 1 )) && TAPM_FLEET_VALID_IDENTITY; then TAPM_FLEET_LAST_VERSION="$TAPM_FLEET_VERSION" - TAPM_FLEET_WRITE_IDENTITY || true + else + # A failed event may mean the broker no longer recognizes this local + # credential. Re-enroll on the next invocation, not during this one. + TAPM_FLEET_ENROLLED=0 fi + TAPM_FLEET_VALID_IDENTITY && TAPM_FLEET_WRITE_IDENTITY || true return 0 } diff --git a/inc/virtio-helpers.inc b/inc/virtio-helpers.inc index ce04a1b..30a8606 100644 --- a/inc/virtio-helpers.inc +++ b/inc/virtio-helpers.inc @@ -23,3 +23,17 @@ TAPM_VIRTIO_LABELED_FILENAME() { printf 'virtio-win-%s%s.iso\n' "$label" "${version:+-${version}}" } + +TAPM_VIRTIO_CACHE_VALID() { + local checked_at="${1:-}" + local now="${2:-}" + local max_age="${3:-}" + local filename="${4:-}" + + [[ "$checked_at" =~ ^[0-9]+$ && + "$now" =~ ^[0-9]+$ && + "$max_age" =~ ^[1-9][0-9]*$ && + "$filename" =~ ^virtio-win(-[0-9]+\.[0-9]+\.[0-9]+)?\.iso$ ]] || + return 1 + (( now >= checked_at && now - checked_at < max_age )) +} diff --git a/proxmenu-scripts.sh b/proxmenu-scripts.sh index 2aa09d5..45f372e 100755 --- a/proxmenu-scripts.sh +++ b/proxmenu-scripts.sh @@ -687,6 +687,8 @@ INSTALL_OMSA() { VIRTIO_STABLE_CHECKED=0 VIRTIO_STABLE_STATUS='unknown' VIRTIO_STABLE_FILE='' +VIRTIO_STABLE_CACHE_FILE="${VIRTIO_STABLE_CACHE_FILE:-/var/cache/ta-proxmenu/virtio-stable}" +VIRTIO_STABLE_CACHE_SECONDS=86400 VIRTIO_LAST_FILE='' DLDIR='' VIRTIO_SELECTED_STORAGE='' @@ -784,8 +786,12 @@ TAPM_REFRESH_VIRTIO_LOCAL_STATUS() { TAPM_CHECK_VIRTIO_STABLE() { local force="${1:-0}" + local cached_at='' + local cached_filename='' local effective_url + local now local source_filename + local cache_temp if (( VIRTIO_STABLE_CHECKED == 1 && force == 0 )); then return @@ -794,6 +800,19 @@ TAPM_CHECK_VIRTIO_STABLE() { VIRTIO_STABLE_CHECKED=1 VIRTIO_STABLE_STATUS='unavailable' VIRTIO_STABLE_FILE='' + now="$(date +%s)" + + if (( force == 0 )) && [[ -r "$VIRTIO_STABLE_CACHE_FILE" ]]; then + IFS='|' read -r cached_at cached_filename <"$VIRTIO_STABLE_CACHE_FILE" + if TAPM_VIRTIO_CACHE_VALID \ + "$cached_at" "$now" "$VIRTIO_STABLE_CACHE_SECONDS" "$cached_filename"; then + VIRTIO_STABLE_FILE="$( + TAPM_VIRTIO_LABELED_FILENAME "$cached_filename" latest + )" || return 1 + TAPM_REFRESH_VIRTIO_LOCAL_STATUS + return 0 + fi + fi effective_url="$( curl --fail --location --silent --show-error --head \ @@ -806,6 +825,18 @@ TAPM_CHECK_VIRTIO_STABLE() { return 1 VIRTIO_STABLE_FILE="$(TAPM_VIRTIO_LABELED_FILENAME "$source_filename" latest)" || return 1 + if mkdir -p "$(dirname "$VIRTIO_STABLE_CACHE_FILE")" 2>/dev/null; then + cache_temp="$(mktemp "${VIRTIO_STABLE_CACHE_FILE}.tmp.XXXXXX")" || cache_temp='' + if [[ -n "$cache_temp" ]]; then + if printf '%s|%s\n' "$now" "$source_filename" >"$cache_temp" && + chmod 0644 "$cache_temp"; then + mv -f "$cache_temp" "$VIRTIO_STABLE_CACHE_FILE" || + rm -f "$cache_temp" + else + rm -f "$cache_temp" + fi + fi + fi TAPM_REFRESH_VIRTIO_LOCAL_STATUS } @@ -1000,7 +1031,7 @@ VIRTIO_MENU() { echo -en "\n${idsCL[LightCyan]}Checking the current stable VirtIO release...${idsCL[Default]} " TAPM_REFRESH_ISO_STORAGES || true - TAPM_CHECK_VIRTIO_STABLE 1 || true + TAPM_CHECK_VIRTIO_STABLE 0 || true echo while true; do @@ -1492,7 +1523,7 @@ INSTALL_KEEPALIVE() { UPDATE_CACHE_DIR='/var/cache/ta-proxmenu' UPDATE_CACHE_FILE="${UPDATE_CACHE_DIR}/update-status" -UPDATE_CACHE_SECONDS=14400 +UPDATE_CACHE_SECONDS=86400 UPDATE_CHECK_PID='' UPDATE_STATUS='unknown' UPDATE_REMOTE_COMMIT='' diff --git a/tests/test-fleet.sh b/tests/test-fleet.sh index c700419..2fd65a7 100644 --- a/tests/test-fleet.sh +++ b/tests/test-fleet.sh @@ -48,6 +48,7 @@ assert payload["clustered"] is True ' printf '0\n' >"${test_dir}/curl-count" +curl_should_fail=0 curl() { local count data_path='' previous='' argument='' count="$(cat "${test_dir}/curl-count")" @@ -59,11 +60,11 @@ curl() { fi previous="$argument" done - if [[ -n "$data_path" ]]; then + if [[ -n "$data_path" && "$data_path" != '-' ]]; then cp "$data_path" "${test_dir}/curl-body-${count}.json" fi cat >"${test_dir}/curl-config-${count}" - return 0 + (( curl_should_fail == 0 )) } TAPM_FLEET_REGISTERED=1 @@ -89,4 +90,59 @@ if compgen -G "${TMPDIR:-/tmp}/tapm-fleet-event.*" >/dev/null; then exit 1 fi +printf '0\n' >"${test_dir}/curl-count" +TAPM_FLEET_ENROLLED=0 +TAPM_FLEET_REGISTERED=0 +TAPM_FLEET_LAST_VERSION='' +TAPM_FLEET_COLLECT_METADATA() { + TAPM_FLEET_HOSTNAME='pve01' + TAPM_FLEET_GIT_COMMIT='0123456789abcdef0123456789abcdef01234567' + TAPM_FLEET_PVE_VERSION='pve-manager/9.2.4' + TAPM_FLEET_OS_VERSION='Debian GNU/Linux 13 (trixie)' + TAPM_FLEET_KERNEL_VERSION='6.14.11-5-pve' + TAPM_FLEET_ARCHITECTURE='amd64' + TAPM_FLEET_CLUSTERED=true +} + +TAPM_FLEET_START '2026.7.28-9' +TAPM_FLEET_FINISH 0 +if [[ "$(cat "${test_dir}/curl-count")" != 2 ]]; then + printf 'FAIL: initial run did not make exactly registration + completion calls\n' >&2 + exit 1 +fi +TAPM_FLEET_LOAD_IDENTITY +if [[ "$TAPM_FLEET_ENROLLED" != 1 || + "$TAPM_FLEET_LAST_VERSION" != '2026.7.28-9' ]]; then + printf 'FAIL: successful fleet enrollment was not persisted\n' >&2 + exit 1 +fi + +TAPM_FLEET_REGISTERED=0 +TAPM_FLEET_START '2026.7.28-9' +TAPM_FLEET_FINISH 0 +if [[ "$(cat "${test_dir}/curl-count")" != 3 ]]; then + printf 'FAIL: normal run made more than one broker call\n' >&2 + exit 1 +fi + +curl_should_fail=1 +TAPM_FLEET_REGISTERED=0 +TAPM_FLEET_START '2026.7.28-9' +TAPM_FLEET_FINISH 0 +TAPM_FLEET_LOAD_IDENTITY +if [[ "$TAPM_FLEET_ENROLLED" != 0 ]]; then + printf 'FAIL: failed fleet event did not schedule next-run re-enrollment\n' >&2 + exit 1 +fi + +curl_should_fail=0 +TAPM_FLEET_REGISTERED=0 +TAPM_FLEET_START '2026.7.28-9' +TAPM_FLEET_FINISH 0 +TAPM_FLEET_LOAD_IDENTITY +if [[ "$TAPM_FLEET_ENROLLED" != 1 ]]; then + printf 'FAIL: fleet client did not recover enrollment after a failed event\n' >&2 + exit 1 +fi + printf 'PASS: fleet identity and event client\n' diff --git a/tests/test-git-update.sh b/tests/test-git-update.sh index 19437c3..3439e9d 100755 --- a/tests/test-git-update.sh +++ b/tests/test-git-update.sh @@ -5,6 +5,9 @@ TEST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" source "${TEST_ROOT}/tests/testlib.sh" source "${TEST_ROOT}/inc/git-update.inc" +assert_success "automatic Git check cache is 24 hours" \ + grep -q '^UPDATE_CACHE_SECONDS=86400$' "${TEST_ROOT}/proxmenu-scripts.sh" + TEST_TEMP_DIR="$(mktemp -d /tmp/tapm-git-tests.XXXXXX)" TEST_REPOSITORY="${TEST_TEMP_DIR}/repository" diff --git a/tests/test-iso-nfs.sh b/tests/test-iso-nfs.sh index 5c9b099..924761c 100755 --- a/tests/test-iso-nfs.sh +++ b/tests/test-iso-nfs.sh @@ -60,4 +60,16 @@ test_default_storage_selection() { assert_success "default storage menu selection" test_default_storage_selection +pveam() { + [[ "${1:-}" == list && "${2:-}" == local ]] || return 1 + printf '%s\n' \ + 'NAME VOLID FORMAT TYPE SIZE VMID' \ + 'local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst 0 0 0 0 0' \ + 'local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst 0 0 0 0 0' +} +assert_equal \ + 'local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst' \ + "$(TAPM_ISO_NFS_LOCAL_TEMPLATE local)" \ + "newest local Debian template avoids catalog refresh" + finish_tests diff --git a/tests/test-pulse.sh b/tests/test-pulse.sh index 9be6d75..df18b83 100644 --- a/tests/test-pulse.sh +++ b/tests/test-pulse.sh @@ -15,6 +15,10 @@ assert_equal amd64 "$(TAPM_PULSE_ARCH x86_64)" "x86 architecture mapping" assert_equal arm64 "$(TAPM_PULSE_ARCH aarch64)" "ARM architecture mapping" assert_failure "unsupported Pulse architecture" TAPM_PULSE_ARCH riscv64 +assert_equal 2 "$(TAPM_PULSE_BACKOFF_NEXT 1 8)" "Pulse backoff doubles" +assert_equal 8 "$(TAPM_PULSE_BACKOFF_NEXT 4 8)" "Pulse backoff reaches cap" +assert_equal 8 "$(TAPM_PULSE_BACKOFF_NEXT 8 8)" "Pulse backoff remains capped" + test_bridge_selection_assignment() { local bridge='' diff --git a/tests/test-virtio.sh b/tests/test-virtio.sh index b753d89..d991261 100755 --- a/tests/test-virtio.sh +++ b/tests/test-virtio.sh @@ -31,4 +31,13 @@ assert_equal virtio-win-server-2008r2-0.1.172.iso \ assert_failure "unsafe local label rejected" \ TAPM_VIRTIO_LABELED_FILENAME virtio-win-0.1.285.iso '../latest' +assert_success "fresh VirtIO cache accepted" \ + TAPM_VIRTIO_CACHE_VALID 1000 1500 86400 virtio-win-0.1.285.iso +assert_failure "expired VirtIO cache rejected" \ + TAPM_VIRTIO_CACHE_VALID 1000 87400 86400 virtio-win-0.1.285.iso +assert_failure "future VirtIO cache rejected" \ + TAPM_VIRTIO_CACHE_VALID 2000 1000 86400 virtio-win-0.1.285.iso +assert_failure "unsafe VirtIO cache filename rejected" \ + TAPM_VIRTIO_CACHE_VALID 1000 1500 86400 ../../installer + finish_tests