Interactive script to backup a VM or Container on one Proxmox host and restore it on another

โ€”

by

in

#!/bin/bash
# Interactive script to backup a VM or Container on one Proxmox host and restore it on another

# Default configuration variables
SOURCE_HOST="srv78"
TARGET_HOST="srv141"
BACKUP_PATH="/var/lib/vz/dump"
SSH_USER="root"
TARGET_STORAGE="local"

# Function to validate numeric input
validate_number() {
    if [[ ! $1 =~ ^[0-9]+$ ]]; then
        echo "Error: '$1' is not a valid number."
        return 1
    fi
    return 0
}

# Ask for Proxmox hosts information
read -p "Enter source Proxmox host [${SOURCE_HOST}]: " input_source_host
SOURCE_HOST=${input_source_host:-$SOURCE_HOST}

read -p "Enter target Proxmox host [${TARGET_HOST}]: " input_target_host
TARGET_HOST=${input_target_host:-$TARGET_HOST}

read -p "Enter SSH user [${SSH_USER}]: " input_ssh_user
SSH_USER=${input_ssh_user:-$SSH_USER}

# Ask for VM/CT ID and validate
while true; do
    read -p "Enter source VM/CT ID: " VM_ID
    if validate_number "$VM_ID"; then
        break
    fi
done

while true; do
    read -p "Enter target VM/CT ID [${VM_ID}]: " input_new_vm_id
    NEW_VM_ID=${input_new_vm_id:-$VM_ID}
    if validate_number "$NEW_VM_ID"; then
        break
    fi
done

# Ask for container/VM type
while true; do
    read -p "Is this a VM (qemu) or Container (lxc)? [qemu/lxc]: " VM_TYPE
    VM_TYPE=$(echo "$VM_TYPE" | tr '[:upper:]' '[:lower:]')
    if [[ "$VM_TYPE" == "qemu" || "$VM_TYPE" == "lxc" ]]; then
        break
    else
        echo "Error: Please enter either 'qemu' or 'lxc'."
    fi
done

read -p "Enter target storage location [${TARGET_STORAGE}]: " input_target_storage
TARGET_STORAGE=${input_target_storage:-$TARGET_STORAGE}

# Confirm the details before proceeding
echo ""
echo "Migration Details:"
echo "-------------------"
echo "Source Host: $SOURCE_HOST"
echo "Target Host: $TARGET_HOST"
echo "Source ID: $VM_ID"
echo "Target ID: $NEW_VM_ID"
echo "Type: $VM_TYPE"
echo "Target Storage: $TARGET_STORAGE"
echo ""

read -p "Are these details correct? [y/N]: " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
    echo "Operation cancelled."
    exit 1
fi

# Stop the VM/CT on source host
echo "Stopping $VM_TYPE $VM_ID on $SOURCE_HOST..."
if [[ "$VM_TYPE" == "qemu" ]]; then
    ssh $SSH_USER@$SOURCE_HOST "qm stop $VM_ID" || { echo "Failed to stop VM"; exit 1; }
else
    ssh $SSH_USER@$SOURCE_HOST "pct stop $VM_ID" || { echo "Failed to stop Container"; exit 1; }
fi

# Wait for VM/CT to stop
echo "Waiting for $VM_TYPE to stop completely..."
sleep 10

# Create backup on source host
echo "Creating backup of $VM_TYPE $VM_ID..."
ssh $SSH_USER@$SOURCE_HOST "vzdump $VM_ID --compress zstd" || { echo "Backup failed"; exit 1; }

# Get the newest backup file for this VM/CT
if [[ "$VM_TYPE" == "qemu" ]]; then
    BACKUP_FILE=$(ssh $SSH_USER@$SOURCE_HOST "ls -t $BACKUP_PATH/vzdump-qemu-$VM_ID-*.vma.zst | head -1")
else
    BACKUP_FILE=$(ssh $SSH_USER@$SOURCE_HOST "ls -t $BACKUP_PATH/vzdump-lxc-$VM_ID-*.tar.zst | head -1")
fi
BACKUP_FILENAME=$(basename "$BACKUP_FILE")

if [[ -z "$BACKUP_FILE" ]]; then
    echo "Error: Backup file not found!"
    exit 1
fi

echo "Backup created: $BACKUP_FILENAME"

# Transfer the backup file to target host
echo "Transferring backup to $TARGET_HOST..."
ssh $SSH_USER@$SOURCE_HOST "rsync --progress -a $BACKUP_FILE $SSH_USER@$TARGET_HOST:$BACKUP_PATH/" || { echo "Transfer failed"; exit 1; }

# Import the backup on target host
echo "Importing backup on $TARGET_HOST..."
if [[ "$VM_TYPE" == "qemu" ]]; then
    ssh $SSH_USER@$TARGET_HOST "qmrestore $BACKUP_PATH/$BACKUP_FILENAME $NEW_VM_ID --storage $TARGET_STORAGE" || { echo "Restore failed"; exit 1; }
else
    ssh $SSH_USER@$TARGET_HOST "pct restore $NEW_VM_ID $BACKUP_PATH/$BACKUP_FILENAME --storage $TARGET_STORAGE" || { echo "Restore failed"; exit 1; }
fi

# Start the VM/CT on target host
echo "Starting $VM_TYPE $NEW_VM_ID on $TARGET_HOST..."
if [[ "$VM_TYPE" == "qemu" ]]; then
    ssh $SSH_USER@$TARGET_HOST "qm start $NEW_VM_ID" || { echo "Failed to start VM"; exit 1; }
else
    ssh $SSH_USER@$TARGET_HOST "pct start $NEW_VM_ID" || { echo "Failed to start Container"; exit 1; }
fi

# Ask if backup files should be removed
read -p "Do you want to remove the backup files to save space? [y/N]: " CLEANUP
if [[ "$CLEANUP" =~ ^[Yy]$ ]]; then
    echo "Cleaning up backup files..."
    ssh $SSH_USER@$SOURCE_HOST "rm $BACKUP_FILE"
    ssh $SSH_USER@$TARGET_HOST "rm $BACKUP_PATH/$BACKUP_FILENAME"
    echo "Backup files removed."
fi

echo "Migration complete! $VM_TYPE $VM_ID from $SOURCE_HOST is now running as $VM_TYPE $NEW_VM_ID on $TARGET_HOST"