Skip to content

fix(backupstrategy-controller): gate the default MongoDB strategy on bootstrap - #3815

Merged
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/mongodb-strategy-bootstrap-gate
Aug 14, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/mongodb-strategy-bootstrap-gate

Conversation

@myasnikovdaniil

@myasnikovdaniil myasnikovdaniil commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

Closes #3814.

Unblocks a fresh install of main. Since #3562 the backupstrategy-controller chart renders one default Strategy CR ungated, and that makes the whole release fail on a cluster where its CRDs are not yet applied:

Helm install failed for release cozy-backup-controller/backupstrategy-controller
resource mapping not found for name: "cozy-default-mongodb"
no matches for kind "MongoDB" in version "strategy.backups.cozystack.io/v1alpha1"

The chart ships its own eight strategy.backups.cozystack.io CRDs as ordinary templates, since templates/crds.yaml globs definitions/*.yaml, and Helm pre-applies only a crds/ directory. Helm then resolves every document in the release manifest through the cluster's RESTMapper in Build() before it applies any of them, so an ungated Strategy CR has no mapping on the first install, Build() fails, and the release applies zero objects, including the CRDs that would have made the mapping resolve.

Nothing recovers from that. Every retry renders the same manifest, so it is permanent rather than a race, and Helm's kind sorter cannot help because it orders the apply and the failure is before the apply. The install log shows Warning InstallFailed 43s (x36 over 20m) and then Install failed (no retry).

Why the seven siblings never hit this

Each of them gates on a resolved $bucketName, which is empty until the COSI BucketClaim status is reconciled, so they are simply absent from the first render. By the time DefaultObjectsGate forces a second revision the CRDs from revision 1 exist and the mapping resolves.

That gate is documented as "the CR needs the bucket name", and it silently doubles as the CRD-ordering guard. MongoDB genuinely does not need the bucket name, the template argues that correctly, so the gate was left off and the accidental protection went with it. This gates it too, for the ordering reason rather than the value, and records that reason in the template so the next bucket-independent strategy keeps it.

Convergence is unchanged. DefaultObjectsGate already routes apps.cozystack.io/MongoDB to cozy-default-mongodb and forces a revision once any routed object is missing, which is exactly how the seven siblings materialise today.

Why this was invisible

tests/rendering_test.yaml asserted count: 1 for the MongoDB template under a case named "bootstrap window (no resolvable bucket name)", so the defect was codified as the expected behaviour and shipped green. helm-unittest has no RESTMapper and cannot see the consequence. That assertion is flipped here, with the ordering reason written next to it.

It was also masked in CI until yesterday by #3806. StreamVisitor.Visit returns immediately on a validation error but only continues on a mapping error, so the OpenAPI defect aborted the manifest stream at the first document and the mapping check was never reached. #3808 fixed that and this surfaced underneath it.

Screenshots

Not applicable.

Downstream repositories

  • No downstream repository is affected by this change

Testing

Verified by rendering both windows, since the whole bug is which documents appear in the first render and a cluster adds nothing to that.

Before, bootstrap window: one Strategy document, MongoDB, alongside the eight not-yet-applied CRDs. After: none. With backupStorage.bucketNameOverride=b, which stands in for a resolved BucketClaim: all eight, MongoDB included.

helm template bsc packages/system/backupstrategy-controller | grep -c '^kind: MongoDB$'

helm unittest packages/system/backupstrategy-controller passes, 4 suites, 18 tests.

Follow-up, not in this PR

The durable fix is to stop shipping these CRDs as templates and split definitions/ into a backupstrategy-controller-crds package with a dependsOn edge, which is the convention six other packages already follow. That cannot be a hotfix: none of the eight definitions carries helm.sh/resource-policy: keep, so the upgrade that removes them from this chart's manifest would have Helm delete the eight CRDs and cascade-delete every live Strategy CR on existing clusters. It needs the keep annotation shipped a release ahead.

Release note

fix(backupstrategy-controller): gate the default MongoDB backup strategy on the bootstrap window, so a fresh platform install no longer fails with "no matches for kind MongoDB" and applies nothing

Summary by CodeRabbit

  • Bug Fixes

    • Prevented the default MongoDB backup strategy from rendering before the required S3 storage configuration is available.
    • Improved first-install reliability by avoiding premature strategy resource creation.
  • Tests

    • Updated bootstrap validation to confirm the MongoDB strategy is omitted until a bucket name is resolved.

…bootstrap

A fresh install of packages/system/backupstrategy-controller fails
permanently and applies nothing:

  Helm install failed for release cozy-backup-controller/backupstrategy-controller
  resource mapping not found for name: "cozy-default-mongodb"
  no matches for kind "MongoDB" in version "strategy.backups.cozystack.io/v1alpha1"

The chart ships its own strategy.backups.cozystack.io CRDs as ordinary
templates (templates/crds.yaml globs definitions/*.yaml), and Helm
resolves every document in a release manifest through the cluster's
RESTMapper in Build() before it applies any of them. An ungated Strategy
CR therefore has no mapping on the first install, Build() fails, and the
release applies ZERO objects, including the CRDs that would have made
the mapping resolve. Nothing recovers: every retry renders the same
manifest, so this is permanent rather than a race, and Helm's kind
sorter cannot help because it orders the apply, not the Build.

The seven sibling strategies never hit this because each gates on a
resolved $bucketName, which is empty until the COSI BucketClaim status
is reconciled. That gate is documented as "the CR needs the bucket
name", and it silently doubles as the CRD-ordering guard. MongoDB
genuinely does not need the bucket name, so the gate was left off and
the accidental protection went with it.

Gate it too, for the ordering reason rather than the value, and record
that reason in the template so the next bucket-independent strategy
keeps the gate. Convergence is unchanged: DefaultObjectsGate already
routes apps.cozystack.io/MongoDB to cozy-default-mongodb and forces a
second revision once any routed object is missing, which is how the
seven siblings materialise today.

Verified by rendering both windows. Before: the bootstrap render emits
one Strategy, MongoDB, alongside the eight not-yet-applied CRDs. After:
it emits none, and with backupStorage.bucketNameOverride set it emits
all eight.

tests/rendering_test.yaml asserted count: 1 for MongoDB under a case
named "bootstrap window (no resolvable bucket name)", so the defect was
codified green. helm-unittest has no RESTMapper and cannot see it.

Assisted-By: Claude <[email protected]>
Signed-off-by: Myasnikov Daniil <[email protected]>
@github-actions github-actions Bot added area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug size/M This PR changes 30-99 lines, ignoring generated files labels Aug 14, 2026
@coderabbitai

coderabbitai Bot commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f679dd30-b94a-4b2b-8580-73ad72401a55

📥 Commits

Reviewing files that changed from the base of the PR and between 15459c9 and 4f9c20c.

📒 Files selected for processing (2)
  • packages/system/backupstrategy-controller/templates/strategy-mongodb-default.yaml
  • packages/system/backupstrategy-controller/tests/rendering_test.yaml

📝 Walkthrough

Walkthrough

The MongoDB default strategy template now requires a resolved bucket name before rendering. The bootstrap rendering test now expects zero documents when the bucket name is unavailable.

Changes

MongoDB strategy bootstrap

Layer / File(s) Summary
Gate MongoDB strategy rendering
packages/system/backupstrategy-controller/templates/strategy-mongodb-default.yaml, packages/system/backupstrategy-controller/tests/rendering_test.yaml
The template renders the MongoDB Strategy only when $bucketName is populated. The bootstrap test verifies that no document renders without a bucket name and documents the install-order behavior.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 4f9c2

The change gates the default MongoDB strategy during bootstrap to prevent fresh installs from failing before its CRDs are available; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: androndo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes gating the default MongoDB strategy during bootstrap, which is the main change.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/mongodb-strategy-bootstrap-gate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blockers, this fixes it. I rendered the chart with the lookup unresolved at the merge base and at this head: the base emits exactly one strategy CR, MongoDB/cozy-default-mongodb, in the same manifest as the CRDs that would map it, and this head emits none. All eight come back once a bucket name resolves. Removing the gate again turns the flipped assertion red on that template alone, so it catches a revert.

Two things I would not block on.

With provisionBucket: false the helper returns the configured bucket name right away, so all eight strategies still render on the first install and the ordering problem is untouched in that configuration. Same before and after this PR, so not yours to fix here, but the template comment reads wider than the gate actually reaches.

On a cluster whose BucketClaim never resolved, upgrading drops an existing cozy-default-mongodb, since it is the one strategy that worked without a bucket name. The gate puts it back as soon as the bucket resolves.

@lexfrei
Aleksei Sviridkin (lexfrei) merged commit b7e51d5 into main Aug 14, 2026
15 of 17 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/mongodb-strategy-bootstrap-gate branch August 14, 2026 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/bug Categorizes issue or PR as related to a bug size/M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fresh install fails: backupstrategy-controller renders a MongoDB strategy in the same release that creates its CRD

2 participants