Skip to content

Instantly share code, notes, and snippets.

@QNimbus
Last active June 19, 2025 10:45
Show Gist options
  • Save QNimbus/12b7b0651e196f1a80f1a7f6de66811e to your computer and use it in GitHub Desktop.
Save QNimbus/12b7b0651e196f1a80f1a7f6de66811e to your computer and use it in GitHub Desktop.
Proxmox Talos download script #proxmox
#!/usr/bin/env bash
# To download: `curl -O https://gist.githubusercontent.com/QNimbus/12b7b0651e196f1a80f1a7f6de66811e/raw/talos_download.sh`
# To run: `chmod +x talos_download.sh && ./talos_download.sh --id <your-schematic-id>`
# ====================================================
# Talos Linux ISO Download Script
# ====================================================
#
# Author: B. van Wetten <[email protected]>
# Version: 1.0.9
# Created: 2025-06-19
# Updated: 2025-06-19
#
# This script automates the download of Talos Linux ISOs.
# It uses shared libraries for common utilities and Proxmox interactions.
#
# Features:
# - Downloads custom Talos ISOs using schematic IDs
# - Integrates with Proxmox storage for ISO placement (uses proxmox.lib.sh)
# - Shows download progress and verifies file integrity
# - Supports version selection
# - Self-update mechanism for script and libraries
#
# Requirements:
# - Proxmox VE with pvesm command available
# - curl, jq and numfmt commands
# - ./lib/utils.lib.sh and ./lib/proxmox.lib.sh
# ====================================================
# --- Script Metadata for Updates ---
SCRIPT_NAME=$(basename "$0")
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
SCRIPT_CURRENT_VERSION_LINE=$(grep '^# Version:' "$0" || echo "# Version: 0.0.0-local")
SCRIPT_CURRENT_VERSION=$(echo "$SCRIPT_CURRENT_VERSION_LINE" | awk '{print $3}')
SCRIPT_RAW_URL="https://gist.githubusercontent.com/QNimbus/12b7b0651e196f1a80f1a7f6de66811e/raw/talos_download.sh"
# --- Library Configuration ---
LIB_DIR_NAME="lib"
LIB_DIR="${SCRIPT_DIR}/${LIB_DIR_NAME}"
declare -A LIBRARIES_CONFIG
LIBRARIES_CONFIG=(
["utils"]="utils.lib.sh UTILS_LIB_RAW_URL UTILS_LIB_CURRENT_VERSION ^# LibVersion:"
["proxmox"]="proxmox.lib.sh PROXMOX_LIB_RAW_URL PROXMOX_LIB_CURRENT_VERSION ^# LibVersion:"
)
UTILS_LIB_RAW_URL="https://gist.githubusercontent.com/QNimbus/a972908f09c2b6fed2b33307d00076f1/raw/utils.lib.sh"
PROXMOX_LIB_RAW_URL="https://gist.githubusercontent.com/QNimbus/a972908f09c2b6fed2b33307d00076f1/raw/proxmox.lib.sh"
VERBOSE_FLAG="false"
log_info() { echo "ℹ️ $*"; }
log_success() { echo "$*"; }
log_warning() { echo "⚠️ $*" >&2; }
log_error() { echo "$*" >&2; }
log_verbose() { if [[ "$VERBOSE_FLAG" == "true" ]]; then echo "🔍 $*" >&2; fi; }
restore_cursor() {
printf "\033[?25h"
}
_err_trap() {
local exit_code=$?
local line_no=${1:-$LINENO}
local command_str="${BASH_COMMAND}"
local func_stack=("${FUNCNAME[@]}")
local source_stack=("${BASH_SOURCE[@]}")
if [[ "$command_str" == "exit"* || "$command_str" == *"_err_trap"* || "$exit_code" -eq 0 || "$command_str" == "return"* ]]; then return; fi
echo; log_error "ERROR in $SCRIPT_NAME: Script exited with status $exit_code."
log_error "Failed command: '$command_str' on line $line_no of file '${BASH_SOURCE[0]}'."
if [[ ${#func_stack[@]} -gt 1 ]]; then
log_error "Call Stack (most recent call first):"
for i in $(seq 1 $((${#func_stack[@]} - 1))); do
local func_idx=$((i)); local src_idx=$((i)); local line_idx=$((i-1))
local func="${func_stack[$func_idx]}"; local src_file="${source_stack[$src_idx]}"; local src_line="${BASH_LINENO[$line_idx]}"
log_error " -> function '$func' in file '$src_file' at line $src_line"
done
fi
restore_cursor
}
trap '_err_trap "${LINENO}"' ERR
trap restore_cursor EXIT SIGINT SIGTERM
set -euo pipefail
get_remote_file_version() {
local file_url="$1"; local version_grep_pattern="$2"; local timestamp cache_busted_url remote_script_content remote_version_line
log_verbose "Fetching remote version metadata from URL: $file_url" # General verbose message
timestamp=$(date +%s); cache_busted_url="${file_url}?v=${timestamp}&nocache=$(date +%s%N 2>/dev/null || echo "$RANDOM")"
log_verbose "Using cache-busted URL: $cache_busted_url"
local curl_cmd_args=(--fail -sL -H "Cache-Control: no-cache, no-store, max-age=0, must-revalidate" -H "Pragma: no-cache" -H "Expires: 0" "$cache_busted_url")
# Use a subshell to avoid affecting the main shell's error handling
_curl_result=$(
set +o pipefail
curl "${curl_cmd_args[@]}"
echo "EXIT_CODE:$?"
)
# Parse the output to separate content from exit code
remote_script_content=$(echo "$_curl_result" | grep -v '^EXIT_CODE:')
curl_exit_code=$(echo "$_curl_result" | grep '^EXIT_CODE:' | cut -d: -f2)
log_verbose "curl exit code for version fetch: $curl_exit_code"
if [[ $curl_exit_code -ne 0 ]]; then log_warning "curl failed for '$file_url' (Code: $curl_exit_code)."; return 1; fi
if [[ -z "$remote_script_content" ]]; then log_warning "Fetched content empty for '$file_url'."; return 1; fi
remote_version_line=$(echo "$remote_script_content" | grep "$version_grep_pattern" || true)
if [[ -z "$remote_version_line" ]]; then log_warning "No version (pattern: '$version_grep_pattern') in '$file_url'."; return 1; fi
echo "$remote_version_line" | awk '{print $3}'
}
get_local_file_version() {
local file_path="$1"; local version_grep_pattern="$2"; local version_line
if [[ ! -f "$file_path" ]]; then return 1; fi
version_line=$(grep "$version_grep_pattern" "$file_path" || echo "")
if [[ -z "$version_line" ]]; then log_warning "No version (pattern: '$version_grep_pattern') in local '$file_path'."; return 1; fi
echo "$version_line" | awk '{print $3}'
}
download_file() {
local file_url="$1"; local local_path="$2"; local temp_file timestamp cache_busted_url
log_info "Downloading '$file_url' to '$local_path'..."
if ! temp_file=$(mktemp); then log_error "Failed to create temp file."; return 1; fi
timestamp=$(date +%s); cache_busted_url="${file_url}?v=${timestamp}&nocache=$(date +%s%N 2>/dev/null || echo "$RANDOM")"
log_verbose "Downloading from (cache-busted): $cache_busted_url"
local curl_cmd_args=( --fail -sL -o "$temp_file" -H "Cache-Control: no-cache, no-store, max-age=0, must-revalidate" -H "Pragma: no-cache" -H "Expires: 0" "$cache_busted_url")
if ! curl "${curl_cmd_args[@]}"; then log_error "Failed to download from '$file_url' (curl exit: $?). Temp: $temp_file"; return 1; fi
# Check if the file is a shell script and contains expected markers
if [[ "$local_path" == *".sh" ]]; then
# Look for a shebang or version markers for validation
if ! grep -qE "^#!/bin/bash|^#!/usr/bin/env bash" "$temp_file" && \
! grep -qE "^# LibVersion:" "$temp_file" && \
! grep -qE "^# Version:" "$temp_file"; then
log_warning "Downloaded file '$temp_file' for '$local_path' may not be valid script."
fi
fi
if mv "$temp_file" "$local_path"; then
if [[ "$local_path" == *".sh" ]]; then chmod +x "$local_path"; fi
log_success "File '$local_path' downloaded."; return 0
else log_error "Failed to move temp to '$local_path' (mv exit $?). Content at $temp_file"; return 1; fi
}
ensure_library_loaded() {
local lib_key="$1"; IFS=' ' read -r lib_filename lib_url_var_name lib_version_var_name lib_version_grep_pattern <<< "${LIBRARIES_CONFIG[$lib_key]}"
local lib_path="${LIB_DIR}/${lib_filename}"; local lib_url="${!lib_url_var_name}"
log_verbose "Ensuring library '$lib_filename' is loaded..."
if [[ ! -d "$LIB_DIR" ]]; then log_info "Creating lib dir: $LIB_DIR"; if ! mkdir -p "$LIB_DIR"; then log_error "Failed to create '$LIB_DIR'."; exit 1; fi; fi
if [[ ! -f "$lib_path" ]]; then
log_info "Library '$lib_filename' not found. Downloading..."
if ! download_file "$lib_url" "$lib_path"; then log_error "Failed to download '$lib_filename'."; exit 1; fi
fi
if [[ -f "$lib_path" ]]; then
# shellcheck source=/dev/null
source "$lib_path"; log_verbose "Library '$lib_filename' sourced."
local current_lib_version=$(get_local_file_version "$lib_path" "$lib_version_grep_pattern" || echo "0.0.0-local")
declare -g "$lib_version_var_name=$current_lib_version"; log_verbose "$lib_filename version: ${!lib_version_var_name}"
else log_error "'$lib_filename' not found after download attempt."; exit 1; fi
}
for lib_key in "${!LIBRARIES_CONFIG[@]}"; do
ensure_library_loaded "$lib_key"
done
check_and_prompt_script_update() {
log_info "Checking for updates to $SCRIPT_NAME..."
local remote_version
remote_version=$(get_remote_file_version "$SCRIPT_RAW_URL" "^# Version:" || true)
if [[ -z "$remote_version" ]]; then log_warning "Update check for $SCRIPT_NAME failed: no remote version."; return 1; fi
log_verbose "Current $SCRIPT_NAME version: $SCRIPT_CURRENT_VERSION, Remote version: $remote_version"
local comparison_result
if compare_versions "$SCRIPT_CURRENT_VERSION" "$remote_version"; then
comparison_result=0
else
comparison_result=$?
fi
log_verbose "Version comparison result: $comparison_result (0: remote newer, 1: equal, 2: local newer)"
if [[ "$comparison_result" -eq 0 ]]; then # Current < Remote
log_success "A new version ($remote_version) of $SCRIPT_NAME is available! (Current: $SCRIPT_CURRENT_VERSION)"
read -r -p "Do you want to download and install it now? (y/N): " choice
if [[ "$choice" =~ ^[Yy]$ ]]; then
if perform_main_script_update "$remote_version"; then
log_success "$SCRIPT_NAME updated successfully. Please re-run: $0 $*"; exit 0
else log_error "Update process for $SCRIPT_NAME failed."; return 1; fi
else log_info "Update for $SCRIPT_NAME skipped by user."; return 2; fi
elif [[ "$comparison_result" -eq 1 ]]; then # Current == Remote
log_info "$SCRIPT_NAME is already the latest version ($SCRIPT_CURRENT_VERSION)."
return 0
elif [[ "$comparison_result" -eq 2 ]]; then # Current > Remote
log_warning "Your current $SCRIPT_NAME version ($SCRIPT_CURRENT_VERSION) seems newer than remote ($remote_version)."
return 0
else
log_error "Unknown comparison_result ($comparison_result) from version comparison for $SCRIPT_NAME."
return 1
fi
log_error "Fallback return from check_and_prompt_script_update - logic error." # Should not be reached
return 1
}
perform_main_script_update() {
local new_version=$1; log_info "Attempting to update $SCRIPT_NAME to version $new_version..."
local script_path="${SCRIPT_DIR}/${SCRIPT_NAME}"; local new_script_temp_path
if ! new_script_temp_path=$(mktemp); then log_error "Failed to create temp file for update."; return 1; fi
if ! download_file "$SCRIPT_RAW_URL" "$new_script_temp_path"; then log_error "Failed to download new $SCRIPT_NAME."; rm -f "$new_script_temp_path"; return 1; fi
local downloaded_version=$(get_local_file_version "$new_script_temp_path" "^# Version:" || true)
if [[ -z "$downloaded_version" ]]; then log_error "Could not extract version from downloaded $SCRIPT_NAME."; rm -f "$new_script_temp_path"; return 1; fi
if [[ "$downloaded_version" != "$new_version" ]]; then
log_warning "Downloaded $SCRIPT_NAME version ($downloaded_version) mismatch expected ($new_version)."
local comp_res; if compare_versions "$new_version" "$downloaded_version"; then comp_res=0; else comp_res=$?; fi
if [[ "$comp_res" -eq 2 ]]; then log_error "Downloaded $SCRIPT_NAME older than expected."; rm -f "$new_script_temp_path"; return 1; fi
fi
log_verbose "New version of $SCRIPT_NAME ($downloaded_version) downloaded to $new_script_temp_path. Replacing $script_path..."
if mv "$new_script_temp_path" "$script_path"; then chmod +x "$script_path"; return 0;
else log_error "Failed to replace $SCRIPT_NAME. New version at $new_script_temp_path"; return 1; fi
}
check_and_prompt_library_update() {
local lib_key="$1"; IFS=' ' read -r lib_filename lib_url_var_name lib_version_var_name lib_version_grep_pattern <<< "${LIBRARIES_CONFIG[$lib_key]}"
local lib_path="${LIB_DIR}/${lib_filename}"; local lib_url="${!lib_url_var_name}"; local current_lib_version_val="${!lib_version_var_name}"
log_info "Checking for updates to library '$lib_filename'..."
local remote_lib_version=$(get_remote_file_version "$lib_url" "$lib_version_grep_pattern" || true)
if [[ -z "$remote_lib_version" ]]; then log_warning "Update check for '$lib_filename' failed."; return 1; fi
log_verbose "Current '$lib_filename' version: $current_lib_version_val, Remote version: $remote_lib_version"
local comparison_result; if compare_versions "$current_lib_version_val" "$remote_lib_version"; then comparison_result=0; else comparison_result=$?; fi
log_verbose "Library '$lib_filename' version comparison result: $comparison_result"
if [[ "$comparison_result" -eq 0 ]]; then
log_success "New version ($remote_lib_version) of '$lib_filename' available! (Current: $current_lib_version_val)"
read -r -p "Download and install? (y/N): " choice
if [[ "$choice" =~ ^[Yy]$ ]]; then
if perform_library_update "$lib_key" "$remote_lib_version"; then
log_success "'$lib_filename' updated."; declare -g "$lib_version_var_name=$remote_lib_version"
else log_error "Update for '$lib_filename' failed."; fi
else log_info "Update for '$lib_filename' skipped."; fi
elif [[ "$comparison_result" -eq 1 ]]; then log_info "'$lib_filename' is latest ($current_lib_version_val)."
elif [[ "$comparison_result" -eq 2 ]]; then log_warning "Current '$lib_filename' ($current_lib_version_val) > remote ($remote_lib_version)."
else log_error "Unknown comparison_result ($comparison_result) for '$lib_filename'."; fi
return 0
}
perform_library_update() {
local lib_key="$1"; local new_version="$2"
IFS=' ' read -r lib_filename lib_url_var_name _ lib_version_grep_pattern <<< "${LIBRARIES_CONFIG[$lib_key]}"
local lib_path="${LIB_DIR}/${lib_filename}"; local lib_url="${!lib_url_var_name}"
log_info "Updating '$lib_filename' to $new_version..."
if ! download_file "$lib_url" "$lib_path"; then log_error "Failed to download '$lib_filename'."; return 1; fi
local downloaded_version=$(get_local_file_version "$lib_path" "$lib_version_grep_pattern" || true)
if [[ -z "$downloaded_version" ]]; then log_error "No version in new '$lib_filename'."; return 1; fi
if [[ "$downloaded_version" != "$new_version" ]]; then
log_warning "Downloaded '$lib_filename' version ($downloaded_version) != expected ($new_version)."
local comp_res; if compare_versions "$new_version" "$downloaded_version"; then comp_res=0; else comp_res=$?; fi
if [[ "$comp_res" -eq 2 ]]; then log_error "Downloaded '$lib_filename' older. Failed."; return 1; fi
fi
return 0
}
DEFAULT_TALOS_VERSION="v1.10.4"
DEFAULT_IMAGE_TYPE="metal-amd64"
SCHEMATIC_ID=""
TALOS_VERSION="$DEFAULT_TALOS_VERSION"
IMAGE_TYPE="$DEFAULT_IMAGE_TYPE"
FORCE_MODE=false
PROXMOX_STORAGE=""
ACTION=""
usage() {
echo "Usage: $SCRIPT_NAME --schematic-id <id> [OPTIONS]" >&2
echo " $SCRIPT_NAME --id <id> [OPTIONS]" >&2
echo " $SCRIPT_NAME update [--verbose]" >&2; echo "" >&2
echo "Required Arguments for download:" >&2
echo " --schematic-id <id>, --id <id> Talos schematic ID (64-char hex)" >&2; echo "" >&2
echo "Optional Arguments for download:" >&2
echo " --version <version> Talos version (default: $DEFAULT_TALOS_VERSION)" >&2
echo " --image-type <type> Image type (default: $DEFAULT_IMAGE_TYPE)" >&2
echo " --force Overwrite existing ISO file" >&2
echo " --storage <storage> Proxmox storage (default: auto-detect)" >&2; echo "" >&2
echo "Other Actions:" >&2
echo " update Check for updates to this script and its libraries." >&2
echo " --verbose Enable verbose output during update." >&2; echo "" >&2
echo "Examples:" >&2
echo " $SCRIPT_NAME --id ce4c...c7515" >&2
echo " $SCRIPT_NAME --id ce4c...c7515 --version v1.7.4" >&2
echo " $SCRIPT_NAME update --verbose" >&2
exit 1
}
if [[ "${1:-}" == "update" ]]; then
ACTION="update"; shift
if [[ "${1:-}" == "--verbose" ]]; then VERBOSE_FLAG="true"; log_verbose "Verbose mode enabled for update process."; shift; fi
else
if [[ $# -eq 0 ]]; then usage; fi
_idx=0; TALOS_VERSION="$DEFAULT_TALOS_VERSION"; IMAGE_TYPE="$DEFAULT_IMAGE_TYPE"; FORCE_MODE=false; PROXMOX_STORAGE=""; SCHEMATIC_ID=""
while [[ $_idx -lt $# ]]; do
_current_arg="${!((_idx + 1))}"; _next_arg="${!((_idx + 2))}"
case "$_current_arg" in
--schematic-id|--id) if [[ -z "$_next_arg" ]] || [[ "$_next_arg" == --* ]]; then log_error "$_current_arg needs value."; usage; fi; SCHEMATIC_ID="$_next_arg"; _idx=$((_idx + 1)) ;;
--version) if [[ -z "$_next_arg" ]] || [[ "$_next_arg" == --* ]]; then log_error "$_current_arg needs value."; usage; fi; TALOS_VERSION="$_next_arg"; _idx=$((_idx + 1)) ;;
--image-type) if [[ -z "$_next_arg" ]] || [[ "$_next_arg" == --* ]]; then log_error "$_current_arg needs value."; usage; fi; IMAGE_TYPE="$_next_arg"; _idx=$((_idx + 1)) ;;
--force) FORCE_MODE=true ;;
--storage) if [[ -z "$_next_arg" ]] || [[ "$_next_arg" == --* ]]; then log_error "$_current_arg needs value."; usage; fi; PROXMOX_STORAGE="$_next_arg"; _idx=$((_idx + 1)) ;;
-h|--help) usage ;;
*) log_error "Unknown option: $_current_arg"; usage ;;
esac; _idx=$((_idx + 1))
done; ACTION="download"
fi
if [[ "$ACTION" == "update" ]]; then
check_and_prompt_script_update; update_status_main_script=$?
if [[ "$update_status_main_script" -eq 1 ]]; then log_error "Main script update failed."; exit 1;
elif [[ "$update_status_main_script" -eq 2 ]]; then log_info "Main script update skipped."; fi
log_info "Proceeding to check for library updates..."
for lib_key_for_update in "${!LIBRARIES_CONFIG[@]}"; do check_and_prompt_library_update "$lib_key_for_update"; done
log_info "Update check process finished."; exit 0
fi
if [[ "$ACTION" == "download" ]]; then
if [[ -z "$SCHEMATIC_ID" ]]; then log_error "--schematic-id required."; usage; fi
if [[ ! "$SCHEMATIC_ID" =~ ^[a-f0-9]{64}$ ]]; then log_error "Invalid schematic ID format."; exit 1; fi
log_info "=== Talos Linux ISO Download Script ==="; log_info "Schematic ID: $SCHEMATIC_ID"; log_info "Version: $TALOS_VERSION"
log_info "Image Type: $IMAGE_TYPE"; if [[ "$FORCE_MODE" == "true" ]]; then log_info "Force mode enabled"; fi
log_info "======================================="
LOG_FILE="${SCRIPT_DIR}/talos_download_output.log"
if ! touch "$LOG_FILE" 2>/dev/null; then log_error "Cannot write to log file $LOG_FILE."; exit 1; fi
echo "$(date): Starting Talos ISO download - SID: $SCHEMATIC_ID, Ver: $TALOS_VERSION" > "$LOG_FILE"
preflight_checks() {
log_info "Performing preflight checks..."; local check_ok=true
for cmd_check in curl pvesm jq numfmt; do if ! command -v "$cmd_check" &> /dev/null; then log_error "'$cmd_check' not found."; check_ok=false; fi; done
if ! curl -s --connect-timeout 5 https://factory.talos.dev/ >/dev/null; then log_error "No connection to factory.talos.dev."; check_ok=false; fi
if [[ "$check_ok" == "false" ]]; then exit 1; fi; log_success "✓ Preflight checks passed."
}
get_storage_path() {
local storage_name=$1; log_info "Getting storage path for '$storage_name'..."
local storage_details=$(pvesh get "/storage/${storage_name}" --output-format=json 2>/dev/null || { log_error "Failed to get details for '$storage_name'."; return 1; })
local storage_physical_path=$(echo "$storage_details" | jq -r '.path // .export // ""' 2>/dev/null)
if [[ -z "$storage_physical_path" ]]; then log_error "No physical path for '$storage_name'."; log_verbose "Details: $storage_details"; exit 1; fi
local iso_dir_path="${storage_physical_path}/template/iso"
if [[ ! -d "$iso_dir_path" ]]; then
log_info "Attempting to create ISO dir: $iso_dir_path"
if ! mkdir -p "$iso_dir_path"; then log_error "Failed to create ISO dir: $iso_dir_path"; exit 1; fi
log_success "Created ISO dir: $iso_dir_path"
fi; log_success "✓ Storage ISO path: $iso_dir_path"; echo "$iso_dir_path"
}
verify_schematic() {
local sid=$1 ver=$2 img_type=$3; log_info "Verifying schematic $sid / $ver / $img_type..."
local test_url="https://factory.talos.dev/image/${sid}/${ver}/${img_type}.iso"
if ! curl -s --head --fail "$test_url" >/dev/null 2>&1; then log_error "Schematic/version/type not found: $test_url"; exit 1; fi
log_success "✓ Schematic verified."
}
download_iso_file() {
local sid=$1 ver=$2 store_path=$3 force=$4 img_type=$5
local download_url="https://factory.talos.dev/image/${sid}/${ver}/${img_type}.iso"; local filename=$(basename "$download_url")
local full_path="${store_path}/${filename}"; local id_file="${full_path}.id"
log_info "Download URL: $download_url"; log_info "Target file: $full_path"
if [[ -f "$full_path" && "$force" != "true" ]]; then log_error "File exists: $full_path. Use --force."; exit 1; fi
if [[ -f "$full_path" && "$force" == "true" ]]; then log_warning "Overwriting: $full_path"; echo "$(date): Overwriting: $full_path" >> "$LOG_FILE"; fi
log_info "Starting ISO download..."; echo "$(date): Downloading $download_url to $full_path" >> "$LOG_FILE"; printf "\033[?25l"
local curl_dl_args=(-L --fail --progress-bar -o "$full_path" "$download_url")
if ! curl "${curl_dl_args[@]}"; then restore_cursor; echo ""; log_error "Download failed."; [[ -f "$full_path" ]] && rm -f "$full_path"; exit 1; fi
restore_cursor; echo ""; log_success "✓ Download completed."
local file_size
if ! file_size=$(stat -f%z "$full_path" 2>/dev/null); then
if ! file_size=$(stat -c%s "$full_path" 2>/dev/null); then
log_warning "Could not determine file size for $full_path. Defaulting to 0."
file_size="0"
fi
fi
if [[ "$file_size" -lt 1000000 ]]; then log_error "File too small ($file_size B). Failed?"; rm -f "$full_path"; exit 1; fi
log_info "File size: $(numfmt --to=iec-i --suffix=B "$file_size")"; echo "$(date): Downloaded. Size: $file_size B" >> "$LOG_FILE"
log_info "Creating ID file: $id_file"; echo "$sid" > "$id_file"
if [[ $? -eq 0 ]]; then log_success "✓ ID saved."; echo "$(date): ID saved to $id_file" >> "$LOG_FILE";
else log_warning "No ID file $id_file"; echo "$(date): Warn: no ID file $id_file" >> "$LOG_FILE"; fi; echo "$full_path"
}
check_iso_in_proxmox() {
local storage_name=$1 iso_filename_to_check=$2; log_info "Verifying ISO '$iso_filename_to_check' in Proxmox '$storage_name'..."
local retries=3 delay=3; for attempt in $(seq 1 $retries); do
if pvesm list "$storage_name" --content iso 2>/dev/null | grep -q "${storage_name}:iso/${iso_filename_to_check}"; then
log_success "✓ ISO '$iso_filename_to_check' visible in Proxmox '$storage_name'."; return 0; fi
if [[ $attempt -lt $retries ]]; then log_verbose "Attempt $attempt: ISO not visible. Retrying..."; sleep $delay; fi
done; log_warning "ISO '$iso_filename_to_check' not visible in Proxmox '$storage_name' after $retries attempts."; return 1
}
preflight_checks
FINAL_PROXMOX_STORAGE_NAME=""
if [[ -n "$PROXMOX_STORAGE" ]]; then
FINAL_PROXMOX_STORAGE_NAME="$PROXMOX_STORAGE"
log_info "Using specified Proxmox storage: $FINAL_PROXMOX_STORAGE_NAME"
else
# Use a subshell to avoid affecting the main shell's pipefail state
_detect_result=$(
set +o pipefail
detect_iso_storage
echo "EXIT_CODE:$?"
)
_detected_storage_output=$(echo "$_detect_result" | grep -v '^EXIT_CODE:')
_detect_exit_status=$(echo "$_detect_result" | grep '^EXIT_CODE:' | cut -d: -f2)
if [[ $_detect_exit_status -ne 0 ]] || [[ -z "$_detected_storage_output" ]] || [[ "$_detected_storage_output" == *"Error:"* ]]; then
log_error "Failed to auto-detect ISO storage."
log_verbose "Output: $_detected_storage_output"
exit 1
fi
FINAL_PROXMOX_STORAGE_NAME=$(echo "$_detected_storage_output" | tail -n 1)
log_info "Auto-detected Proxmox ISO storage: $FINAL_PROXMOX_STORAGE_NAME"
fi
TARGET_STORAGE_PHYSICAL_PATH=$(get_storage_path "$FINAL_PROXMOX_STORAGE_NAME")
verify_schematic "$SCHEMATIC_ID" "$TALOS_VERSION" "$IMAGE_TYPE"
DOWNLOADED_ISO_FULL_PATH=$(download_iso_file "$SCHEMATIC_ID" "$TALOS_VERSION" "$TARGET_STORAGE_PHYSICAL_PATH" "$FORCE_MODE" "$IMAGE_TYPE")
ISO_FILENAME_ONLY=$(basename "$DOWNLOADED_ISO_FULL_PATH")
check_iso_in_proxmox "$FINAL_PROXMOX_STORAGE_NAME" "$ISO_FILENAME_ONLY"
log_success "===== Talos ISO Download Complete ====="
log_info " Schematic ID: $SCHEMATIC_ID"; log_info " Version: $TALOS_VERSION"; log_info " Image Type: $IMAGE_TYPE"
log_info " Storage: $FINAL_PROXMOX_STORAGE_NAME"; log_info " Final path: $DOWNLOADED_ISO_FULL_PATH"
log_info ""; log_info "ISO should be available in Proxmox."; echo "$(date): Talos ISO download complete: $DOWNLOADED_ISO_FULL_PATH" >> "$LOG_FILE"
exit 0
fi
log_error "Invalid script state or unknown action: '$ACTION'."
usage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment