Skip to content

Commit 33610fa

Browse files
committed
CRE Previous Limit
Sets a limit to the number of previous ClusterExtensionRevisions we keep in the cluster, and trims the list of previous revisions when creating new revisions to stay at the limit. The limit has been set to 5 for now. Any revisions beyond this limit will be removed from the cluster. Signed-off-by: Daniel Franz <dfranz@redhat.com>
1 parent 1821160 commit 33610fa

2 files changed

Lines changed: 110 additions & 3 deletions

File tree

internal/operator-controller/applier/boxcutter.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/davecgh/go-spew/spew"
1717
"helm.sh/helm/v3/pkg/release"
1818
"helm.sh/helm/v3/pkg/storage/driver"
19+
apierrors "k8s.io/apimachinery/pkg/api/errors"
1920
"k8s.io/apimachinery/pkg/api/meta"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -35,7 +36,8 @@ import (
3536
)
3637

3738
const (
38-
RevisionHashAnnotation = "olm.operatorframework.io/hash"
39+
RevisionHashAnnotation = "olm.operatorframework.io/hash"
40+
ClusterExtensionRevisionPreviousLimit = 5
3941
)
4042

4143
type ClusterExtensionRevisionGenerator interface {
@@ -292,6 +294,10 @@ func (bc *Boxcutter) apply(ctx context.Context, contentFS fs.FS, ext *ocv1.Clust
292294
})
293295
}
294296

297+
if err = bc.garbageCollectPreviousRevisions(ctx, newRevision); err != nil {
298+
return false, "", fmt.Errorf("garbage collecting old Revisions: %w", err)
299+
}
300+
295301
if err := controllerutil.SetControllerReference(ext, newRevision, bc.Scheme); err != nil {
296302
return false, "", fmt.Errorf("set ownerref: %w", err)
297303
}
@@ -301,8 +307,6 @@ func (bc *Boxcutter) apply(ctx context.Context, contentFS fs.FS, ext *ocv1.Clust
301307
currentRevision = newRevision
302308
}
303309

304-
// TODO: Delete archived previous revisions over a certain revision limit
305-
306310
progressingCondition := meta.FindStatusCondition(currentRevision.Status.Conditions, ocv1.TypeProgressing)
307311
availableCondition := meta.FindStatusCondition(currentRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeAvailable)
308312
succeededCondition := meta.FindStatusCondition(currentRevision.Status.Conditions, ocv1.ClusterExtensionRevisionTypeSucceeded)
@@ -319,6 +323,31 @@ func (bc *Boxcutter) apply(ctx context.Context, contentFS fs.FS, ext *ocv1.Clust
319323
return true, "", nil
320324
}
321325

326+
// garbageCollectPreviousRevisions trims the list of previous revisions down to ClusterExtensionRevisionPreviousLimit and deletes
327+
// the corresponding revisions from the cluster
328+
func (bc *Boxcutter) garbageCollectPreviousRevisions(ctx context.Context, revision *ocv1.ClusterExtensionRevision) error {
329+
if revision == nil || len(revision.Spec.Previous) <= ClusterExtensionRevisionPreviousLimit {
330+
return nil
331+
}
332+
for index, r := range revision.Spec.Previous {
333+
if index < len(revision.Spec.Previous)-ClusterExtensionRevisionPreviousLimit {
334+
// Delete oldest CREs from the cluster and list to reach ClusterExtensionRevisionPreviousLimit
335+
if err := bc.Client.Delete(ctx, &ocv1.ClusterExtensionRevision{
336+
ObjectMeta: metav1.ObjectMeta{
337+
Name: r.Name,
338+
},
339+
}); err != nil && !apierrors.IsNotFound(err) {
340+
return fmt.Errorf("deleting previous Revision: %w", err)
341+
}
342+
} else {
343+
break
344+
}
345+
}
346+
// trim the list of previous revisions in place by preserving revisions starting from index len(revisions) - ClusterExtensionRevisionPreviousLimit
347+
revision.Spec.Previous = revision.Spec.Previous[len(revision.Spec.Previous)-ClusterExtensionRevisionPreviousLimit:]
348+
return nil
349+
}
350+
322351
// getExistingRevisions returns the list of ClusterExtensionRevisions for a ClusterExtension with name extName in revision order (oldest to newest)
323352
func (bc *Boxcutter) getExistingRevisions(ctx context.Context, extName string) ([]ocv1.ClusterExtensionRevision, error) {
324353
existingRevisionList := &ocv1.ClusterExtensionRevisionList{}

internal/operator-controller/applier/boxcutter_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"helm.sh/helm/v3/pkg/storage/driver"
1616
appsv1 "k8s.io/api/apps/v1"
1717
corev1 "k8s.io/api/core/v1"
18+
apierrors "k8s.io/apimachinery/pkg/api/errors"
1819
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1920
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2021
"k8s.io/apimachinery/pkg/runtime"
@@ -567,6 +568,83 @@ func TestBoxcutter_Apply(t *testing.T) {
567568
assert.Empty(t, revList.Items)
568569
},
569570
},
571+
{
572+
name: "sixth revision",
573+
mockBuilder: &mockBundleRevisionBuilder{
574+
makeRevisionFunc: func(bundleFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, revisionAnnotations map[string]string) (*ocv1.ClusterExtensionRevision, error) {
575+
return &ocv1.ClusterExtensionRevision{
576+
ObjectMeta: metav1.ObjectMeta{
577+
Annotations: revisionAnnotations,
578+
Labels: map[string]string{
579+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
580+
},
581+
},
582+
Spec: ocv1.ClusterExtensionRevisionSpec{},
583+
}, nil
584+
},
585+
},
586+
existingObjs: []client.Object{
587+
&ocv1.ClusterExtensionRevision{
588+
ObjectMeta: metav1.ObjectMeta{
589+
Name: "rev-1",
590+
Labels: map[string]string{
591+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
592+
},
593+
},
594+
},
595+
&ocv1.ClusterExtensionRevision{
596+
ObjectMeta: metav1.ObjectMeta{
597+
Name: "rev-2",
598+
Labels: map[string]string{
599+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
600+
},
601+
},
602+
},
603+
&ocv1.ClusterExtensionRevision{
604+
ObjectMeta: metav1.ObjectMeta{
605+
Name: "rev-3",
606+
Labels: map[string]string{
607+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
608+
},
609+
},
610+
},
611+
&ocv1.ClusterExtensionRevision{
612+
ObjectMeta: metav1.ObjectMeta{
613+
Name: "rev-4",
614+
Labels: map[string]string{
615+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
616+
},
617+
},
618+
},
619+
&ocv1.ClusterExtensionRevision{
620+
ObjectMeta: metav1.ObjectMeta{
621+
Name: "rev-5",
622+
Labels: map[string]string{
623+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
624+
},
625+
},
626+
},
627+
&ocv1.ClusterExtensionRevision{
628+
ObjectMeta: metav1.ObjectMeta{
629+
Name: "rev-6",
630+
Labels: map[string]string{
631+
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
632+
},
633+
},
634+
},
635+
},
636+
validate: func(t *testing.T, c client.Client) {
637+
rev1 := &ocv1.ClusterExtensionRevision{}
638+
err := c.Get(t.Context(), client.ObjectKey{Name: "rev-1"}, rev1)
639+
require.Error(t, err)
640+
assert.True(t, apierrors.IsNotFound(err))
641+
642+
latest := &ocv1.ClusterExtensionRevision{}
643+
err = c.Get(t.Context(), client.ObjectKey{Name: "test-ext-1"}, latest)
644+
require.NoError(t, err)
645+
assert.Len(t, latest.Spec.Previous, applier.ClusterExtensionRevisionPreviousLimit)
646+
},
647+
},
570648
}
571649

572650
for _, tc := range testCases {

0 commit comments

Comments
 (0)