Files
clawstor/deploy/scripts/rotate-snapshots.sh
T
Omar Sobh 7a3c04bed7
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 10s
Polish: daily snapshot rotation script + systemd timer
deploy/scripts/rotate-snapshots.sh creates daily-YYYY-MM-DD
snapshot + prunes daily-* older than RETAIN_DAYS. Only touches
its own daily-* namespace so hand-created snapshots (release
anchors etc) never get reaped.

02:00 timer runs ahead of the 03:15 ref-sweep + 03:30 gc so
tonight's fresh snapshot pins protect its blobs from eviction.

DRY_RUN=1 for preview.
2026-07-14 13:12:15 -07:00

75 lines
2.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# rotate-snapshots.sh — create today's daily snapshot + prune snapshots
# older than N days. Idempotent: safe to run repeatedly on the same day.
#
# Snapshots created by this script are named `daily-YYYY-MM-DD`. Only
# snapshots matching that prefix are candidates for pruning — hand-created
# snapshots (release-anchor, pre-migration, etc.) are never touched.
#
# Env / args:
# CLAWSTOR_BIN path to claw-store binary (default: ~/clawstor-deploy/claw-store)
# CLAWSTOR_CONFIG path to config.toml (default: ~/clawstor-deploy/config.toml)
# RETAIN_DAYS snapshots older than this many days get pruned (default: 30)
# DRY_RUN=1 print what would happen, no side effects
set -euo pipefail
CLAWSTOR_BIN=${CLAWSTOR_BIN:-$HOME/clawstor-deploy/claw-store}
CLAWSTOR_CONFIG=${CLAWSTOR_CONFIG:-$HOME/clawstor-deploy/config.toml}
RETAIN_DAYS=${RETAIN_DAYS:-30}
DRY_RUN=${DRY_RUN:-0}
if [ ! -x "$CLAWSTOR_BIN" ]; then
echo "error: $CLAWSTOR_BIN not executable" >&2
exit 1
fi
CS="$CLAWSTOR_BIN --config $CLAWSTOR_CONFIG"
TODAY=$(date +%Y-%m-%d)
NAME="daily-$TODAY"
echo "── rotate-snapshots ────────────────────────────────"
echo "today: $NAME"
echo "retention: $RETAIN_DAYS days"
# Create today's snapshot. Idempotent: `cluster-snapshot-create` errors
# if the name already exists — we treat that as success.
if [ "$DRY_RUN" = "1" ]; then
echo "dry-run: would create snapshot $NAME"
else
if $CS cluster-snapshot-create --name "$NAME" 2>&1 | tail -6; then
echo "created: $NAME"
else
echo "already exists (idempotent): $NAME"
fi
fi
# Compute cutoff — POSIX date arithmetic (no GNU date extensions needed
# because we do the math on the epoch integer).
NOW_EPOCH=$(date +%s)
CUTOFF_EPOCH=$((NOW_EPOCH - RETAIN_DAYS * 86400))
# Snapshot list format:
# CREATED_AT NAME BLOBS SIZE
# 1784046443 daily-2026-07-14 4 224
# So awk field 1 = epoch, field 2 = name.
PRUNE_LIST=$($CS cluster-snapshot-list 2>/dev/null | awk -v cutoff="$CUTOFF_EPOCH" '
NR > 4 && $2 ~ /^daily-/ && $1 < cutoff { print $2 }
')
echo
if [ -z "$PRUNE_LIST" ]; then
echo "nothing to prune"
else
echo "prune candidates (older than $RETAIN_DAYS days):"
echo "$PRUNE_LIST" | sed 's/^/ /'
if [ "$DRY_RUN" = "1" ]; then
echo "dry-run: no snapshots deleted"
else
echo "$PRUNE_LIST" | while read -r snap; do
$CS cluster-snapshot-delete --name "$snap" 2>&1 | tail -1
done
fi
fi
echo "────────────────────────────────────────────────────"