Skip to content

Commit 9032b04

Browse files
committed
add BoxcutterInstalledBundleGetter, plumb bundle metadata into revision annotations
Signed-off-by: Joe Lanford <[email protected]>
1 parent 7ba6e02 commit 9032b04

File tree

4 files changed

+68
-13
lines changed

4 files changed

+68
-13
lines changed

cmd/operator-controller/main.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -441,8 +441,11 @@ func run() error {
441441
}
442442

443443
// create applier
444-
var ctrlBuilderOpts []controllers.ControllerBuilderOption
445-
var extApplier controllers.Applier
444+
var (
445+
ctrlBuilderOpts []controllers.ControllerBuilderOption
446+
extApplier controllers.Applier
447+
installedBundleGetter controllers.InstalledBundleGetter
448+
)
446449
certProvider := getCertificateProvider()
447450
if features.OperatorControllerFeatureGate.Enabled(features.BoxcutterRuntime) {
448451
// TODO: add support for preflight checks
@@ -460,6 +463,7 @@ func run() error {
460463
},
461464
Preflights: preflights,
462465
}
466+
installedBundleGetter = &controllers.BoxcutterInstalledBundleGetter{Reader: mgr.GetClient()}
463467
ctrlBuilderOpts = append(ctrlBuilderOpts, controllers.WithOwns(&ocv1.ClusterExtensionRevision{}))
464468
} else {
465469
// now initialize the helmApplier, assigning the potentially nil preAuth
@@ -474,6 +478,7 @@ func run() error {
474478
PreAuthorizer: preAuth,
475479
HelmReleaseToObjectsConverter: &applier.HelmReleaseToObjectsConverter{},
476480
}
481+
installedBundleGetter = &controllers.HelmInstalledBundleGetter{ActionClientGetter: acg}
477482
}
478483

479484
cm := contentmanager.NewManager(clientRestConfigMapper, mgr.GetConfig(), mgr.GetRESTMapper())
@@ -493,7 +498,7 @@ func run() error {
493498
ImageCache: imageCache,
494499
ImagePuller: imagePuller,
495500
Applier: extApplier,
496-
InstalledBundleGetter: &controllers.DefaultInstalledBundleGetter{ActionClientGetter: acg},
501+
InstalledBundleGetter: installedBundleGetter,
497502
Finalizers: clusterExtensionFinalizers,
498503
Manager: cm,
499504
}).SetupWithManager(mgr, ctrlBuilderOpts...); err != nil {

internal/operator-controller/applier/boxcutter.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ const (
3030
)
3131

3232
type ClusterExtensionRevisionGenerator interface {
33-
GenerateRevision(bundleFS fs.FS, ext *ocv1.ClusterExtension, objectLabels map[string]string) (*ocv1.ClusterExtensionRevision, error)
33+
GenerateRevision(bundleFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, revisionAnnotations map[string]string) (*ocv1.ClusterExtensionRevision, error)
3434
}
3535

3636
type SimpleRevisionGenerator struct {
3737
Scheme *runtime.Scheme
3838
BundleRenderer BundleRenderer
3939
}
4040

41-
func (r *SimpleRevisionGenerator) GenerateRevision(bundleFS fs.FS, ext *ocv1.ClusterExtension, objectLabels map[string]string) (*ocv1.ClusterExtensionRevision, error) {
41+
func (r *SimpleRevisionGenerator) GenerateRevision(bundleFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, revisionAnnotations map[string]string) (*ocv1.ClusterExtensionRevision, error) {
4242
// extract plain manifests
4343
plain, err := r.BundleRenderer.Render(bundleFS, ext)
4444
if err != nil {
@@ -74,10 +74,14 @@ func (r *SimpleRevisionGenerator) GenerateRevision(bundleFS fs.FS, ext *ocv1.Clu
7474
})
7575
}
7676

77+
if revisionAnnotations == nil {
78+
revisionAnnotations = map[string]string{}
79+
}
80+
7781
// Build desired revision
7882
return &ocv1.ClusterExtensionRevision{
7983
ObjectMeta: metav1.ObjectMeta{
80-
Annotations: map[string]string{},
84+
Annotations: revisionAnnotations,
8185
Labels: map[string]string{
8286
controllers.ClusterExtensionRevisionOwnerLabel: ext.Name,
8387
},
@@ -100,8 +104,8 @@ type Boxcutter struct {
100104
Preflights []Preflight
101105
}
102106

103-
func (bc *Boxcutter) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, storageLabels map[string]string) ([]client.Object, string, error) {
104-
objs, err := bc.apply(ctx, contentFS, ext, objectLabels, storageLabels)
107+
func (bc *Boxcutter) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, revisionAnnotations map[string]string) ([]client.Object, string, error) {
108+
objs, err := bc.apply(ctx, contentFS, ext, objectLabels, revisionAnnotations)
105109
return objs, "", err
106110
}
107111

@@ -115,9 +119,9 @@ func (bc *Boxcutter) getObjects(rev *ocv1.ClusterExtensionRevision) []client.Obj
115119
return objs
116120
}
117121

118-
func (bc *Boxcutter) apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, _ map[string]string) ([]client.Object, error) {
122+
func (bc *Boxcutter) apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExtension, objectLabels, revisionAnnotations map[string]string) ([]client.Object, error) {
119123
// Generate desired revision
120-
desiredRevision, err := bc.RevisionGenerator.GenerateRevision(contentFS, ext, objectLabels)
124+
desiredRevision, err := bc.RevisionGenerator.GenerateRevision(contentFS, ext, objectLabels, revisionAnnotations)
121125
if err != nil {
122126
return nil, err
123127
}

internal/operator-controller/controllers/clusterextension_controller.go

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ limitations under the License.
1717
package controllers
1818

1919
import (
20+
"cmp"
2021
"context"
2122
"errors"
2223
"fmt"
2324
"io/fs"
25+
"slices"
2426
"strings"
2527
"time"
2628

@@ -488,7 +490,7 @@ func clusterExtensionRequestsForCatalog(c client.Reader, logger logr.Logger) crh
488490
}
489491
}
490492

491-
type DefaultInstalledBundleGetter struct {
493+
type HelmInstalledBundleGetter struct {
492494
helmclient.ActionClientGetter
493495
}
494496

@@ -497,7 +499,7 @@ type InstalledBundle struct {
497499
Image string
498500
}
499501

500-
func (d *DefaultInstalledBundleGetter) GetInstalledBundle(ctx context.Context, ext *ocv1.ClusterExtension) (*InstalledBundle, error) {
502+
func (d *HelmInstalledBundleGetter) GetInstalledBundle(ctx context.Context, ext *ocv1.ClusterExtension) (*InstalledBundle, error) {
501503
cl, err := d.ActionClientFor(ctx, ext)
502504
if err != nil {
503505
return nil, err
@@ -526,3 +528,47 @@ func (d *DefaultInstalledBundleGetter) GetInstalledBundle(ctx context.Context, e
526528
}
527529
return nil, nil
528530
}
531+
532+
type BoxcutterInstalledBundleGetter struct {
533+
client.Reader
534+
}
535+
536+
func (d *BoxcutterInstalledBundleGetter) GetInstalledBundle(ctx context.Context, ext *ocv1.ClusterExtension) (*InstalledBundle, error) {
537+
// TODO: boxcutter applier has a nearly identical bit of code for listing and sorting revisions
538+
// only difference here is that it sorts in reverse order to start iterating with the most
539+
// recent revisions. We should consolidate to avoid code duplication.
540+
existingRevisionList := &ocv1.ClusterExtensionRevisionList{}
541+
if err := d.Reader.List(ctx, existingRevisionList, client.MatchingLabels{
542+
ClusterExtensionRevisionOwnerLabel: ext.Name,
543+
}); err != nil {
544+
return nil, fmt.Errorf("listing revisions: %w", err)
545+
}
546+
slices.SortFunc(existingRevisionList.Items, func(a, b ocv1.ClusterExtensionRevision) int {
547+
return cmp.Compare(b.Spec.Revision, a.Spec.Revision)
548+
})
549+
550+
for _, rev := range existingRevisionList.Items {
551+
if rev.Spec.LifecycleState == ocv1.ClusterExtensionRevisionLifecycleStateActive {
552+
// TODO: we should make constants for the ClusterExtensionRevision condition types.
553+
if installedCondition := apimeta.FindStatusCondition(rev.Status.Conditions, "Succeeded"); installedCondition == nil || installedCondition.Status != metav1.ConditionTrue {
554+
// TODO: It's not great to return this error in a completely normal situation. This currently cascades
555+
// into Installed=False, Failed and Progressing=True, Retrying conditions that give the impression
556+
// that something is wrong. We should probably refactor the InstalledBundleGetter interface to better
557+
// handle the async nature of ClusterExtensionRevision rollouts.
558+
return nil, fmt.Errorf("most recent active revision %s is still rolling out", rev.Name)
559+
}
560+
561+
// TODO: the setting of these annotations (happens in boxcutter applier when we pass in "storageLabels")
562+
// is fairly decoupled from this code where we get the annotations back out. We may want to co-locate
563+
// the set/get logic a bit better to make it more maintainable and less likely to get out of sync.
564+
return &InstalledBundle{
565+
BundleMetadata: ocv1.BundleMetadata{
566+
Name: rev.Annotations[labels.BundleNameKey],
567+
Version: rev.Annotations[labels.BundleVersionKey],
568+
},
569+
Image: rev.Annotations[labels.BundleReferenceKey],
570+
}, nil
571+
}
572+
}
573+
return nil, nil
574+
}

internal/operator-controller/controllers/clusterextension_controller_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,7 @@ func (mag *MockActionGetter) Reconcile(rel *release.Release) error {
14851485
}
14861486

14871487
func TestGetInstalledBundleHistory(t *testing.T) {
1488-
getter := controllers.DefaultInstalledBundleGetter{}
1488+
getter := controllers.HelmInstalledBundleGetter{}
14891489

14901490
ext := ocv1.ClusterExtension{
14911491
ObjectMeta: metav1.ObjectMeta{

0 commit comments

Comments
 (0)