User Tools

Site Tools


computing:grokhacking

This is an old revision of the document!


#!/bin/bash # New production VM backup and pruning script # Runs monthly to maintain VM image sizes # Configuration BACKUP_DIR=“/mnt/warehouse/backups” VM_DIR=“/mnt/vms/production” TEMP_DIR=“/mnt/vms/temps” LOG_DIR=“/root” ALERT_EMAIL=“alerts@haacksnetworking.org” HOSTNAME=$(hostname -f) RETENTION_DAYS=15 MIN_SPACE_REQUIRED=10737418240 # 10GB in bytes MAX_PARALLEL=2 # Maximum parallel VM processes # VM images array declare -a VM_IMAGES=( “hackingclub.org.qcow2” “felinefantasy.club.qcow2” ) # Check if dry-run mode is enabled DRY_RUN=false if "$1" == "--dry-run"; then DRY_RUN=true echo “Running in dry-run mode - no changes will be made” fi # Function to log and email messages log_and_mail() { local subject=“$1” local message=“$2” local log_file=“$3” echo “$message” | tee -a “$log_file” if ! $DRY_RUN; then echo “$message” | mail -s “$subject” “$ALERT_EMAIL” fi } # Cleanup function for interruptions cleanup() { echo “Script interrupted - cleaning up temporary files…” rm -f “${TEMP_DIR}”/*.bak “${TEMP_DIR}/trimmed2.”* exit 1 } # Trap interrupts trap cleanup INT TERM # Check available disk space check_space() { local dir=“$1” local available=$(df –output=avail “$dir” | tail -n1) if 1); then return 1 fi return 0 } # Process VM function process_vm() { local vm=“$1” local TIMESTAMP=$(date +“%Y%m%d-%H:%M:%S”) local LOG_FILE=“${LOG_DIR}/${vm}-loop-b.log” touch “$LOG_FILE” # Log disk space before local space_before=$(du -sb “${VM_DIR}/${vm}” | cut -f1) # Check disk space if ! check_space “$VM_DIR”; then log_and_mail “[vm-sane-bu-${vm}-failed]-${HOSTNAME}-$(date)” \ “Insufficient disk space for ${vm} at $(date).” \ “$LOG_FILE” return 1 fi if ! $DRY_RUN; then # Shutdown VM if ! virsh shutdown “$vm” 2>/dev/null; then log_and_mail “[vm-sane-bu-${vm}-failed]-${HOSTNAME}-$(date)” \ “Failed to initiate shutdown of ${vm} at $(date).” \ “$LOG_FILE” return 1 fi # Wait for shutdown sleep 30 if ! tail -n 2 “/var/log/libvirt/qemu/${vm}.log” | grep -q “reason=shutdown”; then log_and_mail “[vm-sane-bu-${vm}-failed]-${HOSTNAME}-$(date)” \ “The ${vm} image failed to shutdown properly at $(date).” \ “$LOG_FILE” return 1 fi fi # Image conversion process cd “$VM_DIR” || return 1 local START0=$(date +%s) if ! $DRY_RUN; then if ! virt-sparsify –in-place “$vm” || \ ! qemu-img convert -O qcow2 “$vm” “trimmed.$vm” || \ ! mv “$vm” “${TEMP_DIR}/${vm}.bak” || \ ! mv “trimmed.$vm” “$vm” || \ ! virsh start “$vm”; then log_and_mail “[vm-sane-bu-${vm}-failed]-${HOSTNAME}-$(date)” \ “Image conversion failed for ${vm} at $(date).” \ “$LOG_FILE” return 1 fi fi local END0=$(date +%s) local DURATION0=$2) local MINUTES0=$3) # Tarballing process cd “$TEMP_DIR” || return 1 local START1=$(date +%s) if ! $DRY_RUN; then if ! qemu-img convert -O qcow2 “${vm}.bak” “trimmed2.$vm” || \ ! cp -ar –sparse=always “trimmed2.$vm” “${BACKUP_DIR}/replicas/${vm}:${TIMESTAMP}.bak” || \ ! bsdtar –use-compress-program=pbzip2 -Scf “${vm}.bak.tar.bz2” “trimmed2.$vm” || \ ! mv “${vm}.bak.tar.bz2” “${BACKUP_DIR}/tarballs/${vm}:${TIMESTAMP}.sane.bak.tar.bz2”; then log_and_mail “[vm-sane-bu-${vm}-failed]-${HOSTNAME}-$(date)” \ “Tarball creation failed for ${vm} at $(date).” \ “$LOG_FILE” return 1 fi # Cleanup temporary files rm -f “${vm}.bak” “trimmed2.$vm” fi local END1=$(date +%s) local DURATION1=$4) local MINUTES1=$5) # Log disk space after local space_after=$(du -sb “${VM_DIR}/${vm}” | cut -f1) local space_saved=$6) # Prune old backups if ! $DRY_RUN; then find “${BACKUP_DIR}/tarballs/” -type f -mtime “+${RETENTION_DAYS}” -delete find “${BACKUP_DIR}/replicas/” -type f -mtime “+${RETENTION_DAYS}” -delete fi # Success notification local MESSAGE=“$(date) Jonathan, the ${vm} image conversion took ${DURATION0} sec. (${MINUTES0} min) “\ “and the tarballing took ${DURATION1} sec. (${MINUTES1} min). “\ “Space saved: $7) MB (Before: $8) MB, After: $9) MB)” log_and_mail ”[vm-sane-bu-${vm}-success]-${HOSTNAME}-$(date)” \ “$MESSAGE” \ “$LOG_FILE” rm -f “$LOG_FILE” return 0 } # Main loop with parallel processing pids=() for vm in “${VM_IMAGES[@]}”; do # Wait if maximum parallel processes reached while 10); do wait -n # Wait for any process to finish # Clean up completed PIDs new_pids=() for pid in “${pids[@]}”; do if kill -0 “$pid” 2>/dev/null; then new_pids+=(“$pid”) fi done pids=(“${new_pids[@]}”) done # Process VM in background process_vm “$vm” & pids+=($!) done # Wait for all processes to complete wait echo “All VM processing completed at $(date)”

1)
available * 1024 < MIN_SPACE_REQUIRED
2)
END0 - START0
3)
DURATION0 / 60
4)
END1 - START1
5)
DURATION1 / 60
6)
space_before - space_after
7)
space_saved / 1048576
8)
space_before / 1048576
9)
space_after / 1048576
10)
${#pids[@]} >= MAX_PARALLEL
computing/grokhacking.1743205372.txt.gz · Last modified: 2025/03/28 23:42 by oemb1905