Public DNS for paperclip.home.imicros.de returns the LAN IP 10.0.0.2, so the drill's webhook POST was landing with HTTP 000 from Hetzner. The home reverse proxy at 46.225.155.185 already serves that vhost publicly, so pinning the hostname to the home public IP in the CronJob's hostAliases lets the webhook fire the Paperclip routine without any home-network or SealedSecret changes. Verified end-to-end: bearer POST via --resolve returns HTTP 202 with status=issue_created (run issue b07fc035 created under DEV-578). Co-Authored-By: Paperclip <noreply@paperclip.ing> |
||
|---|---|---|
| .. | ||
| 00-serviceaccount-rbac.yaml | ||
| 10-drill-script-configmap.yaml | ||
| 20-restore-drill-cronjob.yaml | ||
| 30-webhook-sealed.yaml | ||
| README.md | ||
Velero restore drill
Monthly Kubernetes CronJob that exercises the Velero backup chain by restoring
the openwebui namespace into a transient restore-test-<ts> namespace,
diffing resource counts against the live namespace, and cleaning up.
Wired by DEV-575 under the DEV-569 Velero cluster-reconstruction backup layer.
What it does
- Picks the latest
Completedbackup for scheduleopenwebui-manifests(envDRILL_BACKUP_OVERRIDEshort-circuits this — used by the failure drill). - Creates a
RestoreCR with namespace mappingopenwebui: restore-test-<ts>. - Waits for the
Restoreto reach a terminal phase (Completed,PartiallyFailed,Failed,FailedValidation) or times out at 30 min. - Counts core kinds (deployments, statefulsets, services, configmaps, PVCs, …) in source vs target and requires strict equality on the manifest-carrying kinds to pass.
- Deletes the
restore-test-<ts>namespace and theRestoreCR. - Writes the final report to ConfigMap
velero/velero-restore-drill-last-resultand logs it to stdout. - Optionally POSTs a JSON payload to the Paperclip routine webhook if
the
velero-restore-drill-webhookSecret is present. The CronJob uses ahostAliasesentry to routepaperclip.home.imicros.deat the home public IP so the webhook reaches the routine from Hetzner (DEV-579).
Failure signalling
The Job exits non-zero on any failure. The alerting stack (DEV-574) will fire
KubeJobFailed on the velero-restore-drill-* job name and route the alert
through existing Alertmanager receivers. Ops can inspect the last result via:
kubectl -n velero get cm velero-restore-drill-last-result -o jsonpath='{.data.result}'
kubectl -n velero get cm velero-restore-drill-last-result -o jsonpath='{.data.log}'
Manual runs
Kick a drill on demand:
kubectl -n velero create job --from=cronjob/velero-restore-drill drill-adhoc-$(date -u +%Y%m%d-%H%M%S)
Force a failure to test the alert wiring (uses a bogus backup name):
kubectl -n velero create job drill-adhoc-fail-$(date -u +%s) \
--image=alpine/k8s:1.30.5 \
--dry-run=client -o yaml \
| kubectl -n velero apply -f - # only if you need a scratch, prefer:
kubectl -n velero create job --from=cronjob/velero-restore-drill drill-fail-$(date -u +%Y%m%d-%H%M%S) --dry-run=client -o yaml \
| sed 's/value: "openwebui-manifests"/value: "openwebui-manifests"\n - name: DRILL_BACKUP_OVERRIDE\n value: "no-such-backup"/' \
| kubectl apply -f -
For a simpler failure drill, apply the CronJob-derived Job then patch env before scheduling — see the parent DEV-575 comment for the exact runbook.
RBAC scope
velero.io/backups,restores: get/list/create/delete in-cluster (namespace scope is enforced by resource type — Backups/Restores live invelero).namespaces: cluster-wide get/list/create/delete. Cannot be name-scoped in RBAC; the drill script enforces therestore-test-prefix before ever deleting a namespace.configmaps: get/list/create/update/patch (only used to write the result ConfigMap invelero— pod-level namespace scoping via ServiceAccount).- Cluster-wide
viewClusterRole for the counting diff.