#!/bin/bash # Usage: curl -sL https://url/migrate.sh | bash -s -- [SSH_KEY_PATH] LOCAL_SEARCH="$1" DEST_CONN="$2" REMOTE_SEARCH="$3" SSH_KEY_PATH="$4" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # --- 1. SSH SETUP --- SSH_BASE_OPTS="-o BatchMode=yes -o ConnectTimeout=10 -o StrictHostKeyChecking=no" if [ -n "$SSH_KEY_PATH" ]; then SSH_CMD="ssh -i $SSH_KEY_PATH $SSH_BASE_OPTS" RSYNC_SH="ssh -i $SSH_KEY_PATH $SSH_BASE_OPTS" else SSH_CMD="ssh $SSH_BASE_OPTS" RSYNC_SH="ssh $SSH_BASE_OPTS" fi # --- 2. DETECT MODE (Container vs Volume) --- MODE="container" # Check if input is a valid volume if docker volume inspect "$LOCAL_SEARCH" >/dev/null 2>&1; then MODE="volume" echo -e "${YELLOW}Info: Detected input as Volume Name, not Container.${NC}" fi # --- 3. EXECUTE MIGRATION --- if [ "$MODE" == "volume" ]; then # === VOLUME MODE === L_VOL="$LOCAL_SEARCH" R_VOL="$REMOTE_SEARCH" echo -e " Source Volume: ${GREEN}$L_VOL${NC}" echo -e " Target Volume: ${GREEN}$R_VOL${NC}" # Get Paths REAL_L_PATH=$(docker volume inspect --format '{{.Mountpoint}}' "$L_VOL") REAL_R_PATH=$($SSH_CMD "$DEST_CONN" "docker volume inspect --format '{{.Mountpoint}}' $R_VOL") if [ -z "$REAL_R_PATH" ]; then echo -e "${RED}Error: Remote volume '$R_VOL' not found on Server B.${NC}" exit 1 fi # Attempt to stop any containers using these volumes (Safety) echo -e "\nšŸ›‘ Stopping any containers using these volumes..." # Local L_CONTAINER=$(docker ps -q --filter volume="$L_VOL") [ -n "$L_CONTAINER" ] && docker stop $L_CONTAINER # Remote R_CONTAINER=$($SSH_CMD "$DEST_CONN" "docker ps -q --filter volume='$R_VOL'") [ -n "$R_CONTAINER" ] && $SSH_CMD "$DEST_CONN" "docker stop $R_CONTAINER" # Sync echo -e "šŸš€ Transferring data..." rsync -az --info=progress2 -e "$RSYNC_SH" "${REAL_L_PATH}/" "$DEST_CONN:${REAL_R_PATH}/" echo -e "\nāœ… Volume Transfer Complete!" [ -n "$L_CONTAINER" ] && docker start $L_CONTAINER [ -n "$R_CONTAINER" ] && $SSH_CMD "$DEST_CONN" "docker start $R_CONTAINER" else # === CONTAINER MODE (Original Logic) === L_ID=$(docker ps -aq --filter "name=${LOCAL_SEARCH}" | head -n 1) R_ID=$($SSH_CMD "$DEST_CONN" "docker ps -aq --filter 'name=${REMOTE_SEARCH}' | head -n 1") if [ -z "$L_ID" ]; then echo -e "${RED}Error: Container/Volume '$LOCAL_SEARCH' not found.${NC}"; exit 1; fi if [ -z "$R_ID" ]; then echo -e "${RED}Error: Remote container '$REMOTE_SEARCH' not found.${NC}"; exit 1; fi echo -e "šŸ›‘ Stopping containers..." docker stop "$L_ID" $SSH_CMD "$DEST_CONN" "docker stop $R_ID" echo -e "šŸ“¦ Syncing volumes..." L_MOUNTS=$(docker inspect -f '{{range .Mounts}}{{.Type}}|{{.Source}}|{{.Destination}} {{end}}' "$L_ID") for MOUNT in $L_MOUNTS; do TYPE=$(echo "$MOUNT" | cut -d'|' -f1) L_PATH=$(echo "$MOUNT" | cut -d'|' -f2) TARGET=$(echo "$MOUNT" | cut -d'|' -f3) if [[ "$TARGET" == *".sock" ]] || [[ "$TARGET" == *".conf" ]]; then continue; fi R_PATH_RAW=$($SSH_CMD "$DEST_CONN" "docker inspect -f '{{range .Mounts}}{{if eq .Destination \"$TARGET\"}}{{.Source}}{{end}}{{end}}' $R_ID") if [ -n "$R_PATH_RAW" ]; then if [ "$TYPE" == "volume" ]; then REAL_L=$(docker volume inspect --format '{{.Mountpoint}}' "$L_PATH") REAL_R=$($SSH_CMD "$DEST_CONN" "docker volume inspect --format '{{.Mountpoint}}' $R_PATH_RAW" 2>/dev/null || echo $R_PATH_RAW) else REAL_L="$L_PATH"; REAL_R="$R_PATH_RAW" fi rsync -az --info=progress2 -e "$RSYNC_SH" "${REAL_L}/" "$DEST_CONN:${REAL_R}/" fi done echo -e "āœ… Container Transfer Complete!" docker start "$L_ID" $SSH_CMD "$DEST_CONN" "docker start $R_ID" fi