This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| computing:grokhacking [2025/03/28 23:48] – oemb1905 | computing:grokhacking [2025/03/28 23:55] (current) – oemb1905 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ``` | + | #forthcoming |
| - | #!/ | + | |
| - | # New production VM backup and pruning script | + | |
| - | # Runs monthly to maintain VM image sizes | + | |
| - | # Configuration | ||
| - | BACKUP_DIR="/ | ||
| - | VM_DIR="/ | ||
| - | TEMP_DIR="/ | ||
| - | LOG_DIR="/ | ||
| - | ALERT_EMAIL=" | ||
| - | HOSTNAME=$(hostname -f) | ||
| - | RETENTION_DAYS=15 | ||
| - | MIN_SPACE_REQUIRED=10737418240 | ||
| - | MAX_PARALLEL=2 | ||
| - | |||
| - | # VM images array | ||
| - | declare -a VM_IMAGES=( | ||
| - | " | ||
| - | " | ||
| - | ) | ||
| - | |||
| - | # Check if dry-run mode is enabled | ||
| - | DRY_RUN=false | ||
| - | if [[ " | ||
| - | DRY_RUN=true | ||
| - | echo " | ||
| - | fi | ||
| - | |||
| - | # Function to log and email messages | ||
| - | log_and_mail() { | ||
| - | local subject=" | ||
| - | local message=" | ||
| - | local log_file=" | ||
| - | | ||
| - | echo " | ||
| - | if ! $DRY_RUN; then | ||
| - | echo " | ||
| - | fi | ||
| - | } | ||
| - | |||
| - | # Cleanup function for interruptions | ||
| - | cleanup() { | ||
| - | echo " | ||
| - | rm -f " | ||
| - | exit 1 | ||
| - | } | ||
| - | |||
| - | # Trap interrupts | ||
| - | trap cleanup INT TERM | ||
| - | |||
| - | # Check available disk space | ||
| - | check_space() { | ||
| - | local dir=" | ||
| - | local available=$(df --output=avail " | ||
| - | if (( available * 1024 < MIN_SPACE_REQUIRED )); then | ||
| - | return 1 | ||
| - | fi | ||
| - | return 0 | ||
| - | } | ||
| - | |||
| - | # Process VM function | ||
| - | process_vm() { | ||
| - | local vm=" | ||
| - | local TIMESTAMP=$(date +" | ||
| - | local LOG_FILE=" | ||
| - | touch " | ||
| - | |||
| - | # Log disk space before | ||
| - | local space_before=$(du -sb " | ||
| - | |||
| - | # Check disk space | ||
| - | if ! check_space " | ||
| - | log_and_mail " | ||
| - | " | ||
| - | " | ||
| - | return 1 | ||
| - | fi | ||
| - | |||
| - | if ! $DRY_RUN; then | ||
| - | # Shutdown VM | ||
| - | if ! virsh shutdown " | ||
| - | log_and_mail " | ||
| - | " | ||
| - | " | ||
| - | return 1 | ||
| - | fi | ||
| - | |||
| - | # Wait for shutdown | ||
| - | sleep 30 | ||
| - | if ! tail -n 2 "/ | ||
| - | log_and_mail " | ||
| - | "The ${vm} image failed to shutdown properly at $(date)." | ||
| - | " | ||
| - | return 1 | ||
| - | fi | ||
| - | fi | ||
| - | |||
| - | # Image conversion process | ||
| - | cd " | ||
| - | local START0=$(date +%s) | ||
| - | | ||
| - | if ! $DRY_RUN; then | ||
| - | if ! virt-sparsify --in-place " | ||
| - | ! qemu-img convert -O qcow2 " | ||
| - | ! mv " | ||
| - | ! mv " | ||
| - | ! virsh start " | ||
| - | log_and_mail " | ||
| - | "Image conversion failed for ${vm} at $(date)." | ||
| - | " | ||
| - | return 1 | ||
| - | fi | ||
| - | fi | ||
| - | |||
| - | local END0=$(date +%s) | ||
| - | local DURATION0=$((END0 - START0)) | ||
| - | local MINUTES0=$((DURATION0 / 60)) | ||
| - | |||
| - | # Tarballing process | ||
| - | cd " | ||
| - | local START1=$(date +%s) | ||
| - | | ||
| - | if ! $DRY_RUN; then | ||
| - | if ! qemu-img convert -O qcow2 " | ||
| - | ! cp -ar --sparse=always " | ||
| - | ! bsdtar --use-compress-program=pbzip2 -Scf " | ||
| - | ! mv " | ||
| - | log_and_mail " | ||
| - | " | ||
| - | " | ||
| - | return 1 | ||
| - | fi | ||
| - | |||
| - | # Cleanup temporary files | ||
| - | rm -f " | ||
| - | fi | ||
| - | |||
| - | local END1=$(date +%s) | ||
| - | local DURATION1=$((END1 - START1)) | ||
| - | local MINUTES1=$((DURATION1 / 60)) | ||
| - | |||
| - | # Log disk space after | ||
| - | local space_after=$(du -sb " | ||
| - | local space_saved=$((space_before - space_after)) | ||
| - | |||
| - | # Prune old backups | ||
| - | if ! $DRY_RUN; then | ||
| - | find " | ||
| - | find " | ||
| - | fi | ||
| - | |||
| - | # Success notification | ||
| - | local MESSAGE=" | ||
| - | "and the tarballing took ${DURATION1} sec. (${MINUTES1} min). "\ | ||
| - | "Space saved: $((space_saved / 1048576)) MB (Before: $((space_before / 1048576)) MB, After: $((space_after / 1048576)) MB)" | ||
| - | log_and_mail " | ||
| - | " | ||
| - | " | ||
| - | |||
| - | rm -f " | ||
| - | return 0 | ||
| - | } | ||
| - | |||
| - | # Main loop with parallel processing | ||
| - | pids=() | ||
| - | for vm in " | ||
| - | # Wait if maximum parallel processes reached | ||
| - | while (( ${#pids[@]} >= MAX_PARALLEL )); do | ||
| - | wait -n # Wait for any process to finish | ||
| - | # Clean up completed PIDs | ||
| - | new_pids=() | ||
| - | for pid in " | ||
| - | if kill -0 " | ||
| - | new_pids+=(" | ||
| - | fi | ||
| - | done | ||
| - | pids=(" | ||
| - | done | ||
| - | |||
| - | # Process VM in background | ||
| - | process_vm " | ||
| - | pids+=($!) | ||
| - | done | ||
| - | |||
| - | # Wait for all processes to complete | ||
| - | wait | ||
| - | |||
| - | echo "All VM processing completed at $(date)" | ||
| - | ``` | ||