mirror of
https://github.com/iamxvbaba/gramsrv.git
synced 2026-11-07 15:06:06 +03:00
1a19f0d984
Operators had no supported way to move a deployment or to recover one. This
adds cmd/gramsrv-backup, which captures the PostgreSQL databases, the media and
key tree, Redis and the configuration into a single verifiable bundle, and
restores it on another host.
backup / restore / verify, with MANIFEST.json recording the source commit, the
schema version and exact row counts, and SHA256SUMS in sha256sum(1) format.
Components are captured independently (server, grammystore) since each has its
own database and usually its own container; pg_dump and redis-cli can come from
the host or from docker exec.
Portability is the point of the dump format:
- plain SQL rather than the custom format, so any psql can replay it and the
client need not match the server
- --clean --if-exists so a bundle can be replayed over a populated database
- --no-owner --no-privileges, and no --create, so the target role and database
name are not baked into the artifact
- restored with ON_ERROR_STOP=1 and --single-transaction, so a failure cannot
leave a half-applied schema
- \restrict, \unrestrict and SET transaction_timeout are stripped on the way
in; they are PostgreSQL 17 specific and break older clients and servers
- the target major version is checked before the restore starts
Freezing (--freeze-units, --freeze-containers) is optional because pg_dump is
already MVCC-consistent; it exists so the media tree is byte consistent, and
everything stopped is restarted from a defer even when the capture fails.
Verification re-hashes every artifact, decompresses it, walks tar members, and
cross-checks file_blobs against the media tree, reporting missing and corrupt
objects. check-media.sh runs the live form of that check.
Also included: shell and PowerShell wrappers, a migration runbook in
docs/backup-restore.md, and internal/doclint, which fails the build when tracked
markdown leaks a key, a token or a credential so documentation stays safe to
publish.
96 lines
3.0 KiB
Bash
Executable File
96 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Capture a gramsrv backup bundle with sensible defaults for a monolith
|
|
# deployment. Every flag is forwarded to gramsrv-backup unchanged, so anything
|
|
# this script does not cover is still available:
|
|
#
|
|
# ./scripts/backup.sh --out /srv/backups/$(date -u +%Y%m%d) --component all
|
|
#
|
|
# The tool reads .env for the database credentials, so nothing secret is passed
|
|
# on the command line.
|
|
set -euo pipefail
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: ./scripts/backup.sh [gramsrv-backup flags]
|
|
|
|
Builds bin/gramsrv-backup when it is missing, then runs a backup with defaults
|
|
sensible for a monolith deployment:
|
|
|
|
--out bundle directory (default: ../gramsrv-backup-<UTC date>)
|
|
--component server, grammystore or all (default: server)
|
|
--repo-dir deployment root holding .env and data/ (default: repo root)
|
|
--pg-tools local or docker (default: docker when docker is available)
|
|
--redis-tools local or docker (default: docker when docker is available)
|
|
--freeze-units systemd units to stop for the capture
|
|
--freeze-containers containers to stop for the capture
|
|
|
|
Examples:
|
|
# Hot backup with no downtime, database and media only.
|
|
./scripts/backup.sh --component server
|
|
|
|
# Consistent capture with the writers stopped, restarted automatically.
|
|
./scripts/backup.sh --component all \
|
|
--pg-container-server telesrv-postgres \
|
|
--pg-container-grammystore grammystore_postgres_dev \
|
|
--freeze-units gramsrv.service,gramsrv-admin.service \
|
|
--freeze-containers grammystore_app_dev
|
|
|
|
Run './scripts/backup.sh --help' for the full flag list.
|
|
EOF
|
|
}
|
|
|
|
script_dir=$(CDPATH='' cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
|
|
repo_root=$(CDPATH='' cd -- "$script_dir/.." && pwd)
|
|
binary="$repo_root/bin/gramsrv-backup"
|
|
|
|
has_flag() {
|
|
local name=$1
|
|
shift
|
|
local arg
|
|
for arg in "$@"; do
|
|
[[ $arg == "$name" || $arg == "$name="* ]] && return 0
|
|
done
|
|
return 1
|
|
}
|
|
|
|
build_binary() {
|
|
command -v go >/dev/null 2>&1 || {
|
|
printf 'backup.sh: go is required to build %s\n' "$binary" >&2
|
|
return 1
|
|
}
|
|
printf 'backup.sh: building %s\n' "$binary" >&2
|
|
# Serial compilation keeps peak memory low enough for small hosts.
|
|
(cd "$repo_root" && GOFLAGS=-p=1 go build -o "$binary" ./cmd/gramsrv-backup)
|
|
}
|
|
|
|
docker_available() {
|
|
command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1
|
|
}
|
|
|
|
if has_flag --help "$@"; then
|
|
usage
|
|
exit 0
|
|
fi
|
|
|
|
[[ -x $binary ]] || build_binary
|
|
|
|
args=()
|
|
if ! has_flag --out "$@"; then
|
|
args+=(--out "$repo_root/../gramsrv-backup-$(date -u +%Y%m%d)")
|
|
fi
|
|
if ! has_flag --repo-dir "$@"; then
|
|
args+=(--repo-dir "$repo_root")
|
|
fi
|
|
if ! has_flag --pg-tools "$@" && docker_available; then
|
|
# Most deployments never install PostgreSQL client tools on the host; the
|
|
# database container already carries a matching pg_dump.
|
|
args+=(--pg-tools docker)
|
|
fi
|
|
if ! has_flag --redis-tools "$@" && docker_available; then
|
|
args+=(--redis-tools docker)
|
|
fi
|
|
|
|
# The tool must run from the deployment root so it finds .env.
|
|
cd "$repo_root"
|
|
exec "$binary" backup "${args[@]}" "$@"
|