diff --git a/internal/operator-controller/applier/boxcutter.go b/internal/operator-controller/applier/boxcutter.go index 794aad20e..8c9d547ef 100644 --- a/internal/operator-controller/applier/boxcutter.go +++ b/internal/operator-controller/applier/boxcutter.go @@ -67,12 +67,7 @@ func (r *SimpleRevisionGenerator) GenerateRevisionFromHelmRelease( if err := yaml.Unmarshal([]byte(doc), &obj); err != nil { return nil, err } - - existingLabels := obj.GetLabels() - labels := make(map[string]string, len(existingLabels)+len(objectLabels)) - maps.Copy(labels, existingLabels) - maps.Copy(labels, objectLabels) - obj.SetLabels(labels) + obj.SetLabels(mergeLabelMaps(obj.GetLabels(), objectLabels)) // Memory optimization: strip large annotations // Note: ApplyStripTransform never returns an error in practice @@ -131,11 +126,7 @@ func (r *SimpleRevisionGenerator) GenerateRevision( // objectLabels objs := make([]ocv1.ClusterExtensionRevisionObject, 0, len(plain)) for _, obj := range plain { - existingLabels := obj.GetLabels() - labels := make(map[string]string, len(existingLabels)+len(objectLabels)) - maps.Copy(labels, existingLabels) - maps.Copy(labels, objectLabels) - obj.SetLabels(labels) + obj.SetLabels(mergeLabelMaps(obj.GetLabels(), objectLabels)) gvk, err := apiutil.GVKForObject(obj, r.Scheme) if err != nil { @@ -219,6 +210,7 @@ func (r *SimpleRevisionGenerator) buildClusterExtensionRevision( ObjectMeta: metav1.ObjectMeta{ Annotations: annotations, Labels: map[string]string{ + labels.OwnerKindKey: ocv1.ClusterExtensionKind, labels.OwnerNameKey: ext.Name, }, }, @@ -666,3 +658,10 @@ func revisionManagementPerms(rev *ocv1.ClusterExtensionRevision) func(user.Info) } } } + +func mergeLabelMaps(m1, m2 map[string]string) map[string]string { + mergedLabels := make(map[string]string, len(m1)+len(m2)) + maps.Copy(mergedLabels, m1) + maps.Copy(mergedLabels, m2) + return mergedLabels +} diff --git a/internal/operator-controller/applier/boxcutter_test.go b/internal/operator-controller/applier/boxcutter_test.go index ad952e29a..f7c1298ce 100644 --- a/internal/operator-controller/applier/boxcutter_test.go +++ b/internal/operator-controller/applier/boxcutter_test.go @@ -109,6 +109,7 @@ func Test_SimpleRevisionGenerator_GenerateRevisionFromHelmRelease(t *testing.T) "olm.operatorframework.io/service-account-namespace": "test-namespace", }, Labels: map[string]string{ + labels.OwnerKindKey: ocv1.ClusterExtensionKind, labels.OwnerNameKey: "test-123", }, }, @@ -207,8 +208,9 @@ func Test_SimpleRevisionGenerator_GenerateRevision(t *testing.T) { rev, err := b.GenerateRevision(t.Context(), dummyBundle, ext, map[string]string{}, map[string]string{}) require.NoError(t, err) - t.Log("by checking the olm.operatorframework.io/owner-name label is set to the name of the ClusterExtension") + t.Log("by checking the olm.operatorframework.io/owner-name and owner-kind labels are set") require.Equal(t, map[string]string{ + labels.OwnerKindKey: ocv1.ClusterExtensionKind, labels.OwnerNameKey: "test-extension", }, rev.Labels) t.Log("by checking the revision number is 0") diff --git a/test/e2e/features/install.feature b/test/e2e/features/install.feature index c16af88ef..23f75c546 100644 --- a/test/e2e/features/install.feature +++ b/test/e2e/features/install.feature @@ -417,3 +417,29 @@ Feature: Install ClusterExtension """ [{"type":"olm.test-property","value":"some-value"}] """ + + @BoxcutterRuntime + Scenario: ClusterExtensionRevision is labeled with owner information + When ClusterExtension is applied + """ + apiVersion: olm.operatorframework.io/v1 + kind: ClusterExtension + metadata: + name: ${NAME} + spec: + namespace: ${TEST_NAMESPACE} + serviceAccount: + name: olm-sa + source: + sourceType: Catalog + catalog: + packageName: test + version: 1.2.0 + selector: + matchLabels: + "olm.operatorframework.io/metadata.name": test-catalog + """ + Then ClusterExtension is rolled out + And ClusterExtension is available + And ClusterExtensionRevision "${NAME}-1" has label "olm.operatorframework.io/owner-kind" with value "ClusterExtension" + And ClusterExtensionRevision "${NAME}-1" has label "olm.operatorframework.io/owner-name" with value "${NAME}" diff --git a/test/e2e/steps/steps.go b/test/e2e/steps/steps.go index d6ba67ccf..483514e40 100644 --- a/test/e2e/steps/steps.go +++ b/test/e2e/steps/steps.go @@ -74,6 +74,7 @@ func RegisterSteps(sc *godog.ScenarioContext) { sc.Step(`^(?i)ClusterExtension reports ([[:alnum:]]+) transition between (\d+) and (\d+) minutes since its creation$`, ClusterExtensionReportsConditionTransitionTime) sc.Step(`^(?i)ClusterExtensionRevision "([^"]+)" is archived$`, ClusterExtensionRevisionIsArchived) sc.Step(`^(?i)ClusterExtensionRevision "([^"]+)" contains annotation "([^"]+)" with value$`, ClusterExtensionRevisionHasAnnotationWithValue) + sc.Step(`^(?i)ClusterExtensionRevision "([^"]+)" has label "([^"]+)" with value "([^"]+)"$`, ClusterExtensionRevisionHasLabelWithValue) sc.Step(`^(?i)resource "([^"]+)" is installed$`, ResourceAvailable) sc.Step(`^(?i)resource "([^"]+)" is available$`, ResourceAvailable) @@ -507,6 +508,24 @@ func ClusterExtensionRevisionHasAnnotationWithValue(ctx context.Context, revisio return nil } +func ClusterExtensionRevisionHasLabelWithValue(ctx context.Context, revisionName, labelKey, labelValue string) error { + sc := scenarioCtx(ctx) + revisionName = substituteScenarioVars(strings.TrimSpace(revisionName), sc) + labelValue = substituteScenarioVars(labelValue, sc) + waitFor(ctx, func() bool { + obj, err := getResource("clusterextensionrevision", revisionName, "") + if err != nil { + logger.V(1).Error(err, "failed to get clusterextensionrevision", "name", revisionName) + return false + } + if obj.GetLabels() == nil { + return false + } + return obj.GetLabels()[labelKey] == labelValue + }) + return nil +} + func ResourceAvailable(ctx context.Context, resource string) error { sc := scenarioCtx(ctx) resource = substituteScenarioVars(resource, sc)