diff --git a/bash/corellia_backup_VM.sh b/bash/corellia_backup_VM.sh new file mode 100644 index 0000000..3a543f7 --- /dev/null +++ b/bash/corellia_backup_VM.sh @@ -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:-}" + +# 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 +