#!/bin/bash # Restores this host's named volumes from the latest S3 backup, but only into # volumes that are currently empty - never overwrites data that's already # there. Run by spinup.sh via `docker compose -f backup-docker-compose.yml # run --rm restore` before any service that owns one of the mounted volumes # starts. Safe to run on a bucket/prefix that doesn't exist yet (fresh # estate): it just leaves the empty volumes alone. set -euo pipefail S3_URI="s3://${AWS_S3_BUCKET_NAME}/${AWS_S3_PATH}" ENDPOINT_ARGS=() if [ -n "${AWS_ENDPOINT:-}" ]; then ENDPOINT_ARGS=(--endpoint-url "https://${AWS_ENDPOINT}") fi empty_volumes=() for dir in /restore/*/; do name="$(basename "$dir")" if [ -z "$(ls -A "$dir" 2>/dev/null)" ]; then empty_volumes+=("$name") fi done if [ "${#empty_volumes[@]}" -eq 0 ]; then echo "All volumes already contain data - skipping restore." exit 0 fi echo "Empty volumes: ${empty_volumes[*]}" latest="$(aws "${ENDPOINT_ARGS[@]}" s3 ls "${S3_URI}/" 2>/dev/null | awk '{print $4}' | sort | tail -n1 || true)" if [ -z "$latest" ]; then echo "No existing backup found at ${S3_URI} - starting with empty volumes." exit 0 fi echo "Restoring ${S3_URI}/${latest} into empty volumes only..." tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT aws "${ENDPOINT_ARGS[@]}" s3 cp "${S3_URI}/${latest}" "$tmp/backup.tar.gz" mkdir "$tmp/extracted" tar -xzf "$tmp/backup.tar.gz" -C "$tmp/extracted" for name in "${empty_volumes[@]}"; do if [ -d "$tmp/extracted/$name" ]; then echo "Restoring $name..." cp -a "$tmp/extracted/$name/." "/restore/$name/" else echo "No $name/ in backup - leaving volume empty." fi done echo "Restore complete."