Skip to content

✨ Apply a ClusterObjectDeployment instead of managing ClusterObjectSets - #3058

Draft
perdasilva wants to merge 13 commits into
operator-framework:mainfrom
perdasilva:operator-controller-use-cod
Draft

perdasilva wants to merge 13 commits into
operator-framework:mainfrom
perdasilva:operator-controller-use-cod

Conversation

@perdasilva

Copy link
Copy Markdown
Contributor

Description

Switches the operator-controller ClusterExtension applier to manage a single
ClusterObjectDeployment (COD) instead of directly creating and managing
ClusterObjectSet (COS) revisions. The COD controller now owns revision
lifecycle (creation, rollout progress, archival, and history pruning), so the
operator-controller only has to render and apply one top-level object per
extension. This is the "use COD" step of delegating revision management to
ClusterObjectDeployment.

All changes are experimental-only (ClusterObjectDeployment is an experimental
API); standard manifests are unaffected.

Changes

  • Render + apply a COD: generate a packed ClusterObjectDeployment from
    bundle content and apply it, replacing direct ClusterObjectSet management.
  • Packed content: revision-independent packed Secret names, and propagation
    of bundle annotations (including olm.properties) from the COD through to its
    revisions.
  • Applyconfiguration builder for ClusterObjectDeployment.
  • Adoption: adopt pre-existing ClusterObjectSet revisions without forcing a
    re-rollout, reconciled against canonical revision names, with a defensive
    group-scope guard and clearer ownership error messages.
  • RBAC: grant operator-controller the permissions it needs for
    ClusterObjectDeployment.
  • Tests: new cod_extension_rollout e2e feature plus unit/mock updates.

Net: 16 files changed, ~975 insertions / ~1725 deletions (hand-rolled COS
management is removed in favor of delegating to the COD controller).

Testing

Draft — CI validation in progress. cod_extension_rollout.feature exercises the
ClusterExtension-via-ClusterObjectDeployment rollout path.

🤖 Generated with Claude Code

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Oct 23, 2026
@netlify

netlify Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit c98ff9f
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/6adb99a62aba396bfb44af37
😎 Deploy Preview https://deploy-preview-3058--olmv1.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@openshift-ci

openshift-ci Bot commented Oct 23, 2026

Copy link
Copy Markdown

[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 perdasilva 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 commented Oct 23, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

Per G. da Silva and others added 13 commits October 23, 2026 19:21
Change SecretPacker to use OwnerName instead of RevisionName for Secret
name prefixes and labels. This makes Secret names content-addressed and
independent of any specific revision, enabling Secrets to be created
before a revision exists.

- secretNameFromData now prefixes with p.OwnerName instead of p.RevisionName
- newSecret drops labels.RevisionNameKey, keeping only labels.OwnerNameKey
- RevisionName field retained for boxcutter.go compatibility
- Added TestSecretPacker_NameIsRevisionIndependent to verify behavior
- Updated existing test assertions to match new owner-based naming

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
…visions

The COD controller now copies bundle-metadata annotations (package name,
bundle name, bundle version, bundle release, and bundle reference) from
the ClusterObjectDeployment onto each ClusterObjectSet it creates. This
ensures the ClusterExtension status reader—which reads these annotations
off the COS—continues working during the refactor to make
operator-controller write CODs instead of managing COSes directly.

Only the known bundle-metadata annotation keys are copied; non-bundle
annotations on the COD are not propagated to revisions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Introduce buildClusterObjectDeployment, a pure helper function that
constructs a COD applyconfiguration from rendered content. This
mirrors the structure of the existing buildClusterObjectSet but
produces a COD with a template instead of directly setting
COS-specific fields.

The function:
- Sets metadata (name, annotations, owner labels)
- Configures spec.template.spec with:
  - PhaseSort-ordered phases
  - Default progression probes
  - Collision protection strategy
  - Optional progress deadline when > 0

This builder will be used in later tasks to produce the COD that
the applier will server-side-apply, as part of the refactor making
operator-controller write a COD instead of managing ClusterObjectSets
directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Add GenerateClusterObjectDeployment method to SimpleRevisionGenerator that
renders bundle manifests into a ClusterObjectDeployment with content-addressed
Secrets. This provides the generator seam that will be used by the applier
when writing CODs instead of managing ClusterObjectSets directly.

Key changes:
- Extract shared object-rendering logic from GenerateRevision into
  renderObjects helper (DRY principle)
- Add GenerateClusterObjectDeployment that packs objects into Secrets
  and returns a COD applyconfiguration with only refs
- Bundle-metadata annotations are placed on COD metadata
- CollisionProtection is set to Prevent
- Add SystemNamespace field to SimpleRevisionGenerator for Secret packing
- Add replaceInlineWithRefsInCOD helper for COD template phases

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Rewrite Boxcutter.Apply to server-side apply a single
ClusterObjectDeployment (COD) per ClusterExtension and create its
referenced, content-addressed Secrets, instead of creating and
garbage-collecting ClusterObjectSet revisions directly. The COD
controller now owns revision creation, rollout and retention.

- nil content: Get the COD named ext.Name; exists -> maintain state,
  NotFound -> error.
- else: generate COD + Secrets, set CE owner refs, run preflights
  (Install when Status.Install is nil, else Upgrade) on objects
  reconstructed from the packed Secrets, create Secrets then SSA-apply
  the COD.

Drop the COS install/upgrade state machine, revision numbering and
retention helpers, Secret ownerReference patching, the unused
SecretPacker.RevisionName field, and the dead
SimpleRevisionGenerator.GenerateRevision path. Trim the
ClusterObjectSetGenerator interface to GenerateClusterObjectDeployment
and GenerateRevisionFromHelmRelease (migrator stays COS-based) and
regenerate its mock.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
These pre-existing formatting issues (import ordering and map-literal
alignment) failed make lint; apply the gofmt/gci auto-fixes so the lint
gate passes. Formatting-only, no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
When operator-controller writes a COD for an extension that already has
an equivalent ClusterObjectSet (COS) revision (matching TemplateHashKey),
the COD controller now adopts the existing revision by setting the
controller owner reference instead of creating a spurious new revision.

This change:
- Exports TemplateHash() for use in tests and external packages
- Implements ensureRevisionOwnership() in the COD controller to adopt
  existing revisions that match the template hash but lack ownership
- Adds TestBoxcutterApply_AdoptsExistingRevisionWithoutReroll to verify
  that adoption happens without creating a new COS revision

The hash parity between the applier's COD template and the COD
controller's templateHash computation already held (Tasks 1-5 produced
matching hashes), but the adoption logic (setting owner reference) was
missing. This implementation completes the adoption feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
…RevisionOwnership

Address code-quality feedback on the adoption feature:

1. Add defensive group-scope guard: ensureRevisionOwnership now validates
   that rev.Spec.Group == cod.Name before attempting adoption, returning
   a clear error if they mismatch. This prevents adopting a revision from
   another deployment's group.

2. Improve error message when SetControllerReference fails: now includes
   a hint that the failure may be due to the revision already being owned
   by another controller.

3. Add comprehensive unit tests (Test_ensureRevisionOwnership) covering:
   - Rejection of revision with mismatched group (defensive guard)
   - Successful adoption of revision with matching group
   - No-op when revision is already owned

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Add kubebuilder RBAC markers to the ClusterExtension reconciler to grant
permissions for ClusterObjectDeployments, ClusterObjectSets, and Secrets.
This enables the operator-controller to create and manage ClusterObjectDeployments
and their referenced Secrets using the boxcutter applier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Adds cod_extension_rollout.feature (@BoxcutterRuntime) proving a ClusterExtension
installs via a ClusterObjectDeployment, which creates ClusterObjectSet revisions
for the bundle. The scenario verifies the COD exists, the COS becomes Ready, and
the ClusterExtension reports Installed=True with the expected bundle.

Uses existing catalog "test" package "test" 1.2.0 and existing e2e steps
(no new step implementation required).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
Before the COD refactor, SimpleRevisionGenerator placed the
olm.properties bundle annotation on ClusterObjectSet revisions.
After the refactor, the generator sets it on ClusterObjectDeployment
metadata, but the COD controller's annotation propagation list
did not include it, causing a regression: external consumers
(e.g., maxOpenShiftVersion tooling) that read olm.properties
from COS revisions no longer found it.

Restore parity by adding a shared OLMPropertiesKey constant in
internal/shared/labels and including it in the COD controller's
bundleAnnotationKeys slice. The applier now references the shared
constant, and source.PropertyOLMProperties references it to prevent
drift. The propagation test now verifies olm.properties reaches
the COS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
…names (operator-framework#3041)

Rebasing onto main (which merged operator-framework#3041) surfaced two integration points:

- Remove the obsolete applier-level revision-bounds test. operator-framework#3041 added
  TestBoxcutter_Apply_RevisionBounds, which exercises the applier's
  createExternalizedRevision / ClusterObjectSetRetentionLimit path that this
  branch removes. The equivalent revision-limit enforcement and its test now
  live in the ClusterObjectDeployment controller
  (Test_ClusterObjectDeploymentReconciler_RevisionBounds).

- Make ensureRevisionOwnership tolerant of foreign-owned revisions. operator-framework#3041's
  "unchanged template at maximum still reconciles" case models a ClusterObjectSet
  in the group controlled by another deployment and expects reconcile to be a
  no-op, not an error. Adoption now claims only true orphans (no controller
  owner) and leaves a revision controlled by a different controller untouched
  rather than erroring, so a foreign-owned sibling cannot wedge reconciliation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
…data

The direct-ClusterObjectSet path labeled every revision with the owner-kind and
owner-name labels. The ClusterObjectDeployment path had moved those labels onto
the deployment object only, leaving each ClusterObjectSet revision with just the
controller-managed template-hash label.

Set spec.template.metadata.labels on the generated ClusterObjectDeployment to the
owner labels so the object-controller propagates them verbatim onto every revision
it creates, restoring the pre-refactor revision labeling through the template
metadata channel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Per G. da Silva <pegoncal@redhat.com>
@perdasilva
perdasilva force-pushed the operator-controller-use-cod branch from 0e3133a to c98ff9f Compare October 23, 2026 17:30

This branch has not been deployed

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

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant