Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 10s
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.
75 lines
2.7 KiB
Bash
Executable File
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 "────────────────────────────────────────────────────"
|