#!/bin/bash # Backup script for hindsight (Adolf's long-term memory bank) and the # openai_adolf-state Docker volume (Matrix E2EE identity/sessions + config). # Mirrors the seafile/vaultwarden/openai-llm-dbs backup.sh pattern (same repo): # dump/tar via `docker exec`, gzip, retention of last 5, Zabbix freshness # trapper item per target. # # hindsight is an embedded Postgres (pg0) instance living at # /mnt/ssd/dbs/hindsight on the host, bind-mounted into the `hindsight` # container at /home/hindsight/.pg0. We use pg_dump against the live, # running instance (safe, no downtime/quiescing needed — same rationale as # openai-llm-dbs). # # adolf-state is a named Docker volume (openai_adolf-state) owned by the # container's `node` user, not readable directly from the host as this # script's operator. We tar it from inside the `adolf` container instead # (docker exec has access via the mount; no host-side permission needed). # # Run every 3 days via root crontab (same schedule as sibling backups), e.g.: # 0 4 */3 * * /home/alvis/agap_git/openai/backup-hindsight-adolf.sh >> /mnt/backups/hindsight-adolf/backup.log 2>&1 # # Restore: # # hindsight (drop+recreate the DB first if restoring into a fresh instance, # # since the dump is a plain SQL dump, not --clean): # gunzip -c /mnt/backups/hindsight-adolf//hindsight.sql.gz | \ # docker exec -i -e PGPASSWORD=hindsight hindsight \ # /home/hindsight/.pg0/installation/18.1.0/bin/psql -U hindsight -h 127.0.0.1 -p 5432 hindsight # # # adolf-state (container must be stopped first so files aren't overwritten # # while in use; extract into the volume's mountpoint): # docker stop adolf # docker run --rm -v openai_adolf-state:/target -v /mnt/backups/hindsight-adolf/:/backup:ro \ # alpine sh -c "rm -rf /target/* && tar xzf /backup/adolf-state.tar.gz -C /target" # docker start adolf set -euo pipefail BACKUP_DIR="/mnt/backups/hindsight-adolf" ZABBIX_TOKEN_FILE="/root/.zabbix_token" ZABBIX_URL="http://192.168.1.4:81/api_jsonrpc.php" DATE=$(date '+%Y%m%d-%H%M') DEST="$BACKUP_DIR/$DATE" mkdir -p "$DEST" notify_zabbix() { local itemid="$1" label="$2" if [[ -f "$ZABBIX_TOKEN_FILE" ]]; then local token now_epoch token=$(cat "$ZABBIX_TOKEN_FILE") now_epoch=$(date '+%s') env -u HTTPS_PROXY -u HTTP_PROXY -u ALL_PROXY -u https_proxy -u http_proxy -u all_proxy \ curl -s -X POST "$ZABBIX_URL" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $token" \ -d "{\"jsonrpc\":\"2.0\",\"method\":\"history.push\",\"id\":1,\"params\":{\"itemid\":\"$itemid\",\"value\":$now_epoch}}" > /dev/null \ && echo "Zabbix notified ($label=$now_epoch)." else echo "WARNING: $ZABBIX_TOKEN_FILE not found -- skipped Zabbix freshness push for $label." >&2 fi } # --- hindsight (Postgres logical dump, live/read-only) --- echo "Dumping hindsight..." docker exec -e PGPASSWORD=hindsight hindsight \ /home/hindsight/.pg0/installation/18.1.0/bin/pg_dump -U hindsight -h 127.0.0.1 -p 5432 hindsight \ | gzip > "$DEST/hindsight.sql.gz" echo "Dumped: hindsight -> $DEST/hindsight.sql.gz" notify_zabbix "70639" "hindsight.backup.ts" # --- adolf-state (tar the volume from inside the adolf container) --- echo "Archiving adolf-state..." docker exec adolf tar czf - -C /home/node/.openclaw . > "$DEST/adolf-state.tar.gz" echo "Archived: adolf-state -> $DEST/adolf-state.tar.gz" notify_zabbix "70640" "adolf-state.backup.ts" echo "$(date): Backup complete: $DEST" ls -la "$DEST/" # Rotate: keep last 5 backups ls -1dt "$BACKUP_DIR"/[0-9]*-[0-9]* 2>/dev/null | tail -n +6 | xargs -r rm -rf