1# With litestream installed: forge identity replicate copies identity.db2# to a replica next to the backup repository as it changes, forge identity3# restore brings it back as it is now or as it was at a moment, and forge4# restore takes whichever of the backup's copy and the replica changed last.5# FORGE_TEST_LITESTREAM names a litestream binary to use when none is on PATH.6. "$(dirname "$0")/../lib.sh"7if [ -n "${FORGE_TEST_LITESTREAM:-}" ]; then8 mkdir -p "$T/bin"9 ln -s "$FORGE_TEST_LITESTREAM" "$T/bin/litestream"10 PATH=$T/bin:$PATH11fi12command -v litestream >/dev/null 2>&1 || { note "litestream is not installed: skipped"; exit 0; }13user dami14export FORGE_BACKUP_REPOSITORY=$T/restic FORGE_BACKUP_PASSWORD=test15replicate() {16 "$FORGE" identity replicate >>"$T/litestream.log" 2>&1 &17 T_PIDS="$T_PIDS $!"18 sleep 219}20# The names of dami's tokens in the forge at $1 (this one by default).21tokens() { FORGE_STATE=${1:-$FORGE_ROOT}/.forge FORGE_USER=dami node "$T_HOME/lib/identity.ts" tokens | awk 'NR > 1 { print $NF }' | sort | tr '\n' ' '; }22stage() { env -u FORGE_BACKUP_REPOSITORY "$FORGE" backup --dry-run --force >/dev/null 2>&1 && rm -rf "$1" && mv "$FORGE_ROOT/.forge/backup/stage" "$1"; }2324replicate25ok ssh_as dami token a26sleep 227stage "$T/stage-a"28mid=$(date -u +%Y-%m-%dT%H:%M:%SZ)29sleep 230export FORGE_NOW=$((T_NOW + 60))31ok ssh_as dami token b32sleep 333stop_servers34exists "$T/restic-litestream"35has "$FORGE_ROOT/.forge/litestream.yml" "path: $T/restic-litestream"3637# As it was, then as it is.38ok forge identity restore --at "$mid"39eq "$(tokens)" "a "40exists "$FORGE_ROOT/.forge/identity.db.before-restore"41ok forge identity restore42eq "$(tokens)" "a b "43ok forge identity restore --if-missing44eq "$(output)" ""4546# forge restore: the replica changed after the backup's copy (a, b > a)...47r=$T/r148ok restore_into "$r" --from "$T/stage-a"49has "$T_LOG" "identity.db is litestream's, which changed last"50eq "$(tokens "$r")" "a b "51# ...and when replication had stopped, the backup's copy wins.52export FORGE_NOW=$((T_NOW + 120))53ok ssh_as dami token c54stage "$T/stage-c"55r=$T/r256ok restore_into "$r" --from "$T/stage-c"57has "$T_LOG" "identity.db is the backup's, which changed last"58eq "$(tokens "$r")" "a b c "5960# A new box: no identity.db, so it comes from the replica before anything makes one.61r=$T/r362mkdir -p "$r/.forge"63ok env FORGE_ROOT="$r" "$FORGE" identity restore --if-missing64exists "$r/.forge/identity.db"65eq "$(tokens "$r")" "a b "