mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-07-01 12:05:23 +02:00
127 lines
4.1 KiB
TypeScript
127 lines
4.1 KiB
TypeScript
import path from "node:path";
|
|
import {
|
|
findApplicationById,
|
|
findComposeById,
|
|
findDestinationById,
|
|
getS3Credentials,
|
|
paths,
|
|
} from "../..";
|
|
|
|
export const restoreVolume = async (
|
|
id: string,
|
|
destinationId: string,
|
|
volumeName: string,
|
|
backupFileName: string,
|
|
serverId: string,
|
|
serviceType: "application" | "compose",
|
|
) => {
|
|
const destination = await findDestinationById(destinationId);
|
|
const { VOLUME_BACKUPS_PATH } = paths(!!serverId);
|
|
const volumeBackupPath = path.join(VOLUME_BACKUPS_PATH, volumeName);
|
|
const rcloneFlags = getS3Credentials(destination);
|
|
const bucketPath = `:s3:${destination.bucket}`;
|
|
const backupPath = `${bucketPath}/${backupFileName}`;
|
|
|
|
// Command to download backup file from S3
|
|
const downloadCommand = `rclone copyto ${rcloneFlags.join(" ")} "${backupPath}" "${volumeBackupPath}/${backupFileName}"`;
|
|
|
|
// Base restore command that creates the volume and restores data
|
|
const baseRestoreCommand = `
|
|
set -e
|
|
echo "Volume name: ${volumeName}"
|
|
echo "Backup file name: ${backupFileName}"
|
|
echo "Volume backup path: ${volumeBackupPath}"
|
|
echo "Downloading backup from S3..."
|
|
mkdir -p ${volumeBackupPath}
|
|
${downloadCommand}
|
|
echo "Download completed ✅"
|
|
echo "Creating new volume and restoring data..."
|
|
docker run --rm \
|
|
-v ${volumeName}:/volume_data \
|
|
-v ${volumeBackupPath}:/backup \
|
|
ubuntu \
|
|
bash -c "cd /volume_data && tar xvf /backup/${backupFileName} ."
|
|
echo "Volume restore completed ✅"
|
|
`;
|
|
|
|
// Function to check if volume exists and get containers using it
|
|
const checkVolumeCommand = `
|
|
# Check if volume exists
|
|
VOLUME_EXISTS=$(docker volume ls -q --filter name="^${volumeName}$" | wc -l)
|
|
echo "Volume exists: $VOLUME_EXISTS"
|
|
|
|
if [ "$VOLUME_EXISTS" = "0" ]; then
|
|
echo "Volume doesn't exist, proceeding with direct restore"
|
|
${baseRestoreCommand}
|
|
else
|
|
echo "Volume exists, checking for containers using it (including stopped ones)..."
|
|
|
|
# Get ALL containers (running and stopped) using this volume - much simpler with native filter!
|
|
CONTAINERS_USING_VOLUME=$(docker ps -a --filter "volume=${volumeName}" --format "{{.ID}}|{{.Names}}|{{.State}}|{{.Labels}}")
|
|
|
|
if [ -z "$CONTAINERS_USING_VOLUME" ]; then
|
|
echo "Volume exists but no containers are using it"
|
|
echo "Removing existing volume and proceeding with restore"
|
|
docker volume rm ${volumeName} --force
|
|
${baseRestoreCommand}
|
|
else
|
|
echo ""
|
|
echo "⚠️ WARNING: Cannot restore volume as it is currently in use!"
|
|
echo ""
|
|
echo "📋 The following containers are using volume '${volumeName}':"
|
|
echo ""
|
|
|
|
echo "$CONTAINERS_USING_VOLUME" | while IFS='|' read container_id container_name container_state labels; do
|
|
echo " 🐳 Container: $container_name ($container_id)"
|
|
echo " Status: $container_state"
|
|
|
|
# Determine container type
|
|
if echo "$labels" | grep -q "com.docker.swarm.service.name="; then
|
|
SERVICE_NAME=$(echo "$labels" | grep -o "com.docker.swarm.service.name=[^,]*" | cut -d'=' -f2)
|
|
echo " Type: Docker Swarm Service ($SERVICE_NAME)"
|
|
elif echo "$labels" | grep -q "com.docker.compose.project="; then
|
|
PROJECT_NAME=$(echo "$labels" | grep -o "com.docker.compose.project=[^,]*" | cut -d'=' -f2)
|
|
echo " Type: Docker Compose ($PROJECT_NAME)"
|
|
else
|
|
echo " Type: Regular Container"
|
|
fi
|
|
echo ""
|
|
done
|
|
|
|
echo ""
|
|
echo "🔧 To restore this volume, please:"
|
|
echo " 1. Stop all containers/services using this volume"
|
|
echo " 2. Remove the existing volume: docker volume rm ${volumeName}"
|
|
echo " 3. Run the restore operation again"
|
|
echo ""
|
|
echo "❌ Volume restore aborted - volume is in use"
|
|
|
|
exit 1
|
|
fi
|
|
fi
|
|
`;
|
|
|
|
if (serviceType === "application") {
|
|
const application = await findApplicationById(id);
|
|
return `
|
|
echo "=== VOLUME RESTORE FOR APPLICATION ==="
|
|
echo "Application: ${application.appName}"
|
|
${checkVolumeCommand}
|
|
`;
|
|
}
|
|
|
|
if (serviceType === "compose") {
|
|
const compose = await findComposeById(id);
|
|
|
|
return `
|
|
echo "=== VOLUME RESTORE FOR COMPOSE ==="
|
|
echo "Compose: ${compose.appName}"
|
|
echo "Compose Type: ${compose.composeType}"
|
|
${checkVolumeCommand}
|
|
`;
|
|
}
|
|
|
|
// Fallback for unknown service types
|
|
return checkVolumeCommand;
|
|
};
|