Skip to content

Instantly share code, notes, and snippets.

@QNimbus
Last active June 14, 2025 09:23
Show Gist options
  • Save QNimbus/f6f3253e66b9747034be12d0e79d8afe to your computer and use it in GitHub Desktop.
Save QNimbus/f6f3253e66b9747034be12d0e79d8afe to your computer and use it in GitHub Desktop.
Proxmox k3s destroy script #proxmox #shell #scripts
#!/usr/bin/env bash
# To download: `curl -O https://gist.githubusercontent.com/QNimbus/f6f3253e66b9747034be12d0e79d8afe/raw/destroy_vms.sh`
# To run: `curl -s https://gist.githubusercontent.com/QNimbus/f6f3253e66b9747034be12d0e79d8afe/raw/destroy_vms.sh > destroy_vms.sh && chmod +x destroy_vms.sh && ./destroy_vms.sh`
# ====================================================
# K3S VM Destruction Script
# ====================================================
#
# This script automates the destruction of K3s VMs on Proxmox VE cluster.
# It performs the following operations:
# 1. Stops running VMs safely
# 2. Destroys server, worker, and storage VMs
# 3. Provides confirmation prompts for safety
#
# Requirements:
# - Proxmox VE with qm and pvesh commands available
# - Appropriate permissions to destroy VMs
#
# Usage: ./destroy_vms.sh [--vmid <id1,id2,...>] [--force]
#
# Output: Creates a log file (vm_destruction_output.log) with detailed operation logs
# ====================================================
# Function to display usage information
usage() {
echo "Usage: $0 [--vmid <id1,id2,...>] [--force] [--destroy | --reset-disk]"
echo ""
echo " --vmid Comma-separated list of VM IDs to process (optional, defaults to all K3s VMs)"
echo " --force Skip confirmation prompt (use with caution!)"
echo " --destroy Destroy VMs completely (REQUIRED for destruction)"
echo " --reset-disk Reset/format/erase the primary hard disk of VMs"
echo ""
echo "Note: You must specify either --destroy or --reset-disk to perform any action."
echo ""
echo "Examples:"
echo " $0 # Display usage (no action without explicit flag)"
echo " $0 --destroy # Destroy all K3s VMs (with confirmation)"
echo " $0 --vmid 1211,1221,1231 --destroy # Destroy only specific VMs (with confirmation)"
echo " $0 --destroy --force # Destroy all K3s VMs without confirmation"
echo " $0 --reset-disk # Reset primary disk of all K3s VMs (with confirmation)"
echo " $0 --vmid 1211,1221 --reset-disk # Reset primary disk of specific VMs"
exit 1
}
# Parse and validate command-line arguments
VM_IDS=""
FORCE_MODE=false
RESET_DISK_MODE=false
DESTROY_MODE=false
while [[ $# -gt 0 ]]; do
case $1 in
--vmid)
if [[ -z "$2" ]]; then
echo "Error: --vmid flag requires a comma-separated list of VM IDs" >&2
exit 1
fi
VM_IDS="$2"
shift 2
;;
--force)
FORCE_MODE=true
shift
;;
--reset-disk)
RESET_DISK_MODE=true
shift
;;
--destroy)
DESTROY_MODE=true
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
# Validate that either --destroy or --reset-disk is specified
if [[ "$DESTROY_MODE" != "true" && "$RESET_DISK_MODE" != "true" ]]; then
echo "Error: You must specify either --destroy or --reset-disk to perform any action." >&2
echo ""
usage
fi
# Validate that both modes are not specified simultaneously
if [[ "$DESTROY_MODE" == "true" && "$RESET_DISK_MODE" == "true" ]]; then
echo "Error: Cannot specify both --destroy and --reset-disk. Choose one operation." >&2
exit 1
fi
# Exit immediately if a command exits with a non-zero status
set -euo pipefail
echo "=== K3S VM Management Script ==="
if [ "$RESET_DISK_MODE" = true ]; then
echo "This script will RESET/FORMAT the primary disks of K3s VMs on Proxmox nodes"
elif [ "$DESTROY_MODE" = true ]; then
echo "This script will DESTROY K3s VMs on Proxmox nodes"
fi
echo "Script will exit on any error"
echo "==============================="
# Check if running in a non-interactive shell without force mode
if [[ ! -t 0 && "$FORCE_MODE" != "true" ]]; then
echo "ERROR: This script requires an interactive terminal for confirmation."
echo "You appear to be running this script via pipe (e.g., curl | bash) which doesn't support interactive prompts."
echo ""
echo "Instead, please use one of these methods:"
echo ""
echo "1. Download and run the script directly:"
echo " curl -s https://gist.githubusercontent.com/QNimbus/f6f3253e66b9747034be12d0e79d8afe/raw/destroy_vms.sh > destroy_vms.sh"
echo " chmod +x destroy_vms.sh"
echo " ./destroy_vms.sh"
echo ""
echo "2. Use the --force flag to bypass confirmation (USE WITH CAUTION):"
echo " curl -s https://gist.githubusercontent.com/QNimbus/f6f3253e66b9747034be12d0e79d8afe/raw/destroy_vms.sh | bash -s -- --force"
echo ""
exit 1
fi
# Function for preflight checks
#
# Verifies that required Proxmox tools (qm and pvesh) are available
# before proceeding with VM destruction.
#
# Arguments: None
# Returns: Exits with status 1 if required tools are not found
preflight_checks() {
echo "Performing preflight checks..."
if ! command -v qm &> /dev/null; then
echo "Error: 'qm' command not found. Please ensure Proxmox VE CLI tools are installed." >&2
exit 1
fi
if ! command -v pvesh &> /dev/null; then
echo "Error: 'pvesh' command not found. Please ensure Proxmox VE API client is installed." >&2
exit 1
fi
if ! command -v jq &> /dev/null; then
echo "Error: 'jq' command not found. Please install jq for JSON parsing." >&2
exit 1
fi
echo "✓ Required tools are available"
}
# Function to restore cursor visibility
#
# Ensures the terminal cursor is visible, typically called
# after operations that might hide the cursor.
#
# Arguments: None
# Returns: None
restore_cursor() {
printf "\033[?25h" # Show cursor
}
# Ensure cursor is restored on script exit
trap restore_cursor EXIT
# Function to display spinner while command executes
#
# Creates a visual spinner animation to indicate a long-running
# process is executing in the background.
#
# Arguments:
# $1 - PID of the background process to monitor
#
# Returns: None
spinner() {
local pid=$1
local delay=0.1
local spinstr='|/-\'
printf "\033[?25l" # Hide cursor
while kill -0 $pid 2>/dev/null; do
local temp=${spinstr#?}
printf " [%c] " "$spinstr"
local spinstr=$temp${spinstr%"$temp"}
sleep $delay
printf "\b\b\b\b\b\b"
done
printf " \b\b\b\b"
printf "\033[?25h" # Show cursor
}
# Function to run command with spinner and log output
#
# Executes a command with a visual spinner, logs the command and its output,
# and provides status feedback when complete.
#
# Arguments:
# $1 - Description of the command being run
# $2 - Command to execute
#
# Returns: Exits with status 1 if command fails
run_with_spinner() {
local desc=$1
local cmd=$2
printf "%-50s" "$desc"
echo "$(date): $desc - COMMAND: $cmd" >> "$LOG_FILE"
bash -c "$cmd" >> "$LOG_FILE" 2>&1 &
local pid=$!
spinner $pid
wait $pid
local status=$?
if [ $status -eq 0 ]; then
echo "[DONE]"
else
echo "[FAILED] - Check $LOG_FILE for details"
exit 1
fi
}
# Function to get the node where a VM is located
#
# Queries the Proxmox cluster to determine which node hosts a specific VM.
#
# Arguments:
# $1 - VM ID to locate
#
# Returns: Outputs the node name, or empty string if VM not found
get_vm_node() {
local vm_id=$1
local node_info=$(pvesh get /cluster/resources --type vm --output-format=json 2>/dev/null | jq -r ".[] | select(.vmid == $vm_id) | .node" 2>/dev/null || echo "")
echo "$node_info"
}
# Function to get all K3s VM IDs from Proxmox cluster
#
# Scans the entire Proxmox cluster for VMs with K3s tags (k3s-server, k3s-agent, k3s-storage)
# and returns their VM IDs. This replaces the hardcoded VM ID list with dynamic discovery.
#
# Arguments: None
# Returns: Outputs space-separated list of all K3s VM IDs found in the cluster
get_all_k3s_vm_ids() {
echo "Scanning Proxmox cluster for K3s VMs..." >&2
# Get all VMs from the cluster and filter by K3s tags
local k3s_vm_ids=$(pvesh get /cluster/resources --type vm --output-format=json 2>/dev/null | \
jq -r '.[] | select(.tags // "" | test("k3s-(server|agent|storage)")) | .vmid' 2>/dev/null | \
sort -n | tr '\n' ' ' || echo "")
if [[ -z "$k3s_vm_ids" ]]; then
echo "No K3s VMs found in the cluster (no VMs with k3s-server, k3s-agent, or k3s-storage tags)" >&2
return 0
fi
# Remove trailing space and output
k3s_vm_ids=$(echo "$k3s_vm_ids" | sed 's/[[:space:]]*$//')
echo "Found K3s VMs: $k3s_vm_ids" >&2
echo "$k3s_vm_ids"
}
# Function to get VM name and role from Proxmox
#
# Queries Proxmox to get the actual VM name and determines role from tags.
# This provides more accurate information than the hardcoded naming convention.
#
# Arguments:
# $1 - VM ID
#
# Returns: Outputs the VM name and role (e.g., "k3s-server-001 (server)")
get_vm_info_from_proxmox() {
local vm_id=$1
# Get VM info from Proxmox
local vm_info=$(pvesh get /cluster/resources --type vm --output-format=json 2>/dev/null | \
jq -r ".[] | select(.vmid == $vm_id) | {name: .name, tags: .tags}" 2>/dev/null)
if [[ -z "$vm_info" ]]; then
echo "k3s-vm-$vm_id (unknown)"
return
fi
local vm_name=$(echo "$vm_info" | jq -r '.name // empty' 2>/dev/null)
local vm_tags=$(echo "$vm_info" | jq -r '.tags // empty' 2>/dev/null)
# Determine role from tags
local role="unknown"
if [[ "$vm_tags" =~ k3s-server ]]; then
role="server"
elif [[ "$vm_tags" =~ k3s-agent ]]; then
role="agent"
elif [[ "$vm_tags" =~ k3s-storage ]]; then
role="storage"
fi
# Use VM name if available, otherwise generate from ID
if [[ -n "$vm_name" ]]; then
echo "$vm_name ($role)"
else
echo "k3s-vm-$vm_id ($role)"
fi
}
# Function to check SSH connectivity to a node
#
# Verifies that SSH connection to a Proxmox node is working
# before attempting to execute remote commands.
#
# Arguments:
# $1 - Name of the Proxmox node to check
#
# Returns: Exits with status 1 if SSH connection fails
check_ssh_connectivity() {
local node=$1
if ! ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 "$node" "echo 'SSH connection successful'" >/dev/null 2>&1; then
echo "Error: Cannot establish SSH connection to node $node" >&2
exit 1
fi
}
# Function to safely stop and destroy a VM with checks
#
# Stops a running VM (if running) and then destroys it, with safety checks
# to handle VMs that don't exist or are already stopped. Now handles
# distributed VMs by connecting to the appropriate node via SSH.
#
# Arguments:
# $1 - VM ID to destroy
# $2 - VM name for logging purposes
#
# Returns: 0 if successful or VM doesn't exist
# Exits with status 1 if destruction fails
destroy_vm_with_check() {
local vm_id=$1
local vm_name=$2
local desc="Destroying ${vm_name} (ID: ${vm_id})..."
printf "%-50s" "$desc"
echo "$(date): $desc - Locating VM $vm_id" >> "$LOG_FILE"
# Find which node the VM is on
local vm_node=$(get_vm_node $vm_id)
if [ -z "$vm_node" ]; then
echo "[SKIPPED] VM $vm_id does not exist"
echo "$(date): $desc - VM $vm_id does not exist. Skipping." >> "$LOG_FILE"
return 0
fi
echo "$(date): $desc - VM $vm_id found on node $vm_node" >> "$LOG_FILE"
# Check SSH connectivity to the node
check_ssh_connectivity "$vm_node"
# Check VM status and stop if running via SSH
local vm_status=$(ssh -o StrictHostKeyChecking=no "$vm_node" "qm status $vm_id" 2>/dev/null | awk '{print $2}' || echo "unknown")
if [ "$vm_status" = "running" ]; then
echo "$(date): $desc - VM $vm_id is running on $vm_node, stopping first" >> "$LOG_FILE"
ssh -o StrictHostKeyChecking=no "$vm_node" "qm stop $vm_id" >> "$LOG_FILE" 2>&1
sleep 3 # Give VM time to stop gracefully
fi
local cmd="ssh -o StrictHostKeyChecking=no $vm_node 'qm destroy $vm_id --purge'"
echo "$(date): $desc - COMMAND: $cmd" >> "$LOG_FILE"
bash -c "$cmd" >> "$LOG_FILE" 2>&1 &
local pid=$!
spinner $pid
wait $pid
local status=$?
if [ $status -eq 0 ]; then
echo "[DONE]"
else
echo "[FAILED] - Check $LOG_FILE for details"
exit 1
fi
}
# Function to wait for VM to be completely stopped
#
# Waits for a VM to reach 'stopped' status with timeout to ensure
# it's safe to perform disk operations.
#
# Arguments:
# $1 - VM ID
# $2 - Node where VM is located
# $3 - Timeout in seconds (optional, defaults to 30)
#
# Returns: 0 if VM is stopped, 1 if timeout or error
wait_for_vm_stopped() {
local vm_id=$1
local vm_node=$2
local timeout=${3:-30}
local elapsed=0
echo "$(date): Waiting for VM $vm_id to stop completely (timeout: ${timeout}s)..." >> "$LOG_FILE"
while [ $elapsed -lt $timeout ]; do
local vm_status=$(ssh -o StrictHostKeyChecking=no "$vm_node" "qm status $vm_id" 2>/dev/null | awk '{print $2}' || echo "unknown")
if [ "$vm_status" = "stopped" ]; then
echo "$(date): VM $vm_id is now stopped" >> "$LOG_FILE"
return 0
fi
sleep 2
elapsed=$((elapsed + 2))
done
echo "$(date): Timeout waiting for VM $vm_id to stop" >> "$LOG_FILE"
return 1
}
# Function to get VM disk configuration from Proxmox
#
# Queries Proxmox to get the disk configuration for a VM,
# identifying the primary boot disk (usually ide0, scsi0, or virtio0).
#
# Arguments:
# $1 - VM ID
# $2 - Node where VM is located
#
# Returns: Outputs the primary disk identifier (e.g., "scsi0", "virtio0")
get_vm_primary_disk() {
local vm_id=$1
local vm_node=$2
# Get VM configuration and find the primary disk
local disk_info=$(ssh -o StrictHostKeyChecking=no "$vm_node" "qm config $vm_id" 2>/dev/null | grep -E '^(ide0|scsi0|virtio0|sata0):' | head -1 | cut -d: -f1)
if [[ -z "$disk_info" ]]; then
echo "No primary disk found for VM $vm_id" >&2
return 1
fi
echo "$disk_info"
}
# Function to parse disk configuration and extract storage and size
#
# Parses the disk configuration line to extract storage pool and disk size.
# Handles various Proxmox disk formats.
#
# Arguments:
# $1 - Full disk configuration line (e.g., "scsi0: vmdata:vm-1211-disk-0,size=10G")
#
# Returns: Outputs "storage:size" format (e.g., "vmdata:10G")
parse_disk_config() {
local disk_config="$1"
# Extract the part after the colon and first comma
# Format examples:
# scsi0: vmdata:vm-1211-disk-0,size=10G
# scsi0: local-lvm:vm-1211-disk-0,size=32G
local config_part=$(echo "$disk_config" | cut -d: -f2- | sed 's/^[[:space:]]*//')
# Extract storage (part before first colon in config_part)
local storage=$(echo "$config_part" | cut -d: -f1)
# Extract size (look for size= parameter)
local size=$(echo "$config_part" | sed -n 's/.*size=\([^,]*\).*/\1/p')
if [[ -z "$storage" || -z "$size" ]]; then
echo "Failed to parse storage ($storage) or size ($size) from: $disk_config" >&2
return 1
fi
echo "$storage:$size"
}
# Function to reset/format VM primary disk
#
# Stops the VM if running, waits for complete shutdown, removes the primary disk,
# and recreates it with the same size but completely empty/formatted.
#
# Arguments:
# $1 - VM ID to reset disk
# $2 - VM name for logging purposes
#
# Returns: 0 if successful, exits with status 1 if reset fails
reset_vm_disk() {
local vm_id=$1
local vm_name=$2
local desc="Resetting disk for ${vm_name} (ID: ${vm_id})..."
printf "%-50s" "$desc"
echo "$(date): $desc - Locating VM $vm_id" >> "$LOG_FILE"
# Find which node the VM is on
local vm_node=$(get_vm_node $vm_id)
if [ -z "$vm_node" ]; then
echo "[SKIPPED] VM $vm_id does not exist"
echo "$(date): $desc - VM $vm_id does not exist. Skipping." >> "$LOG_FILE"
return 0
fi
echo "$(date): $desc - VM $vm_id found on node $vm_node" >> "$LOG_FILE"
# Check SSH connectivity to the node
check_ssh_connectivity "$vm_node"
# Check VM status and stop if running
local vm_status=$(ssh -o StrictHostKeyChecking=no "$vm_node" "qm status $vm_id" 2>/dev/null | awk '{print $2}' || echo "unknown")
if [ "$vm_status" = "running" ]; then
echo "$(date): $desc - VM $vm_id is running on $vm_node, stopping first" >> "$LOG_FILE"
ssh -o StrictHostKeyChecking=no "$vm_node" "qm stop $vm_id" >> "$LOG_FILE" 2>&1
# Wait for VM to be completely stopped
if ! wait_for_vm_stopped "$vm_id" "$vm_node" 30; then
echo "[FAILED] - VM did not stop within timeout"
echo "$(date): $desc - VM $vm_id did not stop within timeout" >> "$LOG_FILE"
exit 1
fi
elif [ "$vm_status" != "stopped" ]; then
echo "[FAILED] - VM status is '$vm_status', expected 'stopped' or 'running'"
echo "$(date): $desc - VM $vm_id has unexpected status: $vm_status" >> "$LOG_FILE"
exit 1
fi
# Get primary disk information
local primary_disk=$(get_vm_primary_disk "$vm_id" "$vm_node")
if [[ -z "$primary_disk" ]]; then
echo "[FAILED] - Cannot identify primary disk"
echo "$(date): $desc - Failed to identify primary disk for VM $vm_id" >> "$LOG_FILE"
exit 1
fi
echo "$(date): $desc - Primary disk identified as $primary_disk" >> "$LOG_FILE"
# Get current disk configuration to preserve settings
local disk_config=$(ssh -o StrictHostKeyChecking=no "$vm_node" "qm config $vm_id | grep '^$primary_disk:'" 2>/dev/null)
if [[ -z "$disk_config" ]]; then
echo "[FAILED] - Cannot retrieve disk configuration"
echo "$(date): $desc - Failed to retrieve disk configuration for $primary_disk" >> "$LOG_FILE"
exit 1
fi
echo "$(date): $desc - Current disk config: $disk_config" >> "$LOG_FILE"
# Parse storage and size from disk configuration
local storage_size=$(parse_disk_config "$disk_config")
if [[ $? -ne 0 || -z "$storage_size" ]]; then
echo "[FAILED] - Cannot parse disk configuration"
echo "$(date): $desc - Failed to parse disk configuration: $disk_config" >> "$LOG_FILE"
exit 1
fi
echo "$(date): $desc - Parsed storage:size as: $storage_size" >> "$LOG_FILE"
# Create command to reset disk (remove and recreate)
local cmd="ssh -o StrictHostKeyChecking=no $vm_node 'qm set $vm_id --delete $primary_disk && qm set $vm_id --$primary_disk $storage_size'"
echo "$(date): $desc - COMMAND: $cmd" >> "$LOG_FILE"
bash -c "$cmd" >> "$LOG_FILE" 2>&1 &
local pid=$!
spinner $pid
wait $pid
local status=$?
if [ $status -eq 0 ]; then
echo "[DONE]"
echo "$(date): $desc - Successfully reset disk for VM $vm_id" >> "$LOG_FILE"
else
echo "[FAILED] - Check $LOG_FILE for details"
exit 1
fi
}
# Function to filter VM IDs based on provided list
#
# Filters the complete list of K3s VM IDs to only include those
# specified in the --vmid parameter.
#
# Arguments:
# $1 - Space-separated string of all available VM IDs
# $2 - Comma-separated string of requested VM IDs
#
# Returns: Outputs space-separated string of valid VM IDs
filter_vm_ids() {
local all_ids_str=$1
local requested_ids_str=$2
# Convert comma-separated to array
IFS=',' read -ra requested_ids <<< "$requested_ids_str"
# Convert space-separated to array
read -ra all_ids <<< "$all_ids_str"
local filtered_ids=()
for requested_id in "${requested_ids[@]}"; do
# Remove any whitespace
requested_id=$(echo "$requested_id" | xargs)
# Check if this ID exists in all_ids
for all_id in "${all_ids[@]}"; do
if [[ "$all_id" == "$requested_id" ]]; then
filtered_ids+=("$requested_id")
break
fi
done
done
# Output filtered IDs as space-separated string
echo "${filtered_ids[*]}"
}
# Function to get confirmation from user
#
# Prompts the user for confirmation before proceeding with VM destruction or disk reset.
# Provides a safety mechanism to prevent accidental operations.
# Dynamically shows only the VMs that will actually be affected.
#
# Arguments:
# $1 - Space-separated list of VM IDs that will be affected
#
# Returns: Exits with status 1 if user doesn't confirm
get_confirmation() {
local vm_ids_to_process=($1)
# Skip confirmation if in force mode
if [ "$FORCE_MODE" = true ]; then
if [ "$RESET_DISK_MODE" = true ]; then
echo "Force mode enabled - skipping confirmation for disk reset"
else
echo "Force mode enabled - skipping confirmation"
fi
return 0
fi
echo ""
if [ "$RESET_DISK_MODE" = true ]; then
echo "WARNING: This will RESET/FORMAT the primary disks of the following VMs:"
echo "All data on the primary disk will be PERMANENTLY LOST!"
else
echo "WARNING: This will PERMANENTLY DESTROY the following VMs:"
fi
# Group VMs by type for better display
local servers=()
local agents=()
local storage=()
local others=()
for vm_id in "${vm_ids_to_process[@]}"; do
local vm_info=$(get_vm_info_from_proxmox "$vm_id")
if [[ "$vm_info" =~ \(server\) ]]; then
servers+=("$vm_info")
elif [[ "$vm_info" =~ \(agent\) ]]; then
agents+=("$vm_info")
elif [[ "$vm_info" =~ \(storage\) ]]; then
storage+=("$vm_info")
else
others+=("$vm_info")
fi
done
# Display grouped VMs
if [[ ${#servers[@]} -gt 0 ]]; then
echo " Server VMs: ${servers[*]}"
fi
if [[ ${#agents[@]} -gt 0 ]]; then
echo " Agent VMs: ${agents[*]}"
fi
if [[ ${#storage[@]} -gt 0 ]]; then
echo " Storage VMs: ${storage[*]}"
fi
if [[ ${#others[@]} -gt 0 ]]; then
echo " Other VMs: ${others[*]}"
fi
echo ""
if [ "$RESET_DISK_MODE" = true ]; then
echo "This will erase all data on the primary disk of these VMs!"
echo "The VMs will remain but their disks will be completely empty!"
else
echo "This action CANNOT be undone!"
fi
echo ""
if [ "$RESET_DISK_MODE" = true ]; then
read -p "Are you absolutely sure you want to reset these VM disks? (type 'RESET' to confirm): " confirmation
if [ "$confirmation" != "RESET" ]; then
echo "Disk reset cancelled by user."
exit 1
fi
echo ""
echo "Proceeding with VM disk reset..."
else
read -p "Are you absolutely sure you want to proceed? (type 'DESTROY' to confirm): " confirmation
if [ "$confirmation" != "DESTROY" ]; then
echo "Destruction cancelled by user."
exit 1
fi
echo ""
echo "Proceeding with VM destruction..."
fi
}
# Execute preflight checks
preflight_checks
# Get all K3s VM IDs from Proxmox cluster
all_vm_ids_str=$(get_all_k3s_vm_ids)
all_vm_ids=($(echo "$all_vm_ids_str"))
# Check if any K3s VMs were found
if [[ ${#all_vm_ids[@]} -eq 0 || ( ${#all_vm_ids[@]} -eq 1 && -z "${all_vm_ids[0]}" ) ]]; then
echo "No K3s VMs found in the Proxmox cluster."
echo "VMs must be tagged with 'k3s-server', 'k3s-agent', or 'k3s-storage' to be managed by this script."
exit 0
fi
# Filter VM IDs if --vmid is provided
if [[ -n "$VM_IDS" ]]; then
filtered_vm_ids_str=$(filter_vm_ids "$all_vm_ids_str" "$VM_IDS")
filtered_vm_ids=($(echo "$filtered_vm_ids_str"))
# Check if any valid VM IDs were found
if [[ ${#filtered_vm_ids[@]} -eq 0 || ( ${#filtered_vm_ids[@]} -eq 1 && -z "${filtered_vm_ids[0]}" ) ]]; then
echo "Error: No valid VM IDs found in the provided list: $VM_IDS" >&2
echo "Valid K3s VM IDs are: ${all_vm_ids[*]}" >&2
exit 1
fi
if [ "$DESTROY_MODE" = true ]; then
echo "Filtering VMs to destroy: ${filtered_vm_ids[*]} (from list of ${#all_vm_ids[@]} total VMs)"
else
echo "Filtering VMs to reset disks: ${filtered_vm_ids[*]} (from list of ${#all_vm_ids[@]} total VMs)"
fi
all_vm_ids=("${filtered_vm_ids[@]}")
else
if [ "$DESTROY_MODE" = true ]; then
echo "Found ${#all_vm_ids[@]} VMs to destroy: ${all_vm_ids[*]}"
else
echo "Found ${#all_vm_ids[@]} VMs to reset disks: ${all_vm_ids[*]}"
fi
fi
# Get user confirmation with the actual VMs to be destroyed
get_confirmation "${all_vm_ids[*]}"
# Create output log file
LOG_FILE="vm_destruction_output.log"
if ! touch "$LOG_FILE" 2>/dev/null; then
echo "Error: Cannot write to log file $LOG_FILE. Check permissions or disk space." >&2
exit 1
fi
if [ "$RESET_DISK_MODE" = true ]; then
echo "$(date): Starting VM disk reset" > "$LOG_FILE"
else
echo "$(date): Starting VM destruction" > "$LOG_FILE"
fi
# Process VMs based on mode (destroy or reset disk)
if [ "$RESET_DISK_MODE" = true ]; then
echo "Resetting disks for ${#all_vm_ids[@]} VMs..."
for vm_id in "${all_vm_ids[@]}"; do
if [[ -n "$vm_id" ]]; then
vm_info=$(get_vm_info_from_proxmox "$vm_id")
vm_name=$(echo "$vm_info" | sed 's/ (.*)$//') # Extract just the name part
reset_vm_disk "$vm_id" "$vm_name"
fi
done
echo "===== VM Disk Reset Complete ====="
echo "All specified K3s VM disks have been reset successfully."
echo "$(date): VM Disk Reset Complete - All specified K3s VM primary disks have been reset successfully." >> "$LOG_FILE"
elif [ "$DESTROY_MODE" = true ]; then
# Destroy VMs dynamically based on the filtered list
echo "Destroying ${#all_vm_ids[@]} VMs..."
for vm_id in "${all_vm_ids[@]}"; do
if [[ -n "$vm_id" ]]; then
vm_info=$(get_vm_info_from_proxmox "$vm_id")
vm_name=$(echo "$vm_info" | sed 's/ (.*)$//') # Extract just the name part
destroy_vm_with_check "$vm_id" "$vm_name"
fi
done
echo "===== VM Destruction Complete ====="
echo "All specified K3s VMs have been destroyed successfully."
echo "$(date): VM Destruction Complete - All specified K3s VMs have been destroyed successfully." >> "$LOG_FILE"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment