feat: Add Borg Backup support to simple LVM backup system
- Add LV → Borg and VG → Borg backup modes - GUI: Borg settings panel with repo path, encryption, passphrase - CLI: Enhanced script with Borg options (--new-repo, --encryption, --passphrase) - Automatic repository initialization for new repos - Support for all Borg encryption modes (none, repokey, keyfile) - Mount snapshots temporarily for file-level Borg backups - Comprehensive cleanup of snapshots and mount points - Updated documentation and examples Benefits: - Deduplication and compression - Strong encryption support - Incremental backups capability - Space-efficient storage - Still maintains simple snapshot → backup → cleanup workflow
This commit is contained in:
@@ -16,22 +16,33 @@ BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
usage() {
|
||||
echo "Enhanced Simple LVM Backup Script"
|
||||
echo "Enhanced Simple LVM Backup Script with Borg Support"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " $0 lv-to-lv SOURCE_LV TARGET_LV"
|
||||
echo " $0 lv-to-raw SOURCE_LV TARGET_DEVICE"
|
||||
echo " $0 vg-to-raw SOURCE_VG TARGET_DEVICE"
|
||||
echo " $0 lv-to-borg SOURCE_LV REPO_PATH [--new-repo] [--encryption MODE] [--passphrase PASS]"
|
||||
echo " $0 vg-to-borg SOURCE_VG REPO_PATH [--new-repo] [--encryption MODE] [--passphrase PASS]"
|
||||
echo ""
|
||||
echo "Modes:"
|
||||
echo " lv-to-lv - Update existing LV backup (SOURCE_LV → TARGET_LV)"
|
||||
echo " lv-to-raw - Create fresh backup (SOURCE_LV → raw device)"
|
||||
echo " vg-to-raw - Clone entire VG (SOURCE_VG → raw device)"
|
||||
echo " lv-to-borg - Backup LV to Borg repository"
|
||||
echo " vg-to-borg - Backup entire VG to Borg repository"
|
||||
echo ""
|
||||
echo "Borg Options:"
|
||||
echo " --new-repo Create new repository"
|
||||
echo " --encryption MODE Encryption mode: none, repokey, keyfile (default: repokey)"
|
||||
echo " --passphrase PASS Repository passphrase"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 lv-to-lv /dev/internal-vg/root /dev/backup-vg/root"
|
||||
echo " $0 lv-to-raw /dev/internal-vg/root /dev/sdb"
|
||||
echo " $0 vg-to-raw internal-vg /dev/sdb"
|
||||
echo " $0 lv-to-borg /dev/internal-vg/root /path/to/borg/repo --new-repo"
|
||||
echo " $0 vg-to-borg internal-vg /path/to/borg/repo --encryption repokey --passphrase mypass"
|
||||
echo ""
|
||||
echo "List available sources/targets:"
|
||||
echo " ./list_drives.sh"
|
||||
@@ -70,14 +81,40 @@ cleanup_and_exit() {
|
||||
# Trap for cleanup
|
||||
trap 'cleanup_and_exit 130' INT TERM
|
||||
|
||||
# Check arguments
|
||||
if [ $# -ne 3 ]; then
|
||||
# Parse arguments and options
|
||||
if [ $# -lt 3 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
MODE="$1"
|
||||
SOURCE="$2"
|
||||
TARGET="$3"
|
||||
shift 3
|
||||
|
||||
# Parse Borg-specific options
|
||||
NEW_REPO=false
|
||||
ENCRYPTION="repokey"
|
||||
PASSPHRASE=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--new-repo)
|
||||
NEW_REPO=true
|
||||
shift
|
||||
;;
|
||||
--encryption)
|
||||
ENCRYPTION="$2"
|
||||
shift 2
|
||||
;;
|
||||
--passphrase)
|
||||
PASSPHRASE="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
error "Unknown option: $1"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
@@ -86,13 +123,25 @@ fi
|
||||
|
||||
# Validate mode
|
||||
case "$MODE" in
|
||||
"lv-to-lv"|"lv-to-raw"|"vg-to-raw")
|
||||
"lv-to-lv"|"lv-to-raw"|"vg-to-raw"|"lv-to-borg"|"vg-to-borg")
|
||||
;;
|
||||
*)
|
||||
error "Invalid mode: $MODE"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check Borg requirements for Borg modes
|
||||
if [[ "$MODE" == *"-to-borg" ]]; then
|
||||
if ! command -v borg >/dev/null 2>&1; then
|
||||
error "Borg Backup is not installed. Please install it: sudo apt install borgbackup"
|
||||
fi
|
||||
|
||||
# Set up Borg environment
|
||||
if [ -n "$PASSPHRASE" ]; then
|
||||
export BORG_PASSPHRASE="$PASSPHRASE"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Enhanced Simple LVM Backup"
|
||||
log "Mode: $MODE"
|
||||
log "Source: $SOURCE"
|
||||
@@ -236,6 +285,174 @@ case "$MODE" in
|
||||
log "VG to raw device backup completed successfully"
|
||||
log "Target device now contains complete LVM structure"
|
||||
;;
|
||||
|
||||
"lv-to-borg")
|
||||
# LV to Borg repository backup
|
||||
if [ ! -e "$SOURCE" ]; then
|
||||
error "Source LV does not exist: $SOURCE"
|
||||
fi
|
||||
|
||||
# Extract VG and LV names
|
||||
VG_NAME=$(lvs --noheadings -o vg_name "$SOURCE" | tr -d ' ')
|
||||
LV_NAME=$(lvs --noheadings -o lv_name "$SOURCE" | tr -d ' ')
|
||||
SNAPSHOT_NAME="${LV_NAME}_borg_snap"
|
||||
SNAPSHOT_PATH="/dev/$VG_NAME/$SNAPSHOT_NAME"
|
||||
|
||||
info "This will backup LV to Borg repository"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Source LV: $SOURCE${NC}"
|
||||
echo -e "${YELLOW}Repository: $TARGET${NC}"
|
||||
if [ "$NEW_REPO" = true ]; then
|
||||
echo -e "${BLUE}Will create new repository${NC}"
|
||||
else
|
||||
echo -e "${BLUE}Will add to existing repository${NC}"
|
||||
fi
|
||||
echo -e "${BLUE}Encryption: $ENCRYPTION${NC}"
|
||||
echo ""
|
||||
read -p "Continue? (yes/no): " confirm
|
||||
|
||||
if [ "$confirm" != "yes" ]; then
|
||||
echo "Backup cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize repository if needed
|
||||
if [ "$NEW_REPO" = true ]; then
|
||||
log "Creating new Borg repository: $TARGET"
|
||||
if [ "$ENCRYPTION" = "none" ]; then
|
||||
borg init --encryption=none "$TARGET" || error "Failed to initialize repository"
|
||||
else
|
||||
borg init --encryption="$ENCRYPTION" "$TARGET" || error "Failed to initialize repository"
|
||||
fi
|
||||
log "Repository initialized successfully"
|
||||
fi
|
||||
|
||||
log "Creating snapshot of source LV"
|
||||
lvcreate -L1G -s -n "$SNAPSHOT_NAME" "$SOURCE" || error "Failed to create snapshot"
|
||||
|
||||
# Create temporary mount point
|
||||
TEMP_MOUNT=$(mktemp -d -t borg_backup_XXXXXX)
|
||||
|
||||
# Mount snapshot
|
||||
log "Mounting snapshot to $TEMP_MOUNT"
|
||||
mount "$SNAPSHOT_PATH" "$TEMP_MOUNT" || error "Failed to mount snapshot"
|
||||
|
||||
# Create Borg archive
|
||||
ARCHIVE_NAME="lv_${LV_NAME}_$(date +%Y%m%d_%H%M%S)"
|
||||
log "Creating Borg archive: $ARCHIVE_NAME"
|
||||
log "This may take a long time depending on data size..."
|
||||
|
||||
borg create --progress --stats "$TARGET::$ARCHIVE_NAME" "$TEMP_MOUNT" || error "Borg backup failed"
|
||||
|
||||
log "Borg backup completed successfully"
|
||||
|
||||
# Cleanup
|
||||
log "Cleaning up mount point and snapshot"
|
||||
umount "$TEMP_MOUNT" || warn "Failed to unmount"
|
||||
rmdir "$TEMP_MOUNT"
|
||||
lvremove -f "$SNAPSHOT_PATH" || warn "Failed to remove snapshot"
|
||||
SNAPSHOT_PATH=""
|
||||
|
||||
log "LV to Borg backup completed successfully"
|
||||
;;
|
||||
|
||||
"vg-to-borg")
|
||||
# VG to Borg repository backup
|
||||
if ! vgs "$SOURCE" >/dev/null 2>&1; then
|
||||
error "Source VG does not exist: $SOURCE"
|
||||
fi
|
||||
|
||||
info "This will backup entire VG to Borg repository"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Source VG: $SOURCE${NC}"
|
||||
echo -e "${YELLOW}Repository: $TARGET${NC}"
|
||||
if [ "$NEW_REPO" = true ]; then
|
||||
echo -e "${BLUE}Will create new repository${NC}"
|
||||
else
|
||||
echo -e "${BLUE}Will add to existing repository${NC}"
|
||||
fi
|
||||
echo -e "${BLUE}Encryption: $ENCRYPTION${NC}"
|
||||
echo -e "${BLUE}This will backup all logical volumes in the VG${NC}"
|
||||
echo ""
|
||||
read -p "Continue? (yes/no): " confirm
|
||||
|
||||
if [ "$confirm" != "yes" ]; then
|
||||
echo "Backup cancelled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize repository if needed
|
||||
if [ "$NEW_REPO" = true ]; then
|
||||
log "Creating new Borg repository: $TARGET"
|
||||
if [ "$ENCRYPTION" = "none" ]; then
|
||||
borg init --encryption=none "$TARGET" || error "Failed to initialize repository"
|
||||
else
|
||||
borg init --encryption="$ENCRYPTION" "$TARGET" || error "Failed to initialize repository"
|
||||
fi
|
||||
log "Repository initialized successfully"
|
||||
fi
|
||||
|
||||
# Get all LVs in VG
|
||||
LV_LIST=$(lvs --noheadings -o lv_name "$SOURCE" | tr -d ' ')
|
||||
if [ -z "$LV_LIST" ]; then
|
||||
error "No logical volumes found in VG: $SOURCE"
|
||||
fi
|
||||
|
||||
log "Found logical volumes: $(echo $LV_LIST | tr '\n' ' ')"
|
||||
|
||||
# Create base temp directory
|
||||
BASE_TEMP_DIR=$(mktemp -d -t borg_vg_backup_XXXXXX)
|
||||
SNAPSHOTS_CREATED=""
|
||||
|
||||
# Create snapshots and mount them
|
||||
for LV_NAME in $LV_LIST; do
|
||||
SNAPSHOT_NAME="${LV_NAME}_borg_snap"
|
||||
SNAPSHOT_PATH="/dev/$SOURCE/$SNAPSHOT_NAME"
|
||||
LV_PATH="/dev/$SOURCE/$LV_NAME"
|
||||
MOUNT_POINT="$BASE_TEMP_DIR/$LV_NAME"
|
||||
|
||||
log "Creating snapshot: $SNAPSHOT_NAME"
|
||||
lvcreate -L500M -s -n "$SNAPSHOT_NAME" "$LV_PATH" || {
|
||||
warn "Failed to create snapshot for $LV_NAME"
|
||||
continue
|
||||
}
|
||||
SNAPSHOTS_CREATED="$SNAPSHOTS_CREATED $SNAPSHOT_PATH"
|
||||
|
||||
# Create mount point and mount
|
||||
mkdir -p "$MOUNT_POINT"
|
||||
log "Mounting $SNAPSHOT_PATH to $MOUNT_POINT"
|
||||
mount "$SNAPSHOT_PATH" "$MOUNT_POINT" || {
|
||||
warn "Failed to mount $SNAPSHOT_PATH"
|
||||
continue
|
||||
}
|
||||
done
|
||||
|
||||
# Create Borg archive
|
||||
ARCHIVE_NAME="vg_${SOURCE}_$(date +%Y%m%d_%H%M%S)"
|
||||
log "Creating Borg archive: $ARCHIVE_NAME"
|
||||
log "This may take a long time depending on data size..."
|
||||
|
||||
borg create --progress --stats "$TARGET::$ARCHIVE_NAME" "$BASE_TEMP_DIR" || error "Borg backup failed"
|
||||
|
||||
log "Borg backup of entire VG completed successfully"
|
||||
|
||||
# Cleanup
|
||||
log "Cleaning up mount points and snapshots"
|
||||
for MOUNT_POINT in "$BASE_TEMP_DIR"/*; do
|
||||
if mountpoint -q "$MOUNT_POINT" 2>/dev/null; then
|
||||
umount "$MOUNT_POINT" || warn "Failed to unmount $MOUNT_POINT"
|
||||
fi
|
||||
done
|
||||
|
||||
rm -rf "$BASE_TEMP_DIR"
|
||||
|
||||
for SNAPSHOT_PATH in $SNAPSHOTS_CREATED; do
|
||||
log "Removing snapshot $SNAPSHOT_PATH"
|
||||
lvremove -f "$SNAPSHOT_PATH" || warn "Failed to remove snapshot $SNAPSHOT_PATH"
|
||||
done
|
||||
|
||||
log "VG to Borg backup completed successfully"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user