This commit is contained in:
David Schroeder
2026-07-28 22:09:13 -05:00
parent 247c4ddace
commit 3bea3baa88
12 changed files with 236 additions and 49 deletions
+12 -6
View File
@@ -177,12 +177,18 @@ a default company URL.
V2 creates a random installation UUID and 256-bit credential in 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 `/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 is mode `0600`. The first successful launch enrolls the host with the broker.
calls to the configured broker to record the hostname, installation/upgrade Later launches make one best-effort HTTPS call on completion or failure to
state, start and completion status, duration, TA-ProxMenu and Git versions, record the hostname, duration, result, TA-ProxMenu and Git versions,
PVE/OS/kernel versions, architecture, and whether the host is clustered. No PVE/OS/kernel versions, architecture, and whether the host is clustered. A
background service is installed, and broker availability never prevents the failed event schedules re-enrollment on the next invocation instead of adding
menu from running. 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 The hostname is treated as a limited operational identifier. The registry does
not send machine IDs, MAC addresses, usernames, VM/container inventory, not send machine IDs, MAC addresses, usernames, VM/container inventory,
+1 -1
View File
@@ -3,7 +3,7 @@
action="${1:-}" action="${1:-}"
FOLDER='/opt/idssys/ta-proxmenu' FOLDER='/opt/idssys/ta-proxmenu'
VERS='2026.7.28-8' VERS='2026.7.28-9'
noupdate=' ' noupdate=' '
+22 -13
View File
@@ -49,6 +49,15 @@ TAPM_ISO_NFS_FAIL() {
return 1 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() { TAPM_ISO_NFS_SELECT_STORAGE() {
local variable="$1" local variable="$1"
local label="$2" local label="$2"
@@ -198,19 +207,19 @@ TAPM_DEPLOY_ISO_NFS_LXC() {
} }
echo -e "\n${idsCL[LightCyan]}Locating a Debian container template...${idsCL[Default]}" 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_path="$(TAPM_ISO_NFS_LOCAL_TEMPLATE "$template_storage")"
template_name="$( if [[ -z "$template_path" ]]; then
pveam available --section system | pveam update ||
awk '$2 ~ /^debian-(13|12)-standard_/ { print $2 }' | { TAPM_ISO_NFS_FAIL "Could not refresh the template catalog."; return 1; }
sort -V | template_name="$(
tail -1 pveam available --section system |
)" awk '$2 ~ /^debian-(13|12)-standard_/ { print $2 }' |
[[ -n "$template_name" ]] || sort -V |
{ TAPM_ISO_NFS_FAIL "No supported Debian 12/13 standard template was found."; return 1; } tail -1
template_path="${template_storage}:vztmpl/${template_name}" )"
if ! pveam list "$template_storage" 2>/dev/null | [[ -n "$template_name" ]] ||
awk 'NR > 1 { print $1 }' | { TAPM_ISO_NFS_FAIL "No supported Debian 12/13 standard template was found."; return 1; }
grep -Fxq -- "$template_path"; then template_path="${template_storage}:vztmpl/${template_name}"
pveam download "$template_storage" "$template_name" || pveam download "$template_storage" "$template_name" ||
{ TAPM_ISO_NFS_FAIL "The Debian template download failed."; return 1; } { TAPM_ISO_NFS_FAIL "The Debian template download failed."; return 1; }
fi fi
+37 -7
View File
@@ -60,6 +60,28 @@ TAPM_PULSE_VALID_NONNEGATIVE_INTEGER() {
[[ "${1:-}" =~ ^[0-9]+$ ]] [[ "${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() { TAPM_PULSE_VALID_PORT() {
[[ "${1:-}" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 )) [[ "${1:-}" =~ ^[0-9]+$ ]] && (( 10#$1 >= 1 && 10#$1 <= 65535 ))
} }
@@ -498,7 +520,8 @@ TAPM_PULSE_CONFIGURE_SECURITY() {
local token_variable="$6" local token_variable="$6"
local requested_password="${7:-}" local requested_password="${7:-}"
local bootstrap_output bootstrap_token generated_username generated_password generated_api_token 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' generated_username='admin'
if [[ -n "$requested_password" ]]; then 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" printf 'header = "X-API-Token: %s"\n' "$generated_api_token"
} >"$curl_config" || return 1 } >"$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 \ if curl --fail --silent --show-error \
--connect-timeout 3 --max-time 5 \ --connect-timeout 3 --max-time 5 \
--config "$curl_config" \ --config "$curl_config" \
@@ -585,7 +610,8 @@ raise SystemExit(0 if success is True else 1)
security_ready='yes' security_ready='yes'
break break
fi fi
sleep 2 TAPM_PULSE_BACKOFF_SLEEP "$deadline" "$delay"
delay="$(TAPM_PULSE_BACKOFF_NEXT "$delay" 4)"
done done
if [[ "$security_ready" != 'yes' ]]; then if [[ "$security_ready" != 'yes' ]]; then
unset generated_password generated_api_token unset generated_password generated_api_token
@@ -796,7 +822,8 @@ TAPM_PULSE_WAIT_AGENT_REGISTERED() {
local node="$3" local node="$3"
local temp_dir="$4" local temp_dir="$4"
local curl_config="${temp_dir}/agent-${node}-verify.curl" 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 printf 'header = "X-API-Token: %s"\n' "$token" >"$curl_config" || return 1
chmod 0600 "$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 # 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, # 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. # so allow up to four minutes while backing off repeated local lookups.
for (( attempt = 1; attempt <= 80; attempt++ )); do deadline=$((SECONDS + 240))
delay=1
while (( SECONDS < deadline )); do
response="$( response="$(
curl --fail --silent --show-error \ curl --fail --silent --show-error \
--connect-timeout 3 --max-time 5 \ --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 if TAPM_PULSE_AGENT_REGISTERED_FROM_RESPONSE "$response"; then
return 0 return 0
fi fi
sleep 3 TAPM_PULSE_BACKOFF_SLEEP "$deadline" "$delay"
delay="$(TAPM_PULSE_BACKOFF_NEXT "$delay" 8)"
done done
return 1 return 1
} }
+31 -18
View File
@@ -5,6 +5,7 @@ TAPM_FLEET_IDENTITY_FILE="${TAPM_FLEET_IDENTITY_FILE:-${TAPM_FLEET_STATE_DIR}/id
TAPM_FLEET_INSTALLATION_ID='' TAPM_FLEET_INSTALLATION_ID=''
TAPM_FLEET_CREDENTIAL='' TAPM_FLEET_CREDENTIAL=''
TAPM_FLEET_LAST_VERSION='' TAPM_FLEET_LAST_VERSION=''
TAPM_FLEET_ENROLLED=0
TAPM_FLEET_REGISTERED=0 TAPM_FLEET_REGISTERED=0
TAPM_FLEET_STARTED_AT=0 TAPM_FLEET_STARTED_AT=0
TAPM_FLEET_VERSION='' TAPM_FLEET_VERSION=''
@@ -26,6 +27,8 @@ TAPM_FLEET_LOAD_IDENTITY() {
TAPM_FLEET_INSTALLATION_ID="$(TAPM_FLEET_READ_VALUE INSTALLATION_ID)" TAPM_FLEET_INSTALLATION_ID="$(TAPM_FLEET_READ_VALUE INSTALLATION_ID)"
TAPM_FLEET_CREDENTIAL="$(TAPM_FLEET_READ_VALUE CREDENTIAL)" TAPM_FLEET_CREDENTIAL="$(TAPM_FLEET_READ_VALUE CREDENTIAL)"
TAPM_FLEET_LAST_VERSION="$(TAPM_FLEET_READ_VALUE LAST_VERSION)" 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() { TAPM_FLEET_VALID_IDENTITY() {
@@ -43,6 +46,7 @@ TAPM_FLEET_WRITE_IDENTITY() {
printf 'INSTALLATION_ID=%s\n' "$TAPM_FLEET_INSTALLATION_ID" printf 'INSTALLATION_ID=%s\n' "$TAPM_FLEET_INSTALLATION_ID"
printf 'CREDENTIAL=%s\n' "$TAPM_FLEET_CREDENTIAL" printf 'CREDENTIAL=%s\n' "$TAPM_FLEET_CREDENTIAL"
printf 'LAST_VERSION=%s\n' "$TAPM_FLEET_LAST_VERSION" printf 'LAST_VERSION=%s\n' "$TAPM_FLEET_LAST_VERSION"
printf 'ENROLLED=%s\n' "$TAPM_FLEET_ENROLLED"
} >"$temporary_file" || } >"$temporary_file" ||
! chmod 0600 "$temporary_file" || ! chmod 0600 "$temporary_file" ||
! mv -f "$temporary_file" "$TAPM_FLEET_IDENTITY_FILE"; then ! mv -f "$temporary_file" "$TAPM_FLEET_IDENTITY_FILE"; then
@@ -64,6 +68,7 @@ TAPM_FLEET_ENSURE_IDENTITY() {
fi fi
TAPM_FLEET_CREDENTIAL="$(openssl rand -hex 32)" || return 1 TAPM_FLEET_CREDENTIAL="$(openssl rand -hex 32)" || return 1
TAPM_FLEET_LAST_VERSION='' TAPM_FLEET_LAST_VERSION=''
TAPM_FLEET_ENROLLED=0
TAPM_FLEET_WRITE_IDENTITY TAPM_FLEET_WRITE_IDENTITY
} }
@@ -155,23 +160,27 @@ TAPM_FLEET_EVENT_SEND() {
local duration="${4:-0}" local duration="${4:-0}"
local event_payload='' local event_payload=''
(( TAPM_FLEET_REGISTERED == 1 )) || return 0 (( TAPM_FLEET_REGISTERED == 1 )) || return 1
event_payload="$(mktemp "${TMPDIR:-/tmp}/tapm-fleet-event.XXXXXX")" || return 0 event_payload="$(mktemp "${TMPDIR:-/tmp}/tapm-fleet-event.XXXXXX")" || return 1
chmod 0600 "$event_payload" 2>/dev/null || { chmod 0600 "$event_payload" 2>/dev/null || {
rm -f "$event_payload" rm -f "$event_payload"
return 0 return 1
} }
if ! TAPM_FLEET_JSON "$event" "$result" "$error_code" "$duration" >"$event_payload"; then if ! TAPM_FLEET_JSON "$event" "$result" "$error_code" "$duration" >"$event_payload"; then
rm -f "$event_payload" rm -f "$event_payload"
return 0 return 1
fi 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" | "$TAPM_FLEET_CREDENTIAL" "$TAPM_BROKER_URL" |
curl --fail --silent --show-error \ curl --fail --silent --show-error \
--connect-timeout 3 --max-time 10 \ --connect-timeout 3 --max-time 10 \
--config - --data-binary "@${event_payload}" \ --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" rm -f "$event_payload"
return 1
} }
TAPM_FLEET_START() { TAPM_FLEET_START() {
@@ -181,34 +190,38 @@ TAPM_FLEET_START() {
command -v python3 >/dev/null 2>&1 || return 0 command -v python3 >/dev/null 2>&1 || return 0
command -v curl >/dev/null 2>&1 || return 0 command -v curl >/dev/null 2>&1 || return 0
TAPM_FLEET_COLLECT_METADATA TAPM_FLEET_COLLECT_METADATA
if TAPM_FLEET_REGISTER; then if (( TAPM_FLEET_ENROLLED == 1 )); then
TAPM_FLEET_REGISTERED=1 TAPM_FLEET_REGISTERED=1
else elif TAPM_FLEET_REGISTER; then
return 0 TAPM_FLEET_REGISTERED=1
TAPM_FLEET_ENROLLED=1
TAPM_FLEET_WRITE_IDENTITY || true
fi 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() { TAPM_FLEET_FINISH() {
local exit_status="${1:-0}" local exit_status="${1:-0}"
local duration=0 local duration=0
local event_sent=0
if [[ "$TAPM_FLEET_STARTED_AT" =~ ^[0-9]+$ ]] && if [[ "$TAPM_FLEET_STARTED_AT" =~ ^[0-9]+$ ]] &&
(( TAPM_FLEET_STARTED_AT > 0 )); then (( TAPM_FLEET_STARTED_AT > 0 )); then
duration="$(( $(date +%s) - TAPM_FLEET_STARTED_AT ))" duration="$(( $(date +%s) - TAPM_FLEET_STARTED_AT ))"
fi fi
if (( exit_status == 0 )); then 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 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 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_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 fi
TAPM_FLEET_VALID_IDENTITY && TAPM_FLEET_WRITE_IDENTITY || true
return 0 return 0
} }
+14
View File
@@ -23,3 +23,17 @@ TAPM_VIRTIO_LABELED_FILENAME() {
printf 'virtio-win-%s%s.iso\n' "$label" "${version:+-${version}}" 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 ))
}
+33 -2
View File
@@ -687,6 +687,8 @@ INSTALL_OMSA() {
VIRTIO_STABLE_CHECKED=0 VIRTIO_STABLE_CHECKED=0
VIRTIO_STABLE_STATUS='unknown' VIRTIO_STABLE_STATUS='unknown'
VIRTIO_STABLE_FILE='' 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='' VIRTIO_LAST_FILE=''
DLDIR='' DLDIR=''
VIRTIO_SELECTED_STORAGE='' VIRTIO_SELECTED_STORAGE=''
@@ -784,8 +786,12 @@ TAPM_REFRESH_VIRTIO_LOCAL_STATUS() {
TAPM_CHECK_VIRTIO_STABLE() { TAPM_CHECK_VIRTIO_STABLE() {
local force="${1:-0}" local force="${1:-0}"
local cached_at=''
local cached_filename=''
local effective_url local effective_url
local now
local source_filename local source_filename
local cache_temp
if (( VIRTIO_STABLE_CHECKED == 1 && force == 0 )); then if (( VIRTIO_STABLE_CHECKED == 1 && force == 0 )); then
return return
@@ -794,6 +800,19 @@ TAPM_CHECK_VIRTIO_STABLE() {
VIRTIO_STABLE_CHECKED=1 VIRTIO_STABLE_CHECKED=1
VIRTIO_STABLE_STATUS='unavailable' VIRTIO_STABLE_STATUS='unavailable'
VIRTIO_STABLE_FILE='' 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="$( effective_url="$(
curl --fail --location --silent --show-error --head \ curl --fail --location --silent --show-error --head \
@@ -806,6 +825,18 @@ TAPM_CHECK_VIRTIO_STABLE() {
return 1 return 1
VIRTIO_STABLE_FILE="$(TAPM_VIRTIO_LABELED_FILENAME "$source_filename" latest)" || VIRTIO_STABLE_FILE="$(TAPM_VIRTIO_LABELED_FILENAME "$source_filename" latest)" ||
return 1 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 TAPM_REFRESH_VIRTIO_LOCAL_STATUS
} }
@@ -1000,7 +1031,7 @@ VIRTIO_MENU() {
echo -en "\n${idsCL[LightCyan]}Checking the current stable VirtIO release...${idsCL[Default]} " echo -en "\n${idsCL[LightCyan]}Checking the current stable VirtIO release...${idsCL[Default]} "
TAPM_REFRESH_ISO_STORAGES || true TAPM_REFRESH_ISO_STORAGES || true
TAPM_CHECK_VIRTIO_STABLE 1 || true TAPM_CHECK_VIRTIO_STABLE 0 || true
echo echo
while true; do while true; do
@@ -1492,7 +1523,7 @@ INSTALL_KEEPALIVE() {
UPDATE_CACHE_DIR='/var/cache/ta-proxmenu' UPDATE_CACHE_DIR='/var/cache/ta-proxmenu'
UPDATE_CACHE_FILE="${UPDATE_CACHE_DIR}/update-status" UPDATE_CACHE_FILE="${UPDATE_CACHE_DIR}/update-status"
UPDATE_CACHE_SECONDS=14400 UPDATE_CACHE_SECONDS=86400
UPDATE_CHECK_PID='' UPDATE_CHECK_PID=''
UPDATE_STATUS='unknown' UPDATE_STATUS='unknown'
UPDATE_REMOTE_COMMIT='' UPDATE_REMOTE_COMMIT=''
+58 -2
View File
@@ -48,6 +48,7 @@ assert payload["clustered"] is True
' '
printf '0\n' >"${test_dir}/curl-count" printf '0\n' >"${test_dir}/curl-count"
curl_should_fail=0
curl() { curl() {
local count data_path='' previous='' argument='' local count data_path='' previous='' argument=''
count="$(cat "${test_dir}/curl-count")" count="$(cat "${test_dir}/curl-count")"
@@ -59,11 +60,11 @@ curl() {
fi fi
previous="$argument" previous="$argument"
done done
if [[ -n "$data_path" ]]; then if [[ -n "$data_path" && "$data_path" != '-' ]]; then
cp "$data_path" "${test_dir}/curl-body-${count}.json" cp "$data_path" "${test_dir}/curl-body-${count}.json"
fi fi
cat >"${test_dir}/curl-config-${count}" cat >"${test_dir}/curl-config-${count}"
return 0 (( curl_should_fail == 0 ))
} }
TAPM_FLEET_REGISTERED=1 TAPM_FLEET_REGISTERED=1
@@ -89,4 +90,59 @@ if compgen -G "${TMPDIR:-/tmp}/tapm-fleet-event.*" >/dev/null; then
exit 1 exit 1
fi 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' printf 'PASS: fleet identity and event client\n'
+3
View File
@@ -5,6 +5,9 @@ TEST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
source "${TEST_ROOT}/tests/testlib.sh" source "${TEST_ROOT}/tests/testlib.sh"
source "${TEST_ROOT}/inc/git-update.inc" 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_TEMP_DIR="$(mktemp -d /tmp/tapm-git-tests.XXXXXX)"
TEST_REPOSITORY="${TEST_TEMP_DIR}/repository" TEST_REPOSITORY="${TEST_TEMP_DIR}/repository"
+12
View File
@@ -60,4 +60,16 @@ test_default_storage_selection() {
assert_success "default storage menu selection" 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 finish_tests
+4
View File
@@ -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_equal arm64 "$(TAPM_PULSE_ARCH aarch64)" "ARM architecture mapping"
assert_failure "unsupported Pulse architecture" TAPM_PULSE_ARCH riscv64 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() { test_bridge_selection_assignment() {
local bridge='' local bridge=''
+9
View File
@@ -31,4 +31,13 @@ assert_equal virtio-win-server-2008r2-0.1.172.iso \
assert_failure "unsafe local label rejected" \ assert_failure "unsafe local label rejected" \
TAPM_VIRTIO_LABELED_FILENAME virtio-win-0.1.285.iso '../latest' 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 finish_tests