Skip to content

OCPCLOUD-3647: Convert adopt-existing to use a ManifestTransformer - #635

Open
mdbooth wants to merge 7 commits into
openshift:mainfrom
openshift-cloud-team:manifesttransformers/030-adopt-existing
Open

OCPCLOUD-3647: Convert adopt-existing to use a ManifestTransformer#635
mdbooth wants to merge 7 commits into
openshift:mainfrom
openshift-cloud-team:manifesttransformers/030-adopt-existing

Conversation

@mdbooth

@mdbooth mdbooth commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Converts the existing adopt-existing transformation to use a ManifestTransformer.

TODO:

Summary by CodeRabbit

  • New Features

    • Added configurable manifest transformation during installation and revision reconciliation.
    • Added support for adopting existing resources via the supported “adopt-existing” setting to relax collision handling when enabled.
    • Transformers can modify objects and influence reconciliation behavior.
  • Bug Fixes

    • Transformer validation failures now surface as non-retryable reconciliation errors.
    • Transformation errors are aggregated with object context; skipped or failed objects are not applied to generated phases.
  • Tests

    • Expanded coverage for transformer integration, object phase generation, and error/skip behavior.

mdbooth added 5 commits July 28, 2026 18:09
We were previously pre-converting all API revisions into installer
revisions. The purpose of this was to assemble all related objects
before reconciliation. However, we weren't actually writing them so this
served no purpose. We take the opportunity to remove the unnecessary
complexity.
This allows us to add code to component generation which can fail.
This is now handled in toBoxcutterRevision
ManifestTransformer is a common interface for transformations on
resource manifests. It is intended to cover all existing ad-hoc
transformations, although they are not implemented in this change.
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 29, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 29, 2026

Copy link
Copy Markdown

@mdbooth: This pull request references OCPCLOUD-3647 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Converts the existing adopt-existing transformation to use a ManifestTransformer.

TODO:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Walkthrough

The PR adds configurable manifest transformers, moves adopt-existing validation into the transformer package, unifies rendered objects, applies transformations during Boxcutter revision construction, and wires transformers through installer and revision controller reconciliation.

Changes

Manifest transformer integration

Layer / File(s) Summary
Transformer contracts and adopt-existing behavior
pkg/manifesttransformer/*
Defines transformer validation and transformation contracts, aggregates validation errors, and implements adopt-existing annotation handling with collision-protection options.
Unified rendered object model
pkg/revisiongenerator/revision.go, pkg/revisiongenerator/validate.go, pkg/revisiongenerator/revision_test.go
Stores rendered manifests as unstructured object pointers, removes object collectors and CRD accessors, and removes renderer-side adopt-existing validation.
Boxcutter transformation pipeline
pkg/controllers/installer/boxcutter.go, pkg/controllers/installer/boxcutter_test.go
Applies transformers once per object, splits CRD and non-CRD phases, propagates reconcile options, skips nil outputs, and aggregates transformation errors.
Controller wiring and reconciliation
cmd/capi-installer/main.go, pkg/controllers/installer/..., pkg/controllers/revision/...
Passes transformers into controllers, validates them during reconciliation, constructs revisions from API objects, and updates collected-object resolution timing.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CAPIInstaller
  participant RevisionController
  participant InstallerController
  participant ManifestTransformer
  participant Boxcutter
  CAPIInstaller->>RevisionController: configure Transformers
  CAPIInstaller->>InstallerController: configure transformers
  RevisionController->>ManifestTransformer: validate rendered objects
  InstallerController->>ManifestTransformer: transform installer objects
  ManifestTransformer-->>InstallerController: transformed objects and reconcile options
  InstallerController->>Boxcutter: build revision phases
Loading

Possibly related PRs

Suggested reviewers: theobarberbany, racheljpg

🚥 Pre-merge checks | ✅ 13 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Microshift Test Compatibility ⚠️ Warning New Ginkgo test in pkg/controllers/revision/revision_controller_test.go reads configv1.ClusterOperator without a MicroShift skip/tag; ClusterOperator is unavailable on MicroShift. Add a [Skipped:MicroShift] or [apigroup:config.openshift.io] label, or guard the test with exutil.IsMicroShiftCluster() and g.Skip().
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: converting adopt-existing to use a ManifestTransformer.
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.
Stable And Deterministic Test Names ✅ Passed Reviewed all changed Ginkgo titles; they’re static strings and don’t interpolate names, timestamps, UUIDs, or other changing values.
Test Structure And Quality ✅ Passed New Ginkgo cases are narrowly scoped, use BeforeEach/AfterEach or DeferCleanup, and cluster waits in added tests include explicit timeouts.
Single Node Openshift (Sno) Test Compatibility ✅ Passed New Ginkgo tests are controller/envtest focused and contain no node/topology/scheduling assumptions; no SNO-sensitive patterns were found.
Topology-Aware Scheduling Compatibility ✅ Passed No scheduling constraints were added: modified files only wire manifest transformers and revision validation, with no node selectors, affinity, spread, PDB, or replica logic.
Ote Binary Stdout Contract ✅ Passed No process-level stdout writes were added; setup loggers target GinkgoWriter/stderr and main/init only configure controllers.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed Added Ginkgo tests are envtest/unit-only; no IPv4 literals, host:port URL builds, curl/wget, or external-host connectivity were found.
No-Weak-Crypto ✅ Passed No added lines use weak crypto; only SHA-256 is introduced, and the RC4 TLS cipher in a test helper is pre-existing context, not part of the patch.
Container-Privileges ✅ Passed Touched files are Go-only; no privileged/host* or allowPrivilegeEscalation settings appear in the PR scope.
No-Sensitive-Data-In-Logs ✅ Passed No new sensitive logging was added; the changed code logs only revision/object metadata, not secrets, tokens, or PII.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@mdbooth

mdbooth commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

/hold

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 29, 2026
@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign racheljpg for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
pkg/controllers/installer/revision_reconciler_test.go (1)

201-219: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Follow the required Ginkgo test conventions.

Rename the It title to start with “should”, add a By(...) before reconciliation, and give the first three assertions failure messages.

As per coding guidelines, use descriptive test names in “should...” format with By() for test steps, and include meaningful assertion messages.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/installer/revision_reconciler_test.go` around lines 201 -
219, Update the test title in revisionReconciler.reconcileRevision to start with
“should” and add a By(...) step immediately before calling reconcileRevision.
Add meaningful failure messages to the first three assertions while preserving
their existing expectations and behavior.

Source: Coding guidelines

pkg/manifesttransformer/validate_test.go (1)

31-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Use the repository’s Ginkgo suite pattern.

This testing.T/t.Run suite should be converted to Describe/It; the nil/empty and multi-object variants are good DescribeTable candidates.

As per coding guidelines, “Use Ginkgo/Gomega framework and prefer built-in features: use DescribeTable with Entry for table-driven tests.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/manifesttransformer/validate_test.go` around lines 31 - 132, The
TestValidateTransformers suite currently uses testing.T and t.Run instead of the
repository’s Ginkgo pattern. Convert TestValidateTransformers to Describe/It
with Gomega assertions, and consolidate the nil-transformers,
empty-transformers, and multi-object cases into appropriate DescribeTable
entries using Entry; preserve all existing validation and error-aggregation
coverage.

Source: Coding guidelines

pkg/controllers/revision/revision_controller_test.go (1)

588-588: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the reconcile result rather than discarding it.

Swallowing both returns hides whether Reconcile surfaced a non-retryable (terminal) error; assert the error explicitly alongside the conditions.

♻️ Suggested change
-		_, _ = r.Reconcile(ctx, reconcile.Request{NamespacedName: client.ObjectKey{Name: "cluster"}})
+		_, err := r.Reconcile(ctx, reconcile.Request{NamespacedName: client.ObjectKey{Name: "cluster"}})
+		Expect(err).To(MatchError(ContainSubstring("invalid manifest")), "Reconcile should surface the transformer validation failure")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/revision/revision_controller_test.go` at line 588, Update the
Reconcile invocation in the test to capture both returned values instead of
discarding them, then explicitly assert that the returned error matches the
expected non-retryable outcome alongside the existing condition assertions.
pkg/controllers/installer/boxcutter.go (1)

69-70: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Hoist the CRD GroupKind literal.

The same schema.GroupKind{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition"} literal is repeated in pkg/controllers/installer/revision_reconciler.go (Line 462). A package-level var crdGroupKind = ... (or apiextensionsv1.SchemeGroupVersion.WithKind(...)) keeps the two in sync.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/installer/boxcutter.go` around lines 69 - 70, Define a shared
package-level CRD GroupKind value and replace the inline literal in the
installer controller’s object-kind comparison with that variable. Reuse the same
value in revision_reconciler.go so both CRD checks remain synchronized.
pkg/revisiongenerator/validate.go (1)

19-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider renaming the file now that it only holds annotation constants.

All validation moved to pkg/manifesttransformer; validate.go containing just the adopt-existing constants is misleading (e.g. annotations.go).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/revisiongenerator/validate.go` around lines 19 - 24, Rename validate.go
to annotations.go because it now only defines annotation constants after
validation moved to pkg/manifesttransformer. Keep the existing annotation
constants and contents unchanged.
pkg/controllers/installer/boxcutter_test.go (1)

180-213: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add failure messages to these assertions.

Lines 181, 199–201 and 211–213 assert phase counts/names without messages, unlike the rest of the file. As per coding guidelines, "assertions should include meaningful failure messages, flag missing messages".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/installer/boxcutter_test.go` around lines 180 - 213, Add
meaningful failure messages to the phase count and phase name assertions in the
affected tests around the mixed, no-CRD, and CRD-only cases. Update the
assertions on phases length, phases[0].GetName(), and related phase expectations
to describe the expected phase structure, matching the existing message style in
the file.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controllers/installer/boxcutter.go`:
- Around line 64-75: Move the collectObjects invocation in the object-processing
flow so it receives each object only after applyTransformers has transformed or
retained it. Skip collection when the transformer returns nil, and ensure
relatedObjects, gvks, and CRD plural mappings use the transformed object
identity rather than the original.

---

Nitpick comments:
In `@pkg/controllers/installer/boxcutter_test.go`:
- Around line 180-213: Add meaningful failure messages to the phase count and
phase name assertions in the affected tests around the mixed, no-CRD, and
CRD-only cases. Update the assertions on phases length, phases[0].GetName(), and
related phase expectations to describe the expected phase structure, matching
the existing message style in the file.

In `@pkg/controllers/installer/boxcutter.go`:
- Around line 69-70: Define a shared package-level CRD GroupKind value and
replace the inline literal in the installer controller’s object-kind comparison
with that variable. Reuse the same value in revision_reconciler.go so both CRD
checks remain synchronized.

In `@pkg/controllers/installer/revision_reconciler_test.go`:
- Around line 201-219: Update the test title in
revisionReconciler.reconcileRevision to start with “should” and add a By(...)
step immediately before calling reconcileRevision. Add meaningful failure
messages to the first three assertions while preserving their existing
expectations and behavior.

In `@pkg/controllers/revision/revision_controller_test.go`:
- Line 588: Update the Reconcile invocation in the test to capture both returned
values instead of discarding them, then explicitly assert that the returned
error matches the expected non-retryable outcome alongside the existing
condition assertions.

In `@pkg/manifesttransformer/validate_test.go`:
- Around line 31-132: The TestValidateTransformers suite currently uses
testing.T and t.Run instead of the repository’s Ginkgo pattern. Convert
TestValidateTransformers to Describe/It with Gomega assertions, and consolidate
the nil-transformers, empty-transformers, and multi-object cases into
appropriate DescribeTable entries using Entry; preserve all existing validation
and error-aggregation coverage.

In `@pkg/revisiongenerator/validate.go`:
- Around line 19-24: Rename validate.go to annotations.go because it now only
defines annotation constants after validation moved to pkg/manifesttransformer.
Keep the existing annotation constants and contents unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 35d18b42-f171-4128-a3bd-bb64473d9aea

📥 Commits

Reviewing files that changed from the base of the PR and between d6c24ca and b92c47a.

📒 Files selected for processing (19)
  • cmd/capi-installer/main.go
  • pkg/controllers/installer/boxcutter.go
  • pkg/controllers/installer/boxcutter_test.go
  • pkg/controllers/installer/installer_controller.go
  • pkg/controllers/installer/revision_reconciler.go
  • pkg/controllers/installer/revision_reconciler_test.go
  • pkg/controllers/installer/suite_test.go
  • pkg/controllers/revision/helpers_test.go
  • pkg/controllers/revision/revision_controller.go
  • pkg/controllers/revision/revision_controller_test.go
  • pkg/manifesttransformer/adopt_existing_transformer.go
  • pkg/manifesttransformer/adopt_existing_transformer_test.go
  • pkg/manifesttransformer/manifest_transformer.go
  • pkg/manifesttransformer/validate.go
  • pkg/manifesttransformer/validate_test.go
  • pkg/revisiongenerator/revision.go
  • pkg/revisiongenerator/revision_test.go
  • pkg/revisiongenerator/validate.go
  • pkg/revisiongenerator/validate_test.go
💤 Files with no reviewable changes (1)
  • pkg/revisiongenerator/validate_test.go

Comment on lines +64 to +75
for _, obj := range component.Objects() {
if collectObjects != nil {
collectObjects(obj)
}

gvk := obj.GetObjectKind().GroupVersionKind()
if gvk.GroupKind() == (schema.GroupKind{Group: "apiextensions.k8s.io", Kind: "CustomResourceDefinition"}) {
crds = append(crds, obj)
} else {
objects = append(objects, obj)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

collectObjects sees pre-transform objects, including ones transformers skip.

Objects are collected before applyTransformers runs, so an object a transformer drops (nil return) still lands in relatedObjects/gvks/the CRD plural mapping, and renamed objects are collected under their original identity. If collection is meant to describe what is actually applied, move the callback after transformation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/installer/boxcutter.go` around lines 64 - 75, Move the
collectObjects invocation in the object-processing flow so it receives each
object only after applyTransformers has transformed or retained it. Skip
collection when the transformer returns nil, and ensure relatedObjects, gvks,
and CRD plural mappings use the transformed object identity rather than the
original.

@mdbooth
mdbooth force-pushed the manifesttransformers/030-adopt-existing branch from b92c47a to 4f0f78d Compare July 29, 2026 15:17

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/controllers/installer/installer_controller_test.go (1)

198-241: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the new specs with the required Ginkgo conventions.

Rename the It blocks to should... form, add By() steps around setup/trigger/update operations, and provide meaningful messages for the new assertions.

As per coding guidelines, Ginkgo tests should use descriptive should... names, By() steps, and meaningful assertion messages.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controllers/installer/installer_controller_test.go` around lines 198 -
241, Update the two It blocks in the ManifestTransformer Drift context to
descriptive should... names. Add By() steps around setup, transformer changes,
reconcile triggers, and annotation removal, and provide meaningful messages for
each newly added assertion, especially the Eventually checks verifying
annotation values.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/controllers/installer/installer_controller_test.go`:
- Around line 198-241: Update the two It blocks in the ManifestTransformer Drift
context to descriptive should... names. Add By() steps around setup, transformer
changes, reconcile triggers, and annotation removal, and provide meaningful
messages for each newly added assertion, especially the Eventually checks
verifying annotation values.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 6d8cc960-d1f2-4614-8db3-737025457d50

📥 Commits

Reviewing files that changed from the base of the PR and between b92c47a and 4f0f78d.

📒 Files selected for processing (11)
  • cmd/capi-installer/main.go
  • pkg/controllers/installer/boxcutter.go
  • pkg/controllers/installer/installer_controller_test.go
  • pkg/controllers/installer/suite_test.go
  • pkg/controllers/installer/testvalue_transformer_test.go
  • pkg/controllers/revision/helpers_test.go
  • pkg/manifesttransformer/adopt_existing_transformer.go
  • pkg/manifesttransformer/adopt_existing_transformer_test.go
  • pkg/revisiongenerator/revision.go
  • pkg/revisiongenerator/validate.go
  • pkg/revisiongenerator/validate_test.go
💤 Files with no reviewable changes (2)
  • pkg/revisiongenerator/validate_test.go
  • pkg/revisiongenerator/revision.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • pkg/manifesttransformer/adopt_existing_transformer_test.go
  • pkg/revisiongenerator/validate.go
  • pkg/controllers/revision/helpers_test.go
  • pkg/manifesttransformer/adopt_existing_transformer.go
  • cmd/capi-installer/main.go
  • pkg/controllers/installer/boxcutter.go

@openshift-ci

openshift-ci Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

@mdbooth: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants