⚠️ ClusterExtensionRevision API Updates#2491
⚠️ ClusterExtensionRevision API Updates#2491openshift-merge-bot[bot] merged 1 commit intooperator-framework:mainfrom
Conversation
✅ Deploy Preview for olmv1 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
/hold |
5a0ef97 to
6e4fa46
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2491 +/- ##
==========================================
- Coverage 69.82% 69.45% -0.37%
==========================================
Files 102 102
Lines 8496 8505 +9
==========================================
- Hits 5932 5907 -25
- Misses 2091 2129 +38
+ Partials 473 469 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
pedjak
left a comment
There was a problem hiding this comment.
I would expect additional validation tests to add, given that we added a few more restrictions/checks in this PR. Like for checking min/max size of given arrays, etc.
| // | ||
| // Once set, even if empty, the phases field is immutable. | ||
| // | ||
| // Each phase in the list must have a unique name. The maximum number of phases is 20. |
There was a problem hiding this comment.
should we also set the min number of phases to 1?
There was a problem hiding this comment.
Sure, unless we can think of a genuinely useful reason to create a no-op CER? I can't think of one though.
There was a problem hiding this comment.
Update: Looks like we've intentionally built in the ability to have phases initially unset, and allow the normally immutable list to be updated once. If we want to preserve that, we can't set the minimum length to 1 with omitempty present. Removing omitempty removes our ability to leave it unset. Is it vital that we keep this in place?
There was a problem hiding this comment.
While we only use inline objects, it's ok to set a minimum. When we move to sharding, it could be that we'll want to create the ClusterExtensionRevision object first, then create the shards with the ownerref, then update the revision with the shard refs.
There was a problem hiding this comment.
Here's the helm chunked secret implementation: https://github.com/operator-framework/helm-operator-plugins/blob/f1e4eaf3b3924d3339dda2eee7f4520c47fd6162/pkg/storage/chunked.go#L62-L90
There we precompute everything, then:
- Create the immutable index object with all of the chunk references pre-filled
- Create the immutable chunks with owner refs to the index
We can do the same with the CER right?
- Make its phases fully immutable
- Generate the phase object contents and figure out what the names are going to be so we can pre-fill references in the CER
- Generate the CER with the phase object references pre-filled
- Generate the phase objects with the CER ownerRef
That way:
- If we try to read the phases from the CER after 3, but before 4, we correctly get an error instead of incorrectly assuming there are no phases
- If the CER is deleted between 3 and 4, we'll end up putting an ownerref on the phase objects that for an object that is already deleted and garbage collect will automatically delete the phase objects.
- Phases are immutable and create-only and we don't have to handle errors that could occur on an attempt to update the phases.
There was a problem hiding this comment.
Thanks Joe - agreed on these points, but this will take some more work beyond just the API changes. Can we take care of this as a separate issue? Or is getting in the full immutability for phases too critical?
6e4fa46 to
1be387b
Compare
1be387b to
f417730
Compare
f417730 to
2f874e5
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates the ClusterExtensionRevision API surface (Go types + generated CRDs/manifests) to address gaps identified during API review, primarily by tightening schema requirements and improving documentation.
Changes:
- Make
spec.lifecycleStateand per-objectcollisionProtectionrequired (removing CRD defaults). - Add/clarify schema constraints for inline phases (e.g., max phases/objects) and expand lifecycle/phase documentation.
- Update operator-controller generator/tests and API validation tests to populate newly-required fields.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| manifests/experimental.yaml | Updates experimental manifest schema/docs to reflect new required fields and constraints. |
| manifests/experimental-e2e.yaml | Mirrors the experimental schema/doc updates for e2e manifests. |
| helm/olmv1/base/operator-controller/crd/experimental/olm.operatorframework.io_clusterextensionrevisions.yaml | Updates the shipped Helm CRD for ClusterExtensionRevision with the new requirements/validations. |
| api/v1/clusterextensionrevision_types.go | Source-of-truth API changes: required markers, added validations/limits, doc updates. |
| api/v1/clusterextensionrevision_types_test.go | Adds/updates envtest-backed validity/immutability tests for the new schema. |
| api/v1/validation_test.go | Updates validation tests to set LifecycleState where required. |
| internal/operator-controller/applier/boxcutter.go | Ensures generated revision objects always set CollisionProtection. |
| internal/operator-controller/applier/boxcutter_test.go | Updates expectations to include CollisionProtection in generated revision objects. |
Comments suppressed due to low confidence (1)
api/v1/clusterextensionrevision_types.go:60
LifecycleStateis marked+requiredand the CRD now requires it, but the Go JSON tag still usesomitempty. This is inconsistent with other required fields in this repo (which typically omitomitempty) and can cause marshaling to silently drop the field when the zero value is present, producing invalid objects. Consider removingomitempty(and update any constructors/tests that currently rely on omitting the field, e.g. helpers that buildClusterExtensionRevisionSpec{Revision: ...}without a lifecycleState).
// +required
// +kubebuilder:validation:Enum=Active;Archived
// +kubebuilder:validation:XValidation:rule="oldSelf == 'Active' || oldSelf == 'Archived' && oldSelf == self", message="cannot un-archive"
LifecycleState ClusterExtensionRevisionLifecycleState `json:"lifecycleState,omitempty"`
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
35e7673 to
66b75c9
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...operator-controller/crd/experimental/olm.operatorframework.io_clusterextensionrevisions.yaml
Show resolved
Hide resolved
Fixing some missing flags and godoc comments brought up via API review. Signed-off-by: Daniel Franz <dfranz@redhat.com>
66b75c9 to
1225187
Compare
|
/unhold |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "phases entries must have no more than 50 objects": { | ||
| spec: ClusterExtensionRevisionSpec{ | ||
| LifecycleState: ClusterExtensionRevisionLifecycleStateActive, | ||
| Revision: 1, | ||
| Phases: []ClusterExtensionRevisionPhase{ | ||
| { | ||
| Name: "too-many-objects", | ||
| Objects: make([]ClusterExtensionRevisionObject, 51), | ||
| }, | ||
| }, | ||
| }, | ||
| valid: false, | ||
| }, |
There was a problem hiding this comment.
The test case "phases entries must have no more than 50 objects" creates 51 ClusterExtensionRevisionObject instances using make(), which initializes them with zero values. Since CollisionProtection is now a required field, all 51 objects will have an empty CollisionProtection value that doesn't match the enum constraint. This test will likely fail due to the missing required field rather than testing the maxItems validation as intended. Consider initializing the objects with a valid CollisionProtection value to ensure the test properly validates the maxItems constraint.
| "phases must have no more than 20 phases": { | ||
| spec: ClusterExtensionRevisionSpec{ | ||
| LifecycleState: ClusterExtensionRevisionLifecycleStateActive, | ||
| Revision: 1, | ||
| Phases: make([]ClusterExtensionRevisionPhase, 21), | ||
| }, | ||
| valid: false, | ||
| }, |
There was a problem hiding this comment.
The test case "phases must have no more than 20 phases" creates 21 ClusterExtensionRevisionPhase instances using make(), which initializes them with zero values including empty Name strings and empty Objects slices. Since Name has minLength=1 and Objects is required, these phases will fail validation for missing required fields rather than testing the maxItems constraint on phases. Consider initializing the phases with valid Name values and at least one valid Object to ensure the test properly validates the 20-phase limit.
|
/approve |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: perdasilva The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
130c987
into
operator-framework:main
Fixing some missing flags and godoc comments brought up via API review.
Reviewer Checklist