Add snapshot-based LVM migration scripts
- snapshot_migrate_to_internal.sh: Complete snapshot-based migration from external M.2 to internal NVMe - preview_snapshot_migration.sh: Preview script showing snapshot migration process - migrate_lvm_to_internal.sh: Alternative rsync-based migration script - preview_migration.sh: Preview for rsync-based migration Key features: - LVM snapshot creation of ALL logical volumes (root, home, boot, swap) - Block-level dd copying for exact system clone - Automatic LVM structure setup on internal drive - GRUB/EFI boot configuration - Future snapshot management tools - Space-efficient one-at-a-time processing Migration preserves complete live system state with bit-perfect accuracy.
This commit is contained in:
407
migrate_lvm_to_internal.sh
Executable file
407
migrate_lvm_to_internal.sh
Executable file
@@ -0,0 +1,407 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# LVM Migration Script: External M.2 to Internal NVMe
|
||||||
|
# This script migrates the complete LVM structure from external M.2 to internal NVMe
|
||||||
|
# with snapshot capabilities for future backups
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# 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
|
||||||
|
EXTERNAL_DRIVE="/dev/sda"
|
||||||
|
INTERNAL_DRIVE="/dev/nvme0n1"
|
||||||
|
VG_NAME="migration-vg"
|
||||||
|
NEW_VG_NAME="internal-vg" # New VG name for internal drive
|
||||||
|
BACKUP_DIR="/tmp/lvm_migration_backup"
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_FILE="/var/log/lvm_migration.log"
|
||||||
|
exec 1> >(tee -a "$LOG_FILE")
|
||||||
|
exec 2> >(tee -a "$LOG_FILE" >&2)
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_step() {
|
||||||
|
echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Safety checks
|
||||||
|
safety_checks() {
|
||||||
|
log_step "Performing safety checks..."
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
log_error "This script must be run as root (use sudo)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify we're booted from external drive
|
||||||
|
root_device=$(findmnt -n -o SOURCE /)
|
||||||
|
if [[ "$root_device" != "/dev/mapper/migration--vg-root" ]]; then
|
||||||
|
log_error "Not booted from external LVM! Current root: $root_device"
|
||||||
|
log_error "Please boot from external M.2 drive first"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check drives exist
|
||||||
|
if [[ ! -b "$EXTERNAL_DRIVE" ]]; then
|
||||||
|
log_error "External drive $EXTERNAL_DRIVE not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -b "$INTERNAL_DRIVE" ]]; then
|
||||||
|
log_error "Internal drive $INTERNAL_DRIVE not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check available space
|
||||||
|
vg_size=$(vgs --noheadings --units g --nosuffix -o vg_size "$VG_NAME" | tr -d ' ')
|
||||||
|
internal_size=$(lsblk -b -n -o SIZE "$INTERNAL_DRIVE" | awk '{printf "%.0f", $1/1024/1024/1024}')
|
||||||
|
|
||||||
|
if (( $(echo "$vg_size > $internal_size" | bc -l) )); then
|
||||||
|
log_error "Internal drive ($internal_size GB) is smaller than LVM structure ($vg_size GB)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Safety checks passed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create backup directory
|
||||||
|
create_backup_dir() {
|
||||||
|
log_step "Creating backup directory..."
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Backup current LVM configuration
|
||||||
|
vgcfgbackup -f "$BACKUP_DIR/vg_backup" "$VG_NAME"
|
||||||
|
|
||||||
|
# Save partition tables
|
||||||
|
sfdisk -d "$EXTERNAL_DRIVE" > "$BACKUP_DIR/external_partition_table.txt"
|
||||||
|
sfdisk -d "$INTERNAL_DRIVE" > "$BACKUP_DIR/internal_partition_table.txt" 2>/dev/null || true
|
||||||
|
|
||||||
|
log_info "Backup directory created at $BACKUP_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wipe internal drive and create new partition structure
|
||||||
|
prepare_internal_drive() {
|
||||||
|
log_step "Preparing internal drive..."
|
||||||
|
|
||||||
|
# Confirmation
|
||||||
|
echo -e "${RED}WARNING: This will completely wipe $INTERNAL_DRIVE${NC}"
|
||||||
|
echo "Current internal drive content will be lost!"
|
||||||
|
read -p "Type 'YES' to continue: " confirm
|
||||||
|
if [[ "$confirm" != "YES" ]]; then
|
||||||
|
log_error "Migration cancelled by user"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Unmount any mounted partitions from internal drive
|
||||||
|
for mount in $(findmnt -n -o TARGET -S "$INTERNAL_DRIVE"* 2>/dev/null || true); do
|
||||||
|
log_info "Unmounting $mount"
|
||||||
|
umount "$mount" || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Deactivate any LVM on internal drive
|
||||||
|
for pv in $(pvs --noheadings -o pv_name | grep -E "^[[:space:]]*$INTERNAL_DRIVE" || true); do
|
||||||
|
log_info "Deactivating PV $pv"
|
||||||
|
vgchange -an $(pvs --noheadings -o vg_name "$pv") || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wipe filesystem signatures and partition table
|
||||||
|
wipefs -af "$INTERNAL_DRIVE"
|
||||||
|
|
||||||
|
# Create new GPT partition table
|
||||||
|
parted "$INTERNAL_DRIVE" --script mklabel gpt
|
||||||
|
|
||||||
|
# Create EFI boot partition (512MB)
|
||||||
|
parted "$INTERNAL_DRIVE" --script mkpart primary fat32 1MiB 513MiB
|
||||||
|
parted "$INTERNAL_DRIVE" --script set 1 esp on
|
||||||
|
|
||||||
|
# Create LVM partition (rest of the drive)
|
||||||
|
parted "$INTERNAL_DRIVE" --script mkpart primary 513MiB 100%
|
||||||
|
parted "$INTERNAL_DRIVE" --script set 2 lvm on
|
||||||
|
|
||||||
|
# Wait for partitions to be recognized
|
||||||
|
sleep 2
|
||||||
|
partprobe "$INTERNAL_DRIVE"
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Format EFI partition
|
||||||
|
mkfs.fat -F32 "${INTERNAL_DRIVE}p1"
|
||||||
|
|
||||||
|
log_info "Internal drive prepared with new partition structure"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create LVM structure on internal drive
|
||||||
|
create_lvm_structure() {
|
||||||
|
log_step "Creating LVM structure on internal drive..."
|
||||||
|
|
||||||
|
# Create physical volume
|
||||||
|
pvcreate "${INTERNAL_DRIVE}p2"
|
||||||
|
|
||||||
|
# Create volume group
|
||||||
|
vgcreate "$NEW_VG_NAME" "${INTERNAL_DRIVE}p2"
|
||||||
|
|
||||||
|
# Get sizes from external LVM
|
||||||
|
root_size=$(lvs --noheadings --units g --nosuffix -o lv_size "$VG_NAME/root" | tr -d ' ')
|
||||||
|
home_size=$(lvs --noheadings --units g --nosuffix -o lv_size "$VG_NAME/home" | tr -d ' ')
|
||||||
|
boot_size=$(lvs --noheadings --units g --nosuffix -o lv_size "$VG_NAME/boot" | tr -d ' ')
|
||||||
|
swap_size=$(lvs --noheadings --units g --nosuffix -o lv_size "$VG_NAME/swap" | tr -d ' ')
|
||||||
|
|
||||||
|
# Reserve 20% free space for snapshots
|
||||||
|
vg_free=$(vgs --noheadings --units g --nosuffix -o vg_free "$NEW_VG_NAME" | tr -d ' ')
|
||||||
|
snapshot_reserve=$(echo "$vg_free * 0.2" | bc -l | cut -d. -f1)
|
||||||
|
|
||||||
|
log_info "Reserving ${snapshot_reserve}GB for LVM snapshots"
|
||||||
|
|
||||||
|
# Create logical volumes with same sizes as external
|
||||||
|
lvcreate -L "${root_size}G" -n root "$NEW_VG_NAME"
|
||||||
|
lvcreate -L "${boot_size}G" -n boot "$NEW_VG_NAME"
|
||||||
|
lvcreate -L "${swap_size}G" -n swap "$NEW_VG_NAME"
|
||||||
|
|
||||||
|
# Create home with remaining space minus snapshot reserve
|
||||||
|
remaining_space=$(echo "$vg_free - $snapshot_reserve" | bc -l | cut -d. -f1)
|
||||||
|
adjusted_home_size=$(echo "$remaining_space - $root_size - $boot_size - $swap_size" | bc -l | cut -d. -f1)
|
||||||
|
|
||||||
|
if (( $(echo "$adjusted_home_size > 0" | bc -l) )); then
|
||||||
|
lvcreate -L "${adjusted_home_size}G" -n home "$NEW_VG_NAME"
|
||||||
|
else
|
||||||
|
log_warn "Using original home size, may reduce snapshot space"
|
||||||
|
lvcreate -L "${home_size}G" -n home "$NEW_VG_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create filesystems
|
||||||
|
mkfs.ext4 -L root "/dev/$NEW_VG_NAME/root"
|
||||||
|
mkfs.ext4 -L boot "/dev/$NEW_VG_NAME/boot"
|
||||||
|
mkfs.ext4 -L home "/dev/$NEW_VG_NAME/home"
|
||||||
|
mkswap -L swap "/dev/$NEW_VG_NAME/swap"
|
||||||
|
|
||||||
|
log_info "LVM structure created on internal drive"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Mount internal drive and copy data
|
||||||
|
copy_data() {
|
||||||
|
log_step "Copying data from external to internal drive..."
|
||||||
|
|
||||||
|
# Create mount points
|
||||||
|
mkdir -p /mnt/internal_root
|
||||||
|
mkdir -p /mnt/internal_boot
|
||||||
|
mkdir -p /mnt/internal_home
|
||||||
|
|
||||||
|
# Mount internal LVM
|
||||||
|
mount "/dev/$NEW_VG_NAME/root" /mnt/internal_root
|
||||||
|
mount "/dev/$NEW_VG_NAME/boot" /mnt/internal_boot
|
||||||
|
mount "/dev/$NEW_VG_NAME/home" /mnt/internal_home
|
||||||
|
|
||||||
|
# Copy data with progress
|
||||||
|
log_info "Copying root filesystem..."
|
||||||
|
rsync -avHAXS --progress / /mnt/internal_root/ \
|
||||||
|
--exclude=/dev/* \
|
||||||
|
--exclude=/proc/* \
|
||||||
|
--exclude=/sys/* \
|
||||||
|
--exclude=/tmp/* \
|
||||||
|
--exclude=/run/* \
|
||||||
|
--exclude=/mnt/* \
|
||||||
|
--exclude=/media/* \
|
||||||
|
--exclude=/lost+found \
|
||||||
|
--exclude=/boot/*
|
||||||
|
|
||||||
|
log_info "Copying boot filesystem..."
|
||||||
|
rsync -avHAXS --progress /boot/ /mnt/internal_boot/
|
||||||
|
|
||||||
|
log_info "Copying home filesystem..."
|
||||||
|
rsync -avHAXS --progress /home/ /mnt/internal_home/
|
||||||
|
|
||||||
|
log_info "Data copy completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Configure system for internal LVM boot
|
||||||
|
configure_boot() {
|
||||||
|
log_step "Configuring boot for internal LVM..."
|
||||||
|
|
||||||
|
# Mount EFI partition
|
||||||
|
mkdir -p /mnt/internal_root/boot/efi
|
||||||
|
mount "${INTERNAL_DRIVE}p1" /mnt/internal_root/boot/efi
|
||||||
|
|
||||||
|
# Chroot preparations
|
||||||
|
mount --bind /dev /mnt/internal_root/dev
|
||||||
|
mount --bind /proc /mnt/internal_root/proc
|
||||||
|
mount --bind /sys /mnt/internal_root/sys
|
||||||
|
mount --bind /run /mnt/internal_root/run
|
||||||
|
|
||||||
|
# Update fstab
|
||||||
|
cat > /mnt/internal_root/etc/fstab << EOF
|
||||||
|
# Internal LVM Configuration
|
||||||
|
/dev/$NEW_VG_NAME/root / ext4 defaults 0 1
|
||||||
|
/dev/$NEW_VG_NAME/boot /boot ext4 defaults 0 2
|
||||||
|
/dev/$NEW_VG_NAME/home /home ext4 defaults 0 2
|
||||||
|
/dev/$NEW_VG_NAME/swap none swap sw 0 0
|
||||||
|
${INTERNAL_DRIVE}p1 /boot/efi vfat umask=0077 0 1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Update initramfs to include LVM
|
||||||
|
chroot /mnt/internal_root /bin/bash -c "update-initramfs -u -k all"
|
||||||
|
|
||||||
|
# Install and configure GRUB
|
||||||
|
chroot /mnt/internal_root /bin/bash -c "grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=debian"
|
||||||
|
chroot /mnt/internal_root /bin/bash -c "update-grub"
|
||||||
|
|
||||||
|
# Cleanup mounts
|
||||||
|
umount /mnt/internal_root/dev
|
||||||
|
umount /mnt/internal_root/proc
|
||||||
|
umount /mnt/internal_root/sys
|
||||||
|
umount /mnt/internal_root/run
|
||||||
|
umount /mnt/internal_root/boot/efi
|
||||||
|
|
||||||
|
log_info "Boot configuration completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup LVM snapshots
|
||||||
|
setup_snapshots() {
|
||||||
|
log_step "Setting up LVM snapshot capability..."
|
||||||
|
|
||||||
|
# Create snapshot management script
|
||||||
|
cat > /mnt/internal_root/usr/local/bin/lvm-snapshot-manager << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# LVM Snapshot Manager
|
||||||
|
|
||||||
|
VG_NAME="internal-vg"
|
||||||
|
SNAPSHOT_SIZE="10G" # Adjust based on available space
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
create)
|
||||||
|
echo "Creating LVM snapshots..."
|
||||||
|
lvcreate -L $SNAPSHOT_SIZE -s -n root_snapshot $VG_NAME/root
|
||||||
|
lvcreate -L $SNAPSHOT_SIZE -s -n home_snapshot $VG_NAME/home
|
||||||
|
echo "Snapshots created successfully"
|
||||||
|
;;
|
||||||
|
remove)
|
||||||
|
echo "Removing LVM snapshots..."
|
||||||
|
lvremove -f $VG_NAME/root_snapshot 2>/dev/null || true
|
||||||
|
lvremove -f $VG_NAME/home_snapshot 2>/dev/null || true
|
||||||
|
echo "Snapshots removed"
|
||||||
|
;;
|
||||||
|
list)
|
||||||
|
echo "Current snapshots:"
|
||||||
|
lvs $VG_NAME | grep snapshot || echo "No snapshots found"
|
||||||
|
;;
|
||||||
|
merge)
|
||||||
|
if [[ -z "$2" ]]; then
|
||||||
|
echo "Usage: $0 merge <snapshot_name>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Merging snapshot $2..."
|
||||||
|
lvconvert --merge $VG_NAME/$2
|
||||||
|
echo "Snapshot merge initiated (requires reboot to complete)"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {create|remove|list|merge <snapshot_name>}"
|
||||||
|
echo " create - Create snapshots of root and home"
|
||||||
|
echo " remove - Remove all snapshots"
|
||||||
|
echo " list - List existing snapshots"
|
||||||
|
echo " merge - Merge a snapshot back to origin"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x /mnt/internal_root/usr/local/bin/lvm-snapshot-manager
|
||||||
|
|
||||||
|
# Create backup script using snapshots
|
||||||
|
cat > /mnt/internal_root/usr/local/bin/snapshot-backup << 'EOF'
|
||||||
|
#!/bin/bash
|
||||||
|
# Snapshot-based backup script
|
||||||
|
|
||||||
|
BACKUP_DIR="/backup"
|
||||||
|
VG_NAME="internal-vg"
|
||||||
|
DATE=$(date +%Y%m%d_%H%M%S)
|
||||||
|
|
||||||
|
# Create snapshots
|
||||||
|
echo "Creating snapshots..."
|
||||||
|
/usr/local/bin/lvm-snapshot-manager create
|
||||||
|
|
||||||
|
# Mount snapshots and backup
|
||||||
|
mkdir -p $BACKUP_DIR/root_$DATE
|
||||||
|
mkdir -p $BACKUP_DIR/home_$DATE
|
||||||
|
|
||||||
|
mount /dev/$VG_NAME/root_snapshot $BACKUP_DIR/root_$DATE
|
||||||
|
mount /dev/$VG_NAME/home_snapshot $BACKUP_DIR/home_$DATE
|
||||||
|
|
||||||
|
echo "Snapshots mounted. You can now backup from:"
|
||||||
|
echo " Root: $BACKUP_DIR/root_$DATE"
|
||||||
|
echo " Home: $BACKUP_DIR/home_$DATE"
|
||||||
|
echo ""
|
||||||
|
echo "When done, run: umount $BACKUP_DIR/root_$DATE $BACKUP_DIR/home_$DATE"
|
||||||
|
echo "Then run: /usr/local/bin/lvm-snapshot-manager remove"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod +x /mnt/internal_root/usr/local/bin/snapshot-backup
|
||||||
|
|
||||||
|
log_info "LVM snapshot tools installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup and unmount
|
||||||
|
cleanup() {
|
||||||
|
log_step "Cleaning up..."
|
||||||
|
|
||||||
|
# Unmount all internal mounts
|
||||||
|
umount /mnt/internal_home || true
|
||||||
|
umount /mnt/internal_boot || true
|
||||||
|
umount /mnt/internal_root || true
|
||||||
|
|
||||||
|
# Remove mount points
|
||||||
|
rmdir /mnt/internal_home /mnt/internal_boot /mnt/internal_root 2>/dev/null || true
|
||||||
|
|
||||||
|
log_info "Cleanup completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main migration function
|
||||||
|
main() {
|
||||||
|
log_info "Starting LVM migration from external M.2 to internal NVMe"
|
||||||
|
log_info "External: $EXTERNAL_DRIVE -> Internal: $INTERNAL_DRIVE"
|
||||||
|
|
||||||
|
safety_checks
|
||||||
|
create_backup_dir
|
||||||
|
prepare_internal_drive
|
||||||
|
create_lvm_structure
|
||||||
|
copy_data
|
||||||
|
configure_boot
|
||||||
|
setup_snapshots
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
log_info "Migration completed successfully!"
|
||||||
|
echo
|
||||||
|
echo -e "${GREEN}SUCCESS!${NC} LVM migration completed"
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Reboot and select internal drive in BIOS/UEFI"
|
||||||
|
echo "2. Verify system boots correctly from internal LVM"
|
||||||
|
echo "3. Test snapshot functionality with: sudo lvm-snapshot-manager create"
|
||||||
|
echo "4. Once confirmed working, you can repurpose the external M.2"
|
||||||
|
echo
|
||||||
|
echo "Snapshot management commands:"
|
||||||
|
echo " sudo lvm-snapshot-manager create # Create snapshots"
|
||||||
|
echo " sudo lvm-snapshot-manager list # List snapshots"
|
||||||
|
echo " sudo lvm-snapshot-manager remove # Remove snapshots"
|
||||||
|
echo " sudo snapshot-backup # Backup using snapshots"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle interruption
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Run main function
|
||||||
|
main "$@"
|
||||||
75
preview_migration.sh
Executable file
75
preview_migration.sh
Executable file
@@ -0,0 +1,75 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# LVM Migration Preview Script
|
||||||
|
# Shows current status and what the migration will do
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${BLUE}=== LVM Migration Preview ===${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Current Boot Status:${NC}"
|
||||||
|
echo "Root mounted from: $(findmnt -n -o SOURCE /)"
|
||||||
|
echo "Boot mounted from: $(findmnt -n -o SOURCE /boot)"
|
||||||
|
echo "Home mounted from: $(findmnt -n -o SOURCE /home)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Current LVM Structure (External M.2):${NC}"
|
||||||
|
sudo vgs migration-vg 2>/dev/null || echo "No VG found"
|
||||||
|
echo
|
||||||
|
sudo lvs migration-vg 2>/dev/null || echo "No LVs found"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Current Drive Layout:${NC}"
|
||||||
|
echo "External M.2 (sda):"
|
||||||
|
lsblk /dev/sda
|
||||||
|
echo
|
||||||
|
echo "Internal NVMe (nvme0n1):"
|
||||||
|
lsblk /dev/nvme0n1
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Available Space Analysis:${NC}"
|
||||||
|
echo "External VG size: $(sudo vgs --noheadings --units g -o vg_size migration-vg | tr -d ' ')B"
|
||||||
|
echo "External VG free: $(sudo vgs --noheadings --units g -o vg_free migration-vg | tr -d ' ')B"
|
||||||
|
echo "Internal drive size: $(lsblk -b -n -o SIZE /dev/nvme0n1 | awk '{printf "%.1fGB", $1/1024/1024/1024}')"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Migration Plan:${NC}"
|
||||||
|
echo "1. ✅ Wipe internal NVMe drive completely"
|
||||||
|
echo "2. ✅ Create new GPT partition table"
|
||||||
|
echo "3. ✅ Create EFI boot partition (512MB)"
|
||||||
|
echo "4. ✅ Create LVM partition (remaining space)"
|
||||||
|
echo "5. ✅ Set up LVM with volume group 'internal-vg'"
|
||||||
|
echo "6. ✅ Create logical volumes matching current structure"
|
||||||
|
echo "7. ✅ Copy all data from external to internal"
|
||||||
|
echo "8. ✅ Configure GRUB for LVM boot"
|
||||||
|
echo "9. ✅ Set up LVM snapshot capabilities"
|
||||||
|
echo "10. ✅ Reserve 20% space for snapshots"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${RED}⚠️ WARNINGS:${NC}"
|
||||||
|
echo "• This will COMPLETELY WIPE the internal NVMe drive"
|
||||||
|
echo "• All current data on internal drive will be lost"
|
||||||
|
echo "• Make sure you're booted from external M.2 (verified above)"
|
||||||
|
echo "• Ensure external M.2 LED is active/blinking"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Snapshot Features After Migration:${NC}"
|
||||||
|
echo "• lvm-snapshot-manager create - Create system snapshots"
|
||||||
|
echo "• lvm-snapshot-manager list - List existing snapshots"
|
||||||
|
echo "• lvm-snapshot-manager remove - Remove snapshots"
|
||||||
|
echo "• lvm-snapshot-manager merge - Restore from snapshot"
|
||||||
|
echo "• snapshot-backup - Backup using snapshots"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${BLUE}Ready to proceed?${NC}"
|
||||||
|
echo "Run: sudo ./migrate_lvm_to_internal.sh"
|
||||||
|
echo
|
||||||
|
echo -e "${YELLOW}Estimated time: 2-4 hours depending on data size${NC}"
|
||||||
104
preview_snapshot_migration.sh
Executable file
104
preview_snapshot_migration.sh
Executable file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Snapshot Migration Preview Script
|
||||||
|
# Shows what the snapshot-based migration will do
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
RED='\033[0;31m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
echo -e "${BLUE}=== Snapshot-Based LVM Migration Preview ===${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Current System Status:${NC}"
|
||||||
|
echo "✅ Booted from: $(findmnt -n -o SOURCE /)"
|
||||||
|
echo "✅ Volume Group: migration-vg"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Current Logical Volumes:${NC}"
|
||||||
|
sudo lvs migration-vg --units g -o lv_name,lv_size,data_percent 2>/dev/null
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Available Space for Snapshots:${NC}"
|
||||||
|
free_space=$(sudo vgs --noheadings --units m --nosuffix -o vg_free migration-vg | tr -d ' ' | tr ',' '.')
|
||||||
|
if command -v bc >/dev/null 2>&1; then
|
||||||
|
snapshot_size_per_lv=$(echo "$free_space * 0.8 / 4" | bc 2>/dev/null | cut -d. -f1)
|
||||||
|
else
|
||||||
|
snapshot_size_per_lv=$((${free_space%.*} * 80 / 100 / 4))
|
||||||
|
fi
|
||||||
|
echo "Free space: ${free_space}MB"
|
||||||
|
echo "Snapshot size per LV: ${snapshot_size_per_lv}MB"
|
||||||
|
|
||||||
|
if (( snapshot_size_per_lv < 100 )); then
|
||||||
|
echo -e "${RED}⚠️ WARNING: Limited space for snapshots!${NC}"
|
||||||
|
echo "Consider freeing up space or expanding the volume group"
|
||||||
|
else
|
||||||
|
echo -e "${GREEN}✅ Sufficient space for snapshots${NC}"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Target Drive Analysis:${NC}"
|
||||||
|
echo "Internal NVMe (nvme0n1):"
|
||||||
|
lsblk /dev/nvme0n1
|
||||||
|
echo "Size: $(lsblk -b -n -o SIZE /dev/nvme0n1 | awk '{printf "%.1fGB", $1/1024/1024/1024}')"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${YELLOW}Snapshot Migration Process:${NC}"
|
||||||
|
echo "1. 📸 Create temporary snapshots of ALL logical volumes:"
|
||||||
|
echo " • root (${snapshot_size_per_lv}MB snapshot)"
|
||||||
|
echo " • home (${snapshot_size_per_lv}MB snapshot)"
|
||||||
|
echo " • boot (${snapshot_size_per_lv}MB snapshot)"
|
||||||
|
echo " • swap (${snapshot_size_per_lv}MB snapshot)"
|
||||||
|
echo
|
||||||
|
echo "2. 🔧 Prepare internal drive:"
|
||||||
|
echo " • Copy partition table from external M.2"
|
||||||
|
echo " • Create LVM physical volume"
|
||||||
|
echo " • Create volume group 'internal-vg'"
|
||||||
|
echo " • Create logical volumes with exact same sizes"
|
||||||
|
echo
|
||||||
|
echo "3. 📋 Transfer data using block-level copy:"
|
||||||
|
echo " • Use dd to copy each snapshot to internal LV"
|
||||||
|
echo " • Process one LV at a time to manage space"
|
||||||
|
echo " • Remove each snapshot after successful copy"
|
||||||
|
echo
|
||||||
|
echo "4. ⚙️ Configure boot:"
|
||||||
|
echo " • Update fstab for new volume group"
|
||||||
|
echo " • Install GRUB on internal drive"
|
||||||
|
echo " • Update initramfs for LVM"
|
||||||
|
echo
|
||||||
|
echo "5. 🛠️ Setup snapshot tools:"
|
||||||
|
echo " • Install lvm-snapshot-manager"
|
||||||
|
echo " • Reserve space for future snapshots"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${RED}⚠️ CRITICAL WARNINGS:${NC}"
|
||||||
|
echo "• Internal NVMe will be COMPLETELY WIPED"
|
||||||
|
echo "• This creates an EXACT copy including all current data"
|
||||||
|
echo "• Process takes 1-3 hours depending on data size"
|
||||||
|
echo "• Snapshots use limited available space"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Advantages of Snapshot Method:${NC}"
|
||||||
|
echo "✅ Exact bit-for-bit copy of live system"
|
||||||
|
echo "✅ No filesystem corruption risks"
|
||||||
|
echo "✅ Can capture running system state"
|
||||||
|
echo "✅ Uses LVM native capabilities"
|
||||||
|
echo "✅ Block-level transfer (faster than file copy)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${GREEN}Post-Migration Capabilities:${NC}"
|
||||||
|
echo "• sudo lvm-snapshot-manager create - Create system snapshots"
|
||||||
|
echo "• sudo lvm-snapshot-manager list - Show snapshots"
|
||||||
|
echo "• sudo lvm-snapshot-manager remove - Clean up snapshots"
|
||||||
|
echo "• sudo lvm-snapshot-manager merge - Restore from snapshot"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo -e "${BLUE}Ready to proceed with snapshot migration?${NC}"
|
||||||
|
echo "Run: sudo ./snapshot_migrate_to_internal.sh"
|
||||||
|
echo
|
||||||
|
echo -e "${YELLOW}Estimated time: 1-3 hours${NC}"
|
||||||
367
snapshot_migrate_to_internal.sh
Executable file
367
snapshot_migrate_to_internal.sh
Executable file
@@ -0,0 +1,367 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Snapshot-Based LVM Migration Script: External M.2 to Internal NVMe
|
||||||
|
# Creates snapshots of ALL partitions and transfers them to internal drive
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# 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
|
||||||
|
EXTERNAL_DRIVE="/dev/sda"
|
||||||
|
INTERNAL_DRIVE="/dev/nvme0n1"
|
||||||
|
SOURCE_VG="migration-vg"
|
||||||
|
TARGET_VG="internal-vg"
|
||||||
|
BACKUP_DIR="/tmp/lvm_snapshot_migration"
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_FILE="/var/log/lvm_snapshot_migration.log"
|
||||||
|
exec 1> >(tee -a "$LOG_FILE")
|
||||||
|
exec 2> >(tee -a "$LOG_FILE" >&2)
|
||||||
|
|
||||||
|
log_info() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_step() {
|
||||||
|
echo -e "${BLUE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S'): $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Safety checks
|
||||||
|
safety_checks() {
|
||||||
|
log_step "Performing safety checks..."
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
log_error "This script must be run as root (use sudo)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify we're booted from external drive
|
||||||
|
root_device=$(findmnt -n -o SOURCE /)
|
||||||
|
if [[ "$root_device" != "/dev/mapper/migration--vg-root" ]]; then
|
||||||
|
log_error "Not booted from external LVM! Current root: $root_device"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check drives exist
|
||||||
|
if [[ ! -b "$EXTERNAL_DRIVE" ]] || [[ ! -b "$INTERNAL_DRIVE" ]]; then
|
||||||
|
log_error "Required drives not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check LVM tools
|
||||||
|
if ! command -v lvcreate &> /dev/null; then
|
||||||
|
log_error "LVM tools not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Safety checks passed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create backup directory and metadata
|
||||||
|
create_backup_metadata() {
|
||||||
|
log_step "Creating backup metadata..."
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Backup LVM metadata
|
||||||
|
vgcfgbackup -f "$BACKUP_DIR/vg_backup" "$SOURCE_VG"
|
||||||
|
|
||||||
|
# Save current LV information
|
||||||
|
lvs "$SOURCE_VG" > "$BACKUP_DIR/lv_info.txt"
|
||||||
|
vgs "$SOURCE_VG" > "$BACKUP_DIR/vg_info.txt"
|
||||||
|
pvs > "$BACKUP_DIR/pv_info.txt"
|
||||||
|
|
||||||
|
# Save partition information
|
||||||
|
lsblk > "$BACKUP_DIR/lsblk_before.txt"
|
||||||
|
|
||||||
|
log_info "Backup metadata created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prepare internal drive with identical structure
|
||||||
|
prepare_internal_drive() {
|
||||||
|
log_step "Preparing internal drive..."
|
||||||
|
|
||||||
|
echo -e "${RED}WARNING: This will completely wipe $INTERNAL_DRIVE${NC}"
|
||||||
|
read -p "Type 'YES' to continue: " confirm
|
||||||
|
if [[ "$confirm" != "YES" ]]; then
|
||||||
|
log_error "Migration cancelled"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Clean up any existing mounts/LVM on internal drive
|
||||||
|
for mount in $(findmnt -n -o TARGET -S "$INTERNAL_DRIVE"* 2>/dev/null || true); do
|
||||||
|
umount "$mount" || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Deactivate any existing VGs on internal drive
|
||||||
|
for vg in $(vgs --noheadings -o vg_name 2>/dev/null | grep -v "$SOURCE_VG" || true); do
|
||||||
|
vgchange -an "$vg" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wipe the drive
|
||||||
|
wipefs -af "$INTERNAL_DRIVE"
|
||||||
|
|
||||||
|
# Create identical partition structure to external drive
|
||||||
|
log_info "Creating partition table..."
|
||||||
|
sfdisk -d "$EXTERNAL_DRIVE" | sfdisk "$INTERNAL_DRIVE"
|
||||||
|
|
||||||
|
# Wait for partitions to appear
|
||||||
|
sleep 3
|
||||||
|
partprobe "$INTERNAL_DRIVE"
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
log_info "Internal drive partitioned"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create LVM structure on internal drive
|
||||||
|
setup_internal_lvm() {
|
||||||
|
log_step "Setting up LVM on internal drive..."
|
||||||
|
|
||||||
|
# Create physical volume on the LVM partition
|
||||||
|
pvcreate "${INTERNAL_DRIVE}p2" -ff
|
||||||
|
|
||||||
|
# Create volume group with extra space for snapshots
|
||||||
|
vgcreate "$TARGET_VG" "${INTERNAL_DRIVE}p2"
|
||||||
|
|
||||||
|
# Get exact sizes from source LVs
|
||||||
|
declare -A lv_sizes
|
||||||
|
while IFS= read -r line; do
|
||||||
|
lv_name=$(echo "$line" | awk '{print $1}')
|
||||||
|
lv_size=$(echo "$line" | awk '{print $2}')
|
||||||
|
lv_sizes["$lv_name"]="$lv_size"
|
||||||
|
done < <(lvs --noheadings --units b --nosuffix -o lv_name,lv_size "$SOURCE_VG")
|
||||||
|
|
||||||
|
# Create LVs with exact same sizes
|
||||||
|
for lv in root home boot swap; do
|
||||||
|
if [[ -n "${lv_sizes[$lv]:-}" ]]; then
|
||||||
|
size_bytes="${lv_sizes[$lv]}"
|
||||||
|
log_info "Creating LV $lv with size $size_bytes bytes"
|
||||||
|
lvcreate -L "${size_bytes}b" -n "$lv" "$TARGET_VG"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log_info "Internal LVM structure created"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create temporary snapshots and transfer via dd
|
||||||
|
transfer_with_snapshots() {
|
||||||
|
log_step "Transferring data using snapshots..."
|
||||||
|
|
||||||
|
# Calculate optimal snapshot size (use available free space)
|
||||||
|
free_space=$(vgs --noheadings --units m --nosuffix -o vg_free "$SOURCE_VG" | tr -d ' ' | tr ',' '.')
|
||||||
|
# Use 80% of free space for snapshots, divided by number of LVs
|
||||||
|
snapshot_size=$(echo "$free_space * 0.8 / 4" | bc | cut -d. -f1)
|
||||||
|
|
||||||
|
if (( snapshot_size < 100 )); then
|
||||||
|
log_error "Not enough free space for snapshots. Need at least 400MB free."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_info "Using ${snapshot_size}MB for each snapshot"
|
||||||
|
|
||||||
|
# Process each logical volume
|
||||||
|
for lv in root home boot swap; do
|
||||||
|
log_step "Processing $lv..."
|
||||||
|
|
||||||
|
# Create snapshot
|
||||||
|
log_info "Creating snapshot of $lv..."
|
||||||
|
if ! lvcreate -L "${snapshot_size}M" -s -n "${lv}_snapshot" "$SOURCE_VG/$lv"; then
|
||||||
|
log_error "Failed to create snapshot for $lv"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy data using dd with progress
|
||||||
|
log_info "Copying $lv data to internal drive..."
|
||||||
|
if [[ "$lv" == "swap" ]]; then
|
||||||
|
# For swap, just copy the LV structure
|
||||||
|
dd if="/dev/$SOURCE_VG/${lv}_snapshot" of="/dev/$TARGET_VG/$lv" bs=1M status=progress
|
||||||
|
else
|
||||||
|
# For filesystems, use dd for exact copy
|
||||||
|
dd if="/dev/$SOURCE_VG/${lv}_snapshot" of="/dev/$TARGET_VG/$lv" bs=1M status=progress
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove snapshot to free space for next one
|
||||||
|
log_info "Removing snapshot of $lv..."
|
||||||
|
lvremove -f "$SOURCE_VG/${lv}_snapshot"
|
||||||
|
|
||||||
|
log_info "Completed transfer of $lv"
|
||||||
|
done
|
||||||
|
|
||||||
|
log_info "All data transferred successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup boot for internal drive
|
||||||
|
configure_internal_boot() {
|
||||||
|
log_step "Configuring boot for internal drive..."
|
||||||
|
|
||||||
|
# Format and mount EFI partition
|
||||||
|
mkfs.fat -F32 "${INTERNAL_DRIVE}p1" || true
|
||||||
|
mkdir -p /mnt/internal_efi
|
||||||
|
mount "${INTERNAL_DRIVE}p1" /mnt/internal_efi
|
||||||
|
|
||||||
|
# Mount internal filesystems
|
||||||
|
mkdir -p /mnt/internal_root /mnt/internal_boot /mnt/internal_home
|
||||||
|
mount "/dev/$TARGET_VG/root" /mnt/internal_root
|
||||||
|
mount "/dev/$TARGET_VG/boot" /mnt/internal_boot
|
||||||
|
mount "/dev/$TARGET_VG/home" /mnt/internal_home
|
||||||
|
|
||||||
|
# Mount EFI in the target system
|
||||||
|
mkdir -p /mnt/internal_root/boot/efi
|
||||||
|
mount "${INTERNAL_DRIVE}p1" /mnt/internal_root/boot/efi
|
||||||
|
|
||||||
|
# Update fstab for new VG
|
||||||
|
log_info "Updating fstab..."
|
||||||
|
cat > /mnt/internal_root/etc/fstab << EOF
|
||||||
|
# Internal LVM Configuration
|
||||||
|
/dev/$TARGET_VG/root / ext4 defaults 0 1
|
||||||
|
/dev/$TARGET_VG/boot /boot ext4 defaults 0 2
|
||||||
|
/dev/$TARGET_VG/home /home ext4 defaults 0 2
|
||||||
|
/dev/$TARGET_VG/swap none swap sw 0 0
|
||||||
|
${INTERNAL_DRIVE}p1 /boot/efi vfat umask=0077 0 1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Prepare chroot environment
|
||||||
|
mount --bind /dev /mnt/internal_root/dev
|
||||||
|
mount --bind /proc /mnt/internal_root/proc
|
||||||
|
mount --bind /sys /mnt/internal_root/sys
|
||||||
|
mount --bind /run /mnt/internal_root/run
|
||||||
|
|
||||||
|
# Update initramfs and install GRUB
|
||||||
|
log_info "Updating initramfs and GRUB..."
|
||||||
|
chroot /mnt/internal_root /bin/bash -c "update-initramfs -u -k all"
|
||||||
|
chroot /mnt/internal_root /bin/bash -c "grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=Internal-LVM"
|
||||||
|
chroot /mnt/internal_root /bin/bash -c "update-grub"
|
||||||
|
|
||||||
|
# Clean up mounts
|
||||||
|
umount /mnt/internal_root/dev /mnt/internal_root/proc /mnt/internal_root/sys /mnt/internal_root/run
|
||||||
|
umount /mnt/internal_root/boot/efi
|
||||||
|
umount /mnt/internal_efi /mnt/internal_root /mnt/internal_boot /mnt/internal_home
|
||||||
|
|
||||||
|
log_info "Boot configuration completed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup snapshot capabilities on internal drive
|
||||||
|
setup_snapshot_tools() {
|
||||||
|
log_step "Setting up snapshot tools on internal drive..."
|
||||||
|
|
||||||
|
# Remount for tool installation
|
||||||
|
mount "/dev/$TARGET_VG/root" /mnt/internal_root
|
||||||
|
|
||||||
|
# Create snapshot management script
|
||||||
|
cat > /mnt/internal_root/usr/local/bin/lvm-snapshot-manager << 'EOFSCRIPT'
|
||||||
|
#!/bin/bash
|
||||||
|
# LVM Snapshot Manager for Internal Drive
|
||||||
|
|
||||||
|
VG_NAME="internal-vg"
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
create)
|
||||||
|
echo "Creating LVM snapshots..."
|
||||||
|
# Calculate available space for snapshots
|
||||||
|
free_space=$(vgs --noheadings --units g --nosuffix -o vg_free "$VG_NAME" | tr -d ' ')
|
||||||
|
snapshot_size=$(echo "$free_space / 4" | bc)G
|
||||||
|
|
||||||
|
lvcreate -L "$snapshot_size" -s -n root_backup "$VG_NAME/root"
|
||||||
|
lvcreate -L "$snapshot_size" -s -n home_backup "$VG_NAME/home"
|
||||||
|
lvcreate -L "$snapshot_size" -s -n boot_backup "$VG_NAME/boot"
|
||||||
|
echo "Snapshots created with size: $snapshot_size each"
|
||||||
|
;;
|
||||||
|
remove)
|
||||||
|
echo "Removing LVM snapshots..."
|
||||||
|
lvremove -f "$VG_NAME/root_backup" 2>/dev/null || true
|
||||||
|
lvremove -f "$VG_NAME/home_backup" 2>/dev/null || true
|
||||||
|
lvremove -f "$VG_NAME/boot_backup" 2>/dev/null || true
|
||||||
|
echo "Snapshots removed"
|
||||||
|
;;
|
||||||
|
list)
|
||||||
|
echo "Current snapshots:"
|
||||||
|
lvs "$VG_NAME" | grep backup || echo "No snapshots found"
|
||||||
|
;;
|
||||||
|
merge)
|
||||||
|
if [[ -z "$2" ]]; then
|
||||||
|
echo "Usage: $0 merge <snapshot_name>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Merging snapshot $2..."
|
||||||
|
lvconvert --merge "$VG_NAME/$2"
|
||||||
|
echo "Snapshot merge initiated (reboot required to complete)"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 {create|remove|list|merge <snapshot_name>}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
EOFSCRIPT
|
||||||
|
|
||||||
|
chmod +x /mnt/internal_root/usr/local/bin/lvm-snapshot-manager
|
||||||
|
|
||||||
|
umount /mnt/internal_root
|
||||||
|
|
||||||
|
log_info "Snapshot tools installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Cleanup function
|
||||||
|
cleanup() {
|
||||||
|
log_info "Cleaning up..."
|
||||||
|
|
||||||
|
# Remove any remaining snapshots
|
||||||
|
for snap in $(lvs --noheadings -o lv_name "$SOURCE_VG" 2>/dev/null | grep snapshot || true); do
|
||||||
|
lvremove -f "$SOURCE_VG/$snap" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
# Unmount any remaining mounts
|
||||||
|
for mount in /mnt/internal_*; do
|
||||||
|
umount "$mount" 2>/dev/null || true
|
||||||
|
rmdir "$mount" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main migration function
|
||||||
|
main() {
|
||||||
|
log_info "Starting snapshot-based LVM migration"
|
||||||
|
log_info "Source: $EXTERNAL_DRIVE ($SOURCE_VG) -> Target: $INTERNAL_DRIVE ($TARGET_VG)"
|
||||||
|
|
||||||
|
safety_checks
|
||||||
|
create_backup_metadata
|
||||||
|
prepare_internal_drive
|
||||||
|
setup_internal_lvm
|
||||||
|
transfer_with_snapshots
|
||||||
|
configure_internal_boot
|
||||||
|
setup_snapshot_tools
|
||||||
|
cleanup
|
||||||
|
|
||||||
|
log_info "Migration completed successfully!"
|
||||||
|
echo
|
||||||
|
echo -e "${GREEN}SUCCESS!${NC} Snapshot-based LVM migration completed"
|
||||||
|
echo
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Reboot and select internal drive in BIOS/UEFI"
|
||||||
|
echo "2. Verify all systems working from internal LVM"
|
||||||
|
echo "3. Test snapshot functionality: sudo lvm-snapshot-manager create"
|
||||||
|
echo "4. External M.2 can now be used as backup drive"
|
||||||
|
echo
|
||||||
|
echo "The internal drive now has:"
|
||||||
|
echo "- Complete copy of your current system"
|
||||||
|
echo "- LVM with snapshot capabilities"
|
||||||
|
echo "- Reserved space for future snapshots"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle interruption
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Run migration
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user