Skip to content

feat(kopiur): alert on backup freshness and enable weekly verification - #4305

Merged
Tanguille merged 1 commit into
mainfrom
feat/kopiur-backup-alerting
Aug 2, 2026
Merged

feat(kopiur): alert on backup freshness and enable weekly verification#4305
Tanguille merged 1 commit into
mainfrom
feat/kopiur-backup-alerting

Conversation

@Tanguille

Copy link
Copy Markdown
Owner

Backups ran hourly for 18d with LAST-VERIFIED empty on all 18 policies, and nothing watched freshness. A repo that stops being restorable reads identical to a healthy one until a restore is attempted.

Alerts

KopiurBackupOverdue (6h), KopiurBackupCritical (24h), KopiurPolicyMetricsAbsent, KopiurRepoEmpty, KopiurControllerNotLeader.

Name collision avoided

The chart ships its own kopiur.rules group (via monitoring.prometheusRule.enabled) containing a KopiurBackupStale on the same metric at the same severity with the same for:. Identical result labels mean identical alert fingerprints, which Alertmanager cannot distinguish — and crossing the threshold downward would make one rule resolve while the other kept firing.

Hence group kopiur.freshness.rules and alert KopiurBackupOverdue. The chart's other 8 alerts are not duplicated; freshness, metric-absence, empty-repo and never-leader are genuine gaps.

Verification

spec.verification is opt-in and nobody had opted in. Enables the quick (blob-level) tier weekly with 3h jitter so 18 policies do not hit the NAS at once. Concrete cron rather than the H placeholder.

Validation

kustomize build, kubectl apply --dry-run=server on the rule and an envsubst'd SnapshotPolicy, every expression run against live VictoriaMetrics. All 18 policies are currently under 1h old, so these are silent on merge.

Known, not addressed

KopiurBackupCritical at 24h double-notifies with KopiurBackupOverdue at 6h — the inhibit rule matches on alertname, which differs. A 24h-dead backup arguably deserves the noise.

Backups ran hourly for 18d with LAST-VERIFIED empty on all 18 policies, and nothing
watched freshness -- a repo that stops being restorable reads healthy until a restore
is attempted.

Group is kopiur.freshness.rules and the freshness alert is KopiurBackupOverdue: the
chart ships its own kopiur.rules group with a KopiurBackupStale on the same metric at
the same severity, which would have produced identical alert fingerprints.
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Tanguille, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 40 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: da81df94-829a-4b85-a1ea-5fb70ba28763

📥 Commits

Reviewing files that changed from the base of the PR and between 6ac1a8b and 70ea98e.

📒 Files selected for processing (3)
  • kubernetes/apps/kopiur-system/kopiur/app/kustomization.yaml
  • kubernetes/apps/kopiur-system/kopiur/app/prometheusrule.yaml
  • kubernetes/components/kopiur/backup/snapshotpolicy.yaml

Comment @coderabbitai help to get the list of available commands.

@tanguille-cluster

Copy link
Copy Markdown
@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/ai/hermes
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/ai/odysseus
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/ai/opencode
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/default/changedetection
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/default/dumbassets
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/default/karakeep
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/default/nextcloud
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/bazarr
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/brrpolice
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/fileflows
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/jellyfin
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/prowlarr
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/qbittorrent
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/qui
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/radarr
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/seerr
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/sonarr
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ spec @@
# kopiur.home-operations.com/v1alpha1/SnapshotPolicy/media/wizarr
! + one map entry added:
+ verification:
+   quick:
+     schedule:
+       cron: "0 3 * * 0"
+       jitter: 3h

@@ (root level) @@
# monitoring.coreos.com/v1/PrometheusRule/kopiur-system/kopiur-rules
! + one document added:
+ apiVersion: monitoring.coreos.com/v1
+ kind: PrometheusRule
+ metadata:
+   name: kopiur-rules
+   namespace: kopiur-system
+   labels:
+     kustomize.toolkit.fluxcd.io/name: kopiur
+     kustomize.toolkit.fluxcd.io/namespace: kopiur-system
+ spec:
+   groups:
+   - name: kopiur.freshness.rules
+     rules:
+     - alert: KopiurBackupOverdue
+       annotations:
+         summary: "kopiur {{ $labels.namespace }}/{{ $labels.policy }} has no successful backup for {{ $value | humanizeDuration }} — restore point is aging"
+       expr: "time() - kopiur_policy_last_backup_success_timestamp_seconds > 6 * 60 * 60"
+       for: 30m
+       labels:
+         severity: warning
+     - alert: KopiurBackupCritical
+       annotations:
+         summary: "kopiur {{ $labels.namespace }}/{{ $labels.policy }} has not backed up successfully in {{ $value | humanizeDuration }}"
+       expr: "time() - kopiur_policy_last_backup_success_timestamp_seconds > 24 * 60 * 60"
+       for: 30m
+       labels:
+         severity: critical
+     - alert: KopiurPolicyMetricsAbsent
+       annotations:
+         summary: "No kopiur policy backup metrics at all — the controller is down or every policy stopped reporting; backup state is unknown, not healthy"
+       expr: absent(kopiur_policy_last_backup_success_timestamp_seconds)
+       for: 30m
+       labels:
+         severity: critical
+     - alert: KopiurRepoEmpty
+       annotations:
+         summary: "kopiur repository {{ $labels.name }} reports zero snapshots — the repo is empty or unreadable"
+       expr: "kopiur_repo_snapshot_count == 0"
+       for: 1h
+       labels:
+         severity: critical
+     - alert: KopiurControllerNotLeader
+       annotations:
+         summary: "No kopiur controller holds the leader lease — nothing is scheduling backups"
+       expr: "max(kopiur_leader_is_leader) == 0"
+       for: 30m
+       labels:
+         severity: critical

@deepsource-io

deepsource-io Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

DeepSource Code Review

We reviewed changes in 6ac1a8b...70ea98e on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Aug 2, 2026 3:02p.m. Review ↗
Shell Aug 2, 2026 3:02p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

AI Automated Review

Analysis engine: qwen-3.6-fast@http://litellm.ai.svc.cluster.local/v1 (openai)

Recommendation

Approve. The PR adds well-reasoned PrometheusRule alerts for backup freshness, controller health, and repo integrity, plus enables weekly snapshot verification with jitter. All changes are internally consistent, follow repository conventions, and address the documented gaps from past incidents.


Change-by-Change Findings

kubernetes/apps/kopiur-system/kopiur/app/prometheusrule.yaml (new)

  • Five new alerts (KopiurBackupOverdue, KopiurBackupCritical, KopiurPolicyMetricsAbsent, KopiurRepoEmpty, KopiurControllerNotLeader) using a distinct group name kopiur.freshness.rules to avoid colliding with the chart's built-in kopiur.rules group. This is correct — the HelmRelease has monitoring.prometheusRule.enabled: true, so both rule groups coexist.
  • Alert naming deliberately avoids KopiurBackupStale (the chart's existing alert on the same metric) to prevent fingerprint collisions in Alertmanager. Documented rationale is sound.
  • Expressions use standard PromQL patterns (time() - <timestamp>, absent(), max() == 0). Thresholds (6h overdue, 24h critical, 30m/1h evaluation windows) are reasonable for hourly-scheduled backups.
  • Schema annotation points to k8s-schemas.home-operations.com; this host is not allowlisted for fetching but follows the repo's existing pattern seen across other PrometheusRules.

kubernetes/apps/kopiur-system/kopiur/app/kustomization.yaml

  • Adds prometheusrule.yaml to the Kustomization resources list. Standard pattern matching other apps in the repo.

kubernetes/components/kopiur/backup/snapshotpolicy.yaml

  • Enables spec.verification.quick with a weekly schedule (0 3 * * 0) and 3h jitter. The comment explains why a fixed hour + jitter is preferred over hashed scheduling (H) for fleet-wide load distribution during full-repo walks. Reasonable operational choice.
  • No changes to retention, compression, or mover config — purely additive.

Standards Compliance

  • Conventional commit: Title feat(kopiur): alert on backup freshness and enable weekly verification follows the required format.
  • Small and focused scope: Three files changed, all within the kopiur subsystem. No unrelated modifications.
  • YAML structure: Follows existing patterns for PrometheusRules (group naming, annotation style, severity labels) and SnapshotPolicies seen elsewhere in the repo.
  • No secrets committed: Only template variables (${KOPIUR_PUID}, ${TRUENAS_IP}, etc.) present; no plaintext credentials.

Must-Check Items

Check Status
Validate manifest against target cluster version PrometheusRule uses monitoring.coreos.com/v1 (standard Prometheus Operator CRD). SnapshotPolicy uses kopiur.home-operations.com/v1alpha1. Both APIs are custom/operator-managed and validated by their respective controllers at reconcile time. No version pinning mismatch detected in the diff.
Check for resource quota / limit changes No resource requests, limits, quotas, or HPA changes in this PR. Not applicable.

Unknowns or Needs Verification

  • The schema URL https://k8s-schemas.home-operations.com/ was not fetchable (not on the allowlist). This is an info-level gap; it does not affect correctness since the manifests follow established repo patterns and the PR author states they validated with kustomize build and kubectl apply --dry-run=server.
  • The inhibit rule between KopiurBackupOverdue (warning) and KopiurBackupCritical (critical) is acknowledged as intentionally absent by the author ("arguably deserves the noise"). This is a conscious trade-off, not a defect.

@Tanguille
Tanguille merged commit bd23036 into main Aug 2, 2026
15 checks passed
@Tanguille
Tanguille deleted the feat/kopiur-backup-alerting branch August 2, 2026 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant