feat: complete LVM backup system with external M.2 boot support
MAJOR MILESTONE: Transform backup system into comprehensive LVM migration solution 🎯 LVM Migration & Boot System Complete: - Complete external M.2 LVM migration capability - One-button migration from non-LVM to LVM system - Automatic GRUB repair and boot configuration - External boot validation and recovery tools 🔧 New Migration Tools Added: - fix_grub_lvm_boot.sh: Complete GRUB repair for external LVM boot - automated_clonezilla_backup.sh: Automated backup with Clonezilla integration - validate_lvm_migration.sh: Comprehensive migration validation - troubleshoot_migration.sh: Advanced diagnostic and repair tools - emergency_install.sh: Package installation for live systems - bootstrap_usb_tools.sh: USB preparation with all dependencies 💾 Backup System Enhancements: - create_alpine_backup_usb.sh: Alpine Linux live system preparation - create_clonezilla_backup.sh: Professional backup solution integration - plug_and_play_backup.sh: Simple automated backup workflow - lvm_snapshot_backup.sh: LVM snapshot-based incremental backups - simple_auto_backup.sh: Streamlined backup automation 📋 Documentation & Guides: - LIVE_USB_MIGRATION_GUIDE.md: Complete migration walkthrough - DRIVE_SELECTION_REFERENCE.md: Safe drive selection procedures - Comprehensive troubleshooting and validation procedures - Step-by-step migration instructions with safety checks 🛡️ Safety & Validation Features: - Interactive drive selection with confirmation - Comprehensive pre-migration checks - Automatic backup validation - GRUB boot repair with fallback options - Hardware compatibility verification 🧪 Testing & Debugging: - Complete GRUB configuration analysis - LVM volume validation and repair - Boot sequence troubleshooting - Hardware connection diagnostics ✅ Production Ready Status: - All migration tools tested and validated - External M.2 boot functionality confirmed - GRUB configuration properly generates LVM entries - Kernel files correctly deployed to external boot partition - EFI bootloader properly configured as 'ubuntu-external' This completes the transformation from simple backup scripts to a comprehensive LVM migration and backup system capable of full system migration to external M.2 with proper boot configuration and recovery capabilities.
This commit is contained in:
409
lvm_snapshot_backup.sh
Executable file
409
lvm_snapshot_backup.sh
Executable file
@@ -0,0 +1,409 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Enhanced LVM Snapshot Backup System
|
||||
# Integrates LVM snapshots with the existing backup system for M.2 external drives
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Configuration
|
||||
VG_NAME="system-vg"
|
||||
SNAPSHOT_SIZE="10G"
|
||||
BACKUP_BASE_DIR="/mnt/backup"
|
||||
EXTERNAL_BACKUP_DRIVE="" # Will be auto-detected
|
||||
LOG_FILE="/var/log/lvm-snapshot-backup.log"
|
||||
|
||||
# Snapshot names
|
||||
ROOT_SNAPSHOT="root-snapshot"
|
||||
HOME_SNAPSHOT="home-snapshot"
|
||||
BOOT_SNAPSHOT="boot-snapshot"
|
||||
|
||||
log() {
|
||||
local message="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
|
||||
echo -e "${BLUE}$message${NC}"
|
||||
echo "$message" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
error() {
|
||||
local message="[ERROR] $1"
|
||||
echo -e "${RED}$message${NC}" >&2
|
||||
echo "$message" >> "$LOG_FILE"
|
||||
exit 1
|
||||
}
|
||||
|
||||
warning() {
|
||||
local message="[WARNING] $1"
|
||||
echo -e "${YELLOW}$message${NC}"
|
||||
echo "$message" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
success() {
|
||||
local message="[SUCCESS] $1"
|
||||
echo -e "${GREEN}$message${NC}"
|
||||
echo "$message" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
check_lvm_system() {
|
||||
log "Checking LVM system status..."
|
||||
|
||||
# Check if we're running on an LVM system
|
||||
if ! command -v lvm >/dev/null 2>&1; then
|
||||
error "LVM tools not found. This system may not support LVM."
|
||||
fi
|
||||
|
||||
# Check if volume group exists
|
||||
if ! vgs "$VG_NAME" >/dev/null 2>&1; then
|
||||
error "Volume group '$VG_NAME' not found. Are you running on the migrated LVM system?"
|
||||
fi
|
||||
|
||||
# Check available space for snapshots
|
||||
local vg_free=$(vgs --noheadings -o vg_free --units g "$VG_NAME" | tr -d ' G')
|
||||
local snapshot_size_num=$(echo "$SNAPSHOT_SIZE" | tr -d 'G')
|
||||
local required_space=$((snapshot_size_num * 3)) # 3 snapshots
|
||||
|
||||
if (( $(echo "$vg_free < $required_space" | bc -l) )); then
|
||||
warning "Low free space in volume group ($vg_free GB available, $required_space GB recommended)"
|
||||
echo "Consider reducing snapshot size or extending volume group"
|
||||
fi
|
||||
|
||||
success "LVM system check passed"
|
||||
}
|
||||
|
||||
detect_backup_drive() {
|
||||
log "Detecting external backup drive..."
|
||||
|
||||
# Look for drives that are not the current root drive
|
||||
local root_drive=$(lsblk -no PKNAME $(findmnt -no SOURCE /))
|
||||
local available_drives=($(lsblk -dpno NAME | grep -v "$root_drive"))
|
||||
|
||||
if [ ${#available_drives[@]} -eq 0 ]; then
|
||||
error "No external drives found for backup"
|
||||
elif [ ${#available_drives[@]} -eq 1 ]; then
|
||||
EXTERNAL_BACKUP_DRIVE="${available_drives[0]}"
|
||||
log "Auto-selected backup drive: $EXTERNAL_BACKUP_DRIVE"
|
||||
else
|
||||
echo "Multiple external drives found:"
|
||||
for i in "${!available_drives[@]}"; do
|
||||
local drive="${available_drives[$i]}"
|
||||
local info=$(lsblk -no SIZE,MODEL "$drive" | head -1)
|
||||
echo "$((i+1)). $drive - $info"
|
||||
done
|
||||
|
||||
read -p "Select backup drive [1-${#available_drives[@]}]: " choice
|
||||
EXTERNAL_BACKUP_DRIVE="${available_drives[$((choice-1))]}"
|
||||
fi
|
||||
|
||||
success "Selected backup drive: $EXTERNAL_BACKUP_DRIVE"
|
||||
}
|
||||
|
||||
create_snapshots() {
|
||||
log "Creating LVM snapshots..."
|
||||
|
||||
# Remove existing snapshots if they exist
|
||||
remove_snapshots_quiet
|
||||
|
||||
# Create snapshots for each logical volume
|
||||
local volumes=("root" "home" "boot")
|
||||
local snapshots=("$ROOT_SNAPSHOT" "$HOME_SNAPSHOT" "$BOOT_SNAPSHOT")
|
||||
|
||||
for i in "${!volumes[@]}"; do
|
||||
local volume="${volumes[$i]}"
|
||||
local snapshot="${snapshots[$i]}"
|
||||
|
||||
if lvs "$VG_NAME/$volume" >/dev/null 2>&1; then
|
||||
log "Creating snapshot: $snapshot for $volume"
|
||||
lvcreate -L "$SNAPSHOT_SIZE" -s -n "$snapshot" "/dev/$VG_NAME/$volume" || {
|
||||
error "Failed to create snapshot $snapshot"
|
||||
}
|
||||
success "Created snapshot: $snapshot"
|
||||
else
|
||||
warning "Logical volume $volume not found, skipping"
|
||||
fi
|
||||
done
|
||||
|
||||
success "All snapshots created successfully"
|
||||
}
|
||||
|
||||
mount_snapshots() {
|
||||
log "Mounting snapshots for backup..."
|
||||
|
||||
# Create mount points
|
||||
mkdir -p "$BACKUP_BASE_DIR"/{root,home,boot}
|
||||
|
||||
# Mount snapshots
|
||||
local snapshots=("$ROOT_SNAPSHOT" "$HOME_SNAPSHOT" "$BOOT_SNAPSHOT")
|
||||
local mount_points=("root" "home" "boot")
|
||||
|
||||
for i in "${!snapshots[@]}"; do
|
||||
local snapshot="${snapshots[$i]}"
|
||||
local mount_point="$BACKUP_BASE_DIR/${mount_points[$i]}"
|
||||
|
||||
if [ -e "/dev/$VG_NAME/$snapshot" ]; then
|
||||
log "Mounting /dev/$VG_NAME/$snapshot to $mount_point"
|
||||
mount "/dev/$VG_NAME/$snapshot" "$mount_point" || {
|
||||
warning "Failed to mount snapshot $snapshot"
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
success "Snapshots mounted at $BACKUP_BASE_DIR"
|
||||
}
|
||||
|
||||
backup_to_external() {
|
||||
log "Backing up snapshots to external drive..."
|
||||
|
||||
if [ -z "$EXTERNAL_BACKUP_DRIVE" ]; then
|
||||
detect_backup_drive
|
||||
fi
|
||||
|
||||
# Create backup directory on external drive
|
||||
local external_mount="/mnt/external-backup"
|
||||
mkdir -p "$external_mount"
|
||||
|
||||
# Mount external drive (assume first partition)
|
||||
mount "${EXTERNAL_BACKUP_DRIVE}1" "$external_mount" 2>/dev/null || {
|
||||
# Try the whole drive if partition doesn't work
|
||||
mount "$EXTERNAL_BACKUP_DRIVE" "$external_mount" || {
|
||||
error "Failed to mount external backup drive"
|
||||
}
|
||||
}
|
||||
|
||||
# Create timestamped backup directory
|
||||
local backup_timestamp=$(date '+%Y%m%d_%H%M%S')
|
||||
local backup_dir="$external_mount/lvm-snapshots/$backup_timestamp"
|
||||
mkdir -p "$backup_dir"
|
||||
|
||||
# Backup each mounted snapshot
|
||||
local mount_points=("root" "home" "boot")
|
||||
for mount_point in "${mount_points[@]}"; do
|
||||
local source="$BACKUP_BASE_DIR/$mount_point"
|
||||
local target="$backup_dir/$mount_point"
|
||||
|
||||
if mountpoint -q "$source"; then
|
||||
log "Backing up $mount_point to external drive..."
|
||||
mkdir -p "$target"
|
||||
rsync -avxHAX --progress "$source/" "$target/" || {
|
||||
warning "Backup of $mount_point failed"
|
||||
}
|
||||
else
|
||||
warning "Snapshot $mount_point not mounted, skipping"
|
||||
fi
|
||||
done
|
||||
|
||||
# Create backup metadata
|
||||
cat > "$backup_dir/backup-info.txt" << EOF
|
||||
LVM Snapshot Backup Information
|
||||
===============================
|
||||
Backup Date: $(date)
|
||||
Source System: $(hostname)
|
||||
Volume Group: $VG_NAME
|
||||
Snapshot Size: $SNAPSHOT_SIZE
|
||||
Backup Location: $backup_dir
|
||||
|
||||
Logical Volumes:
|
||||
$(lvs $VG_NAME)
|
||||
|
||||
Volume Group Info:
|
||||
$(vgs $VG_NAME)
|
||||
|
||||
Physical Volumes:
|
||||
$(pvs)
|
||||
EOF
|
||||
|
||||
# Unmount external drive
|
||||
umount "$external_mount"
|
||||
|
||||
success "Backup completed to $backup_dir"
|
||||
}
|
||||
|
||||
remove_snapshots_quiet() {
|
||||
# Remove snapshots without error messages (used internally)
|
||||
lvremove -f "/dev/$VG_NAME/$ROOT_SNAPSHOT" 2>/dev/null || true
|
||||
lvremove -f "/dev/$VG_NAME/$HOME_SNAPSHOT" 2>/dev/null || true
|
||||
lvremove -f "/dev/$VG_NAME/$BOOT_SNAPSHOT" 2>/dev/null || true
|
||||
}
|
||||
|
||||
remove_snapshots() {
|
||||
log "Cleaning up snapshots..."
|
||||
|
||||
# Unmount snapshots
|
||||
umount "$BACKUP_BASE_DIR/root" 2>/dev/null || true
|
||||
umount "$BACKUP_BASE_DIR/home" 2>/dev/null || true
|
||||
umount "$BACKUP_BASE_DIR/boot" 2>/dev/null || true
|
||||
|
||||
# Remove logical volumes
|
||||
remove_snapshots_quiet
|
||||
|
||||
success "Snapshots removed"
|
||||
}
|
||||
|
||||
list_snapshots() {
|
||||
echo "Current LVM snapshots:"
|
||||
lvs "$VG_NAME" | grep -E "(snapshot|Snap%)" || echo "No snapshots found"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo -e "${GREEN}=== LVM Snapshot Backup Status ===${NC}"
|
||||
echo
|
||||
|
||||
echo "Volume Group Information:"
|
||||
vgs "$VG_NAME" 2>/dev/null || echo "Volume group not found"
|
||||
echo
|
||||
|
||||
echo "Logical Volumes:"
|
||||
lvs "$VG_NAME" 2>/dev/null || echo "No logical volumes found"
|
||||
echo
|
||||
|
||||
echo "Current Snapshots:"
|
||||
list_snapshots
|
||||
echo
|
||||
|
||||
echo "Mount Status:"
|
||||
if mountpoint -q "$BACKUP_BASE_DIR/root" 2>/dev/null; then
|
||||
echo " Root snapshot: mounted at $BACKUP_BASE_DIR/root"
|
||||
else
|
||||
echo " Root snapshot: not mounted"
|
||||
fi
|
||||
|
||||
if mountpoint -q "$BACKUP_BASE_DIR/home" 2>/dev/null; then
|
||||
echo " Home snapshot: mounted at $BACKUP_BASE_DIR/home"
|
||||
else
|
||||
echo " Home snapshot: not mounted"
|
||||
fi
|
||||
|
||||
if mountpoint -q "$BACKUP_BASE_DIR/boot" 2>/dev/null; then
|
||||
echo " Boot snapshot: mounted at $BACKUP_BASE_DIR/boot"
|
||||
else
|
||||
echo " Boot snapshot: not mounted"
|
||||
fi
|
||||
}
|
||||
|
||||
integrate_with_backup_system() {
|
||||
log "Integrating with existing backup system..."
|
||||
|
||||
# Check if main backup system exists
|
||||
if [ -f "./backup_script.sh" ]; then
|
||||
log "Found main backup system - creating integration"
|
||||
|
||||
# Create wrapper script that combines snapshot and full backup
|
||||
cat > "./lvm_integrated_backup.sh" << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
# Integrated LVM + Full System Backup
|
||||
# Combines LVM snapshots with the main backup system
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
echo "=== Integrated LVM Backup System ==="
|
||||
echo "1. LVM Snapshot Backup (fast, consistent)"
|
||||
echo "2. Full System Backup (complete clone)"
|
||||
echo "3. Combined Backup (snapshots + clone)"
|
||||
echo
|
||||
|
||||
read -p "Select backup type [1-3]: " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
echo "Performing LVM snapshot backup..."
|
||||
sudo "$SCRIPT_DIR/lvm_snapshot_backup.sh" backup
|
||||
;;
|
||||
2)
|
||||
echo "Performing full system backup..."
|
||||
sudo "$SCRIPT_DIR/backup_script.sh"
|
||||
;;
|
||||
3)
|
||||
echo "Performing combined backup..."
|
||||
echo "Step 1: LVM snapshots..."
|
||||
sudo "$SCRIPT_DIR/lvm_snapshot_backup.sh" backup
|
||||
echo "Step 2: Full system clone..."
|
||||
sudo "$SCRIPT_DIR/backup_script.sh" --sync
|
||||
;;
|
||||
*)
|
||||
echo "Invalid choice"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
chmod +x "./lvm_integrated_backup.sh"
|
||||
success "Created integrated backup script: lvm_integrated_backup.sh"
|
||||
else
|
||||
warning "Main backup system not found in current directory"
|
||||
fi
|
||||
}
|
||||
|
||||
show_usage() {
|
||||
echo "Usage: $0 {create|mount|remove|backup|external|status|list|integrate}"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " create - Create LVM snapshots only"
|
||||
echo " mount - Mount existing snapshots for access"
|
||||
echo " remove - Remove snapshots and unmount"
|
||||
echo " backup - Create snapshots and mount (ready for backup)"
|
||||
echo " external - Full backup to external drive"
|
||||
echo " status - Show current LVM and snapshot status"
|
||||
echo " list - List current snapshots"
|
||||
echo " integrate - Integrate with existing backup system"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " $0 backup # Create and mount snapshots"
|
||||
echo " $0 external # Full backup to external drive"
|
||||
echo " $0 remove # Clean up when backup complete"
|
||||
}
|
||||
|
||||
main() {
|
||||
# Ensure log file exists and is writable
|
||||
sudo touch "$LOG_FILE" 2>/dev/null || LOG_FILE="/tmp/lvm-backup.log"
|
||||
|
||||
case "${1:-}" in
|
||||
create)
|
||||
check_lvm_system
|
||||
create_snapshots
|
||||
;;
|
||||
mount)
|
||||
mount_snapshots
|
||||
;;
|
||||
remove)
|
||||
remove_snapshots
|
||||
;;
|
||||
backup)
|
||||
check_lvm_system
|
||||
create_snapshots
|
||||
mount_snapshots
|
||||
echo "Snapshots ready for backup at $BACKUP_BASE_DIR"
|
||||
echo "Run '$0 remove' when backup is complete"
|
||||
;;
|
||||
external)
|
||||
check_lvm_system
|
||||
create_snapshots
|
||||
mount_snapshots
|
||||
backup_to_external
|
||||
remove_snapshots
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
list)
|
||||
list_snapshots
|
||||
;;
|
||||
integrate)
|
||||
integrate_with_backup_system
|
||||
;;
|
||||
*)
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Check if running as root for LVM operations
|
||||
if [ "$EUID" -ne 0 ] && [[ "$1" =~ ^(create|mount|remove|backup|external)$ ]]; then
|
||||
error "LVM operations require root privileges. Use: sudo $0 $1"
|
||||
fi
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user