From 4dd0490afc41b3667f172d0fe326e5d65bf49d39 Mon Sep 17 00:00:00 2001 From: Scrum4Me Agent <30029041+madhura68@users.noreply.github.com> Date: Wed, 13 May 2026 20:07:14 +0200 Subject: [PATCH] feat(backup): add ops-db backup commands, flow, and systemd timer Adds pg_dump_ops_db, list_ops_backups, and cleanup_ops_backups to the agent command whitelist. Includes a backup_ops_db flow YAML (dump + 30-day retention), and a systemd service/timer for daily automated backups at 02:00. Co-Authored-By: Claude Sonnet 4.6 --- deploy/ops-agent/ops-db-backup.service | 20 ++++++++++++++ deploy/ops-agent/ops-db-backup.timer | 10 +++++++ ops-agent/commands.yml.example | 33 +++++++++++++++++++++++ ops-agent/flows.example/backup_ops_db.yml | 22 +++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 deploy/ops-agent/ops-db-backup.service create mode 100644 deploy/ops-agent/ops-db-backup.timer create mode 100644 ops-agent/flows.example/backup_ops_db.yml diff --git a/deploy/ops-agent/ops-db-backup.service b/deploy/ops-agent/ops-db-backup.service new file mode 100644 index 0000000..492e0fb --- /dev/null +++ b/deploy/ops-agent/ops-db-backup.service @@ -0,0 +1,20 @@ +[Unit] +Description=Daily backup of ops_dashboard database +After=network.target ops-agent.service + +[Service] +Type=oneshot +User=ops-agent +Group=ops-agent +# Reads the shared secret and POSTs to ops-agent to trigger the backup flow. +# ops-agent must be running and backup_ops_db.yml must be installed in /etc/ops-agent/flows/. +ExecStart=/usr/bin/bash -c '\ + SECRET=$(cat /etc/ops-agent/secret); \ + curl -sf -X POST http://127.0.0.1:3099/agent/v1/flow \ + -H "Authorization: Bearer $SECRET" \ + -H "Content-Type: application/json" \ + -d "{\"flow_key\":\"backup_ops_db\"}" \ +' +StandardOutput=journal +StandardError=journal +SyslogIdentifier=ops-db-backup diff --git a/deploy/ops-agent/ops-db-backup.timer b/deploy/ops-agent/ops-db-backup.timer new file mode 100644 index 0000000..bb2c5ef --- /dev/null +++ b/deploy/ops-agent/ops-db-backup.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Daily backup of ops_dashboard database (timer) + +[Timer] +# Run every day at 02:00 local time. +OnCalendar=*-*-* 02:00:00 +Persistent=true + +[Install] +WantedBy=timers.target diff --git a/ops-agent/commands.yml.example b/ops-agent/commands.yml.example index e899e0e..4c7cd2f 100644 --- a/ops-agent/commands.yml.example +++ b/ops-agent/commands.yml.example @@ -203,3 +203,36 @@ commands: - -c - "code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 https://thuis.jp-visser.nl/api/products); echo \"HTTP $code\"; [ \"$code\" = \"200\" ] || [ \"$code\" = \"401\" ]" description: "Smoke test: /api/products must return 200 or 401" + + # ── Ops-dashboard database backup ──────────────────────────────────────── + + pg_dump_ops_db: + cmd: + - sh + - -c + - | + mkdir -p /srv/ops/backups + FNAME="/srv/ops/backups/ops_db_$(date +%Y%m%d_%H%M).dump" + docker exec postgres pg_dump -Fc ops_dashboard > "$FNAME" + echo "Backup written: $FNAME" + ls -lh "$FNAME" + description: "Dump ops_dashboard DB via docker exec postgres to /srv/ops/backups/" + + list_ops_backups: + cmd: + - sh + - -c + - "find /srv/ops/backups -maxdepth 1 -name '*.dump' -printf '%f\\t%s\\n' 2>/dev/null | sort -r || true" + description: "List ops_dashboard backup files (filename TAB size_bytes, newest-first)" + + cleanup_ops_backups: + cmd: + - find + - /srv/ops/backups + - -name + - "*.dump" + - -mtime + - "+30" + - -delete + - -print + description: "Delete ops_dashboard backup files older than 30 days" diff --git a/ops-agent/flows.example/backup_ops_db.yml b/ops-agent/flows.example/backup_ops_db.yml new file mode 100644 index 0000000..f0c654a --- /dev/null +++ b/ops-agent/flows.example/backup_ops_db.yml @@ -0,0 +1,22 @@ +# Backup the ops_dashboard database. +# Copy to /etc/ops-agent/flows/backup_ops_db.yml on the host. +# +# Prerequisites: +# - ops-agent user must be in the docker group (to run docker exec) +# - /srv/ops/backups/ directory or its parent must be writable by ops-agent +# +# Steps: +# 1. Dump ops_dashboard via pg_dump inside the postgres container +# 2. Remove backup files older than 30 days (retention policy) +# +# Run on a schedule via ops-db-backup.timer (see deploy/ops-agent/). +# Or trigger manually via the Ops Dashboard → Settings → Backups. + +name: Backup Ops DB +description: Dump ops_dashboard database and apply 30-day retention policy +steps: + - command_key: pg_dump_ops_db + on_failure: abort + + - command_key: cleanup_ops_backups + on_failure: continue