Skip to content

Commit 3a1c266

Browse files
(chore): (Boxcutter): Use label selector for listing previous revisions
Replaces explicit spec.Previous with dynamic cache query. Generated-by: Cursor/Claude
1 parent b3f85d5 commit 3a1c266

File tree

2 files changed

+285
-42
lines changed

2 files changed

+285
-42
lines changed

internal/operator-controller/controllers/clusterextensionrevision_controller.go

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"k8s.io/apimachinery/pkg/api/equality"
1717
"k8s.io/apimachinery/pkg/api/meta"
1818
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19-
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2019
"k8s.io/apimachinery/pkg/runtime/schema"
2120
"k8s.io/apimachinery/pkg/types"
2221
"k8s.io/apimachinery/pkg/util/sets"
@@ -116,7 +115,17 @@ func checkForUnexpectedClusterExtensionRevisionFieldChange(a, b ocv1.ClusterExte
116115
func (c *ClusterExtensionRevisionReconciler) reconcile(ctx context.Context, rev *ocv1.ClusterExtensionRevision) (ctrl.Result, error) {
117116
l := log.FromContext(ctx)
118117

119-
revision, opts, previous := toBoxcutterRevision(rev)
118+
revision, opts, err := c.toBoxcutterRevision(ctx, rev)
119+
if err != nil {
120+
meta.SetStatusCondition(&rev.Status.Conditions, metav1.Condition{
121+
Type: ocv1.ClusterExtensionRevisionTypeAvailable,
122+
Status: metav1.ConditionFalse,
123+
Reason: ocv1.ClusterExtensionRevisionReasonReconcileFailure,
124+
Message: err.Error(),
125+
ObservedGeneration: rev.Generation,
126+
})
127+
return ctrl.Result{}, fmt.Errorf("converting to boxcutter revision: %v", err)
128+
}
120129

121130
if !rev.DeletionTimestamp.IsZero() || rev.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStateArchived {
122131
return c.teardown(ctx, rev, revision)
@@ -212,7 +221,11 @@ func (c *ClusterExtensionRevisionReconciler) reconcile(ctx context.Context, rev
212221

213222
//nolint:nestif
214223
if rres.IsComplete() {
215-
// Archive other revisions.
224+
// Archive previous revisions
225+
previous, err := c.ListPreviousRevisions(ctx, rev)
226+
if err != nil {
227+
return ctrl.Result{}, fmt.Errorf("listing previous revisions: %v", err)
228+
}
216229
for _, a := range previous {
217230
patch := []byte(`{"spec":{"lifecycleState":"Archived"}}`)
218231
if err := c.Client.Patch(ctx, a, client.RawPatch(types.MergePatchType, patch)); err != nil {
@@ -428,14 +441,41 @@ func (c *ClusterExtensionRevisionReconciler) removeFinalizer(ctx context.Context
428441
return nil
429442
}
430443

431-
func toBoxcutterRevision(rev *ocv1.ClusterExtensionRevision) (*boxcutter.Revision, []boxcutter.RevisionReconcileOption, []client.Object) {
432-
previous := make([]client.Object, 0, len(rev.Spec.Previous))
433-
for _, specPrevious := range rev.Spec.Previous {
434-
prev := &unstructured.Unstructured{}
435-
prev.SetName(specPrevious.Name)
436-
prev.SetUID(specPrevious.UID)
437-
prev.SetGroupVersionKind(ocv1.GroupVersion.WithKind(ocv1.ClusterExtensionRevisionKind))
438-
previous = append(previous, prev)
444+
// ListPreviousRevisions returns active revisions with the same owner, excluding self and archived.
445+
// Used by boxcutter for collision detection and to mark old revisions as archived on successful rollout.
446+
func (c *ClusterExtensionRevisionReconciler) ListPreviousRevisions(ctx context.Context, rev *ocv1.ClusterExtensionRevision) ([]client.Object, error) {
447+
ownerLabel, ok := rev.Labels[ClusterExtensionRevisionOwnerLabel]
448+
if !ok {
449+
return nil, nil
450+
}
451+
452+
revList := &ocv1.ClusterExtensionRevisionList{}
453+
if err := c.Client.List(ctx, revList, client.MatchingLabels{
454+
ClusterExtensionRevisionOwnerLabel: ownerLabel,
455+
}); err != nil {
456+
return nil, fmt.Errorf("listing revisions: %w", err)
457+
}
458+
459+
previous := make([]client.Object, 0, len(revList.Items))
460+
for i := range revList.Items {
461+
r := &revList.Items[i]
462+
if r.Name == rev.Name {
463+
continue
464+
}
465+
if r.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStateArchived ||
466+
!r.DeletionTimestamp.IsZero() {
467+
continue
468+
}
469+
previous = append(previous, r)
470+
}
471+
472+
return previous, nil
473+
}
474+
475+
func (c *ClusterExtensionRevisionReconciler) toBoxcutterRevision(ctx context.Context, rev *ocv1.ClusterExtensionRevision) (*boxcutter.Revision, []boxcutter.RevisionReconcileOption, error) {
476+
previous, err := c.ListPreviousRevisions(ctx, rev)
477+
if err != nil {
478+
return nil, nil, fmt.Errorf("listing previous revisions: %w", err)
439479
}
440480

441481
opts := []boxcutter.RevisionReconcileOption{
@@ -476,7 +516,7 @@ func toBoxcutterRevision(rev *ocv1.ClusterExtensionRevision) (*boxcutter.Revisio
476516
if rev.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStatePaused {
477517
opts = append(opts, boxcutter.WithPaused{})
478518
}
479-
return r, opts, previous
519+
return r, opts, nil
480520
}
481521

482522
var (

0 commit comments

Comments
 (0)