2026-05-23 07:09:39
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env bash
|
||||
set -u # no unset vars
|
||||
|
||||
########################
|
||||
# Configuration
|
||||
########################
|
||||
|
||||
SECONDS_WAIT=60
|
||||
DESTINATION_DIR="/mnt/unprotected/tmp/VM/backup/corellia"
|
||||
VMHOME="/vm/ssd0/" # base dir for VM data; adapt as needed
|
||||
DAYS_TO_KEEP_VM_BACKUP=60
|
||||
MAIL_TO="vplesnila@gmail.com"
|
||||
MAIL_FROM="plesnila.valeriu@orange.fr"
|
||||
MAIL_SUBJECT_OK="VM backup success"
|
||||
MAIL_SUBJECT_FAIL="VM backup failure"
|
||||
LOG_DIR="/root/tmp"
|
||||
LOGFILE="${LOG_DIR}/vm_backup_$(date +%F_%H%M%S).log"
|
||||
|
||||
########################
|
||||
# Logging setup
|
||||
########################
|
||||
|
||||
mkdir -p "$LOG_DIR" "$DESTINATION_DIR"
|
||||
|
||||
# Log everything to file and stdout
|
||||
exec > >(tee -a "$LOGFILE") 2>&1
|
||||
|
||||
echo "===== VM backup started at $(date) ====="
|
||||
|
||||
FAILED=0
|
||||
|
||||
fail() {
|
||||
echo "ERROR: $*" >&2
|
||||
FAILED=1
|
||||
}
|
||||
|
||||
send_mail() {
|
||||
local subject="$1"
|
||||
{
|
||||
echo "From: ${MAIL_FROM}"
|
||||
echo "To: ${MAIL_TO}"
|
||||
echo "Subject: ${subject}"
|
||||
echo
|
||||
cat "$LOGFILE"
|
||||
} | msmtp "$MAIL_TO"
|
||||
}
|
||||
|
||||
########################
|
||||
# Helper functions
|
||||
########################
|
||||
|
||||
list_all_vms() {
|
||||
virsh list --all --name | sed '/^$/d'
|
||||
}
|
||||
|
||||
list_running_vms() {
|
||||
virsh list --name | sed '/^$/d'
|
||||
}
|
||||
|
||||
wait_and_check_offline() {
|
||||
local wait_seconds="$1"
|
||||
echo "Waiting ${wait_seconds}s..."
|
||||
sleep "$wait_seconds"
|
||||
|
||||
local still_running
|
||||
still_running=$(list_running_vms || true)
|
||||
|
||||
if [[ -n "$still_running" ]]; then
|
||||
echo "Still running VMs:"
|
||||
echo "$still_running"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "All VMs are offline."
|
||||
return 0
|
||||
}
|
||||
|
||||
backup_vm() {
|
||||
local vm="$1"
|
||||
local date_str
|
||||
date_str="$(date +%F)"
|
||||
local backup_file="${DESTINATION_DIR}/${vm}_${date_str}.tar.gz"
|
||||
local xml_file="${DESTINATION_DIR}/${vm}_${date_str}.xml"
|
||||
|
||||
echo "----- Backing up VM: ${vm} -----"
|
||||
|
||||
# 1. Export XML definition
|
||||
echo "Exporting XML definition to ${xml_file}"
|
||||
if ! virsh dumpxml "$vm" > "$xml_file"; then
|
||||
fail "Failed to dump XML for VM '$vm'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 2. Backup VM storage
|
||||
if [[ ! -d "$VMHOME" ]]; then
|
||||
fail "VMHOME directory '$VMHOME' does not exist for VM '$vm'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
cd "$VMHOME" || { fail "Cannot cd to $VMHOME for VM '$vm'"; return 1; }
|
||||
|
||||
echo "Creating compressed archive: $backup_file"
|
||||
if ! tar -cvf - ${vm} | pigz > "$backup_file"; then
|
||||
fail "Backup failed for VM '$vm'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 3. Cleanup old backups
|
||||
echo "Cleaning old backups for VM '$vm' older than ${DAYS_TO_KEEP_VM_BACKUP} days"
|
||||
if ! find "$DESTINATION_DIR" -maxdepth 1 -type f \
|
||||
\( -name "${vm}_*.tar.gz" -o -name "${vm}_*.xml" \) \
|
||||
-mtime +"$DAYS_TO_KEEP_VM_BACKUP" -print -delete; then
|
||||
fail "Failed to clean old backups for VM '$vm'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Backup completed for VM '$vm'"
|
||||
return 0
|
||||
}
|
||||
|
||||
start_all_vms() {
|
||||
echo "===== Starting ALL defined VMs ====="
|
||||
|
||||
local all_vms
|
||||
all_vms=$(virsh list --all --name | sed '/^$/d')
|
||||
|
||||
if [[ -z "$all_vms" ]]; then
|
||||
echo "No VMs defined on this host; nothing to start."
|
||||
return 0
|
||||
fi
|
||||
|
||||
while read -r vm; do
|
||||
[[ -z "$vm" ]] && continue
|
||||
echo "Starting VM: $vm"
|
||||
if ! virsh start "$vm"; then
|
||||
fail "Failed to start VM '$vm'"
|
||||
fi
|
||||
done <<< "$all_vms"
|
||||
|
||||
echo "===== VM startup phase completed ====="
|
||||
}
|
||||
|
||||
########################
|
||||
# Main logic
|
||||
########################
|
||||
|
||||
ALL_VMS=$(list_all_vms)
|
||||
if [[ -z "$ALL_VMS" ]]; then
|
||||
echo "No VMs defined on this host."
|
||||
fi
|
||||
|
||||
echo "All VMs:"
|
||||
echo "$ALL_VMS"
|
||||
|
||||
RUNNING_VMS=$(list_running_vms)
|
||||
echo "Running VMs:"
|
||||
echo "${RUNNING_VMS:-<none>}"
|
||||
|
||||
# Graceful shutdown
|
||||
if [[ -n "$RUNNING_VMS" ]]; then
|
||||
echo "Shutting down VMs gracefully..."
|
||||
while read -r vm; do
|
||||
[[ -z "$vm" ]] && continue
|
||||
echo "virsh shutdown $vm"
|
||||
if ! virsh shutdown "$vm"; then
|
||||
fail "Graceful shutdown failed for VM '$vm'"
|
||||
fi
|
||||
done <<< "$RUNNING_VMS"
|
||||
else
|
||||
echo "No running VMs to shut down gracefully."
|
||||
fi
|
||||
|
||||
# Wait and check
|
||||
if ! wait_and_check_offline "$SECONDS_WAIT"; then
|
||||
echo "Some VMs still running after graceful shutdown; forcing shutdown..."
|
||||
STILL_RUNNING=$(list_running_vms)
|
||||
while read -r vm; do
|
||||
[[ -z "$vm" ]] && continue
|
||||
echo "virsh destroy $vm"
|
||||
if ! virsh destroy "$vm"; then
|
||||
fail "Force shutdown failed for VM '$vm'"
|
||||
fi
|
||||
done <<< "$STILL_RUNNING"
|
||||
fi
|
||||
|
||||
# If any failure so far, send failure mail and exit
|
||||
if [[ "$FAILED" -ne 0 ]]; then
|
||||
echo "Failures detected before backup phase."
|
||||
send_mail "$MAIL_SUBJECT_FAIL"
|
||||
echo "===== VM backup finished with FAILURE at $(date) ====="
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Backup each VM
|
||||
for vm in $ALL_VMS; do
|
||||
[[ -z "$vm" ]] && continue
|
||||
backup_vm "$vm" || FAILED=1
|
||||
done
|
||||
|
||||
echo "Starting all VMs..."
|
||||
start_all_vms
|
||||
|
||||
# Final status and mail
|
||||
if [[ "$FAILED" -ne 0 ]]; then
|
||||
echo "One or more VM backups failed."
|
||||
send_mail "$MAIL_SUBJECT_FAIL"
|
||||
echo "===== VM backup finished with FAILURE at $(date) ====="
|
||||
exit 1
|
||||
else
|
||||
echo "All VM backups completed successfully."
|
||||
send_mail "$MAIL_SUBJECT_OK"
|
||||
echo "===== VM backup finished with SUCCESS at $(date) ====="
|
||||
exit 0
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user