From 931fa4a3c4326deefe14691313a5becedf79a0b1 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Sun, 30 Aug 2026 15:53:46 -0600 Subject: [PATCH] fix: remove stopped containers referencing a volume before restore Volume restore aborted with "volume is in use" whenever a stopped container still referenced the target volume, forcing users to SSH in and remove it manually. Running containers still block the restore, but stopped ones are now removed automatically before the volume is recreated. Fixes #3995 --- .../src/utils/volume-backups/restore.ts | 76 ++++++++++++------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/packages/server/src/utils/volume-backups/restore.ts b/packages/server/src/utils/volume-backups/restore.ts index 812f6cefd..d23a0a869 100644 --- a/packages/server/src/utils/volume-backups/restore.ts +++ b/packages/server/src/utils/volume-backups/restore.ts @@ -66,38 +66,56 @@ export const restoreVolume = async ( 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 + RUNNING_CONTAINERS=$(echo "$CONTAINERS_USING_VOLUME" | awk -F'|' '$3 == "running"') + STOPPED_CONTAINERS=$(echo "$CONTAINERS_USING_VOLUME" | awk -F'|' '$3 != "running"') + + if [ -n "$RUNNING_CONTAINERS" ]; then echo "" + echo "⚠️ WARNING: Cannot restore volume as it is currently in use!" + echo "" + echo "📋 The following running containers are using volume '${volumeName}':" + echo "" + + echo "$RUNNING_CONTAINERS" | 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 + + echo "Volume exists but is only referenced by stopped containers, removing them..." + echo "" + + echo "$STOPPED_CONTAINERS" | while IFS='|' read container_id container_name container_state labels; do + echo " 🗑 Removing stopped container: $container_name ($container_id) [status: $container_state]" + docker rm -f "$container_id" >/dev/null 2>&1 || true 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 + echo "Removing existing volume and proceeding with restore" + docker volume rm ${volumeName} --force + ${baseRestoreCommand} fi fi `;