Skip to content

🐛 Fix: Use labels for queryable bundle metadata and unify owner labels#2345

Closed
camilamacedo86 wants to merge 1 commit into
operator-framework:mainfrom
camilamacedo86:fix-labels
Closed

🐛 Fix: Use labels for queryable bundle metadata and unify owner labels#2345
camilamacedo86 wants to merge 1 commit into
operator-framework:mainfrom
camilamacedo86:fix-labels

Conversation

@camilamacedo86
Copy link
Copy Markdown
Contributor

Problem

Bundle metadata (package-name, bundle-name, bundle-version) was stored in annotations on ClusterExtensionRevision, making it impossible to query or filter revisions by package, bundle, or version. Additionally, owner labels were inconsistent across different object types.

Solution

  1. Move bundle metadata to labels - Enables kubectl queries and follows Kubernetes best practices
  2. Unify owner labels - Use owner-name + owner-kind consistently on all objects
  3. Fix naming - Rename misleading storeLbls variable to revisionLabels + revisionAnnotations

Changes

BEFORE

ClusterExtensionRevision Resource

apiVersion: olm.operatorframework.io/v1
kind: ClusterExtensionRevision
metadata:
  name: prometheus-operator-1
  labels:
    # ❌ Only owner label (inconsistent pattern)
    olm.operatorframework.io/owner: prometheus-operator
  annotations:
    # ❌ Bundle metadata in annotations (NOT queryable)
    olm.operatorframework.io/package-name: prometheus-operator
    olm.operatorframework.io/bundle-name: prometheus-operator.v0.56.0
    olm.operatorframework.io/bundle-version: 0.56.0
    olm.operatorframework.io/bundle-reference: quay.io/prometheus-operator/prometheus-operator@sha256:abc123...
spec:
  revision: 1
  lifecycleState: Active
  phases:
    - name: deploy
      objects:
        - object:
            apiVersion: apps/v1
            kind: Deployment
            metadata:
              name: prometheus-operator
              labels:
                # ✅ Managed objects use owner-kind + owner-name (different pattern)
                olm.operatorframework.io/owner-kind: ClusterExtension
                olm.operatorframework.io/owner-name: prometheus-operator

kubectl Queries (Didn't Work)

# ❌ FAILED - package-name is an annotation
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/package-name=prometheus-operator
No resources found

# ❌ FAILED - bundle-version is an annotation  
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/bundle-version=0.56.0
No resources found

# ✅ Only owner filtering worked
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/owner=prometheus-operator
NAME                       AGE
prometheus-operator-1      5m

AFTER

ClusterExtensionRevision Resource

apiVersion: olm.operatorframework.io/v1
kind: ClusterExtensionRevision
metadata:
  name: prometheus-operator-1
  labels:
    # ✅ Owner labels (NOW CONSISTENT with managed objects)
    olm.operatorframework.io/owner-kind: ClusterExtension
    olm.operatorframework.io/owner-name: prometheus-operator
    # ✅ Bundle metadata in labels (QUERYABLE!)
    olm.operatorframework.io/package-name: prometheus-operator
    olm.operatorframework.io/bundle-name: prometheus-operator.v0.56.0
    olm.operatorframework.io/bundle-version: 0.56.0
  annotations:
    # ✅ Only bundle-reference in annotations (can exceed 63 chars)
    olm.operatorframework.io/bundle-reference: quay.io/prometheus-operator/prometheus-operator@sha256:abc123...
spec:
  revision: 1
  lifecycleState: Active
  phases:
    - name: deploy
      objects:
        - object:
            apiVersion: apps/v1
            kind: Deployment
            metadata:
              name: prometheus-operator
              labels:
                # ✅ Same pattern as ClusterExtensionRevision (consistent!)
                olm.operatorframework.io/owner-kind: ClusterExtension
                olm.operatorframework.io/owner-name: prometheus-operator

kubectl Queries (Now Work!)

# ✅ SUCCESS - Filter by package
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/package-name=prometheus-operator
NAME                       AGE
prometheus-operator-1      5m
prometheus-operator-2      3m
other-prometheus-1         2m

# ✅ SUCCESS - Filter by version
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/bundle-version=0.56.0
NAME                       AGE
prometheus-operator-1      5m
prometheus-operator-2      3m

# ✅ SUCCESS - Filter by bundle name
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/bundle-name=prometheus-operator.v0.56.0
NAME                       AGE
prometheus-operator-1      5m

# ✅ SUCCESS - Combine filters (AND logic)
$ kubectl get clusterextensionrevisions \
  -l olm.operatorframework.io/package-name=prometheus-operator,olm.operatorframework.io/bundle-version=0.56.0
NAME                       AGE
prometheus-operator-1      5m
prometheus-operator-2      3m

# ✅ SUCCESS - Updated owner query (now uses owner-name)
$ kubectl get clusterextensionrevisions -l olm.operatorframework.io/owner-name=prometheus-operator
NAME                       AGE
prometheus-operator-1      5m
prometheus-operator-2      3m

Code Changes

BEFORE (Confusing and Wrong)

// ❌ Misleadingly named - actually contains annotations!
storeLbls := map[string]string{
    labels.BundleNameKey:      resolvedRevisionMetadata.Name,
    labels.PackageNameKey:     resolvedRevisionMetadata.Package,
    labels.BundleVersionKey:   resolvedRevisionMetadata.Version,
    labels.BundleReferenceKey: resolvedRevisionMetadata.Image,
}

// ❌ Applied as annotations (not labels!)
rolloutSucceeded, rolloutStatus, err := r.Applier.Apply(ctx, imageFS, ext, objLbls, storeLbls)

AFTER (Clear and Correct)

// ✅ Clear split: labels for queryable data
revisionLabels := map[string]string{
    labels.BundleNameKey:    resolvedRevisionMetadata.Name,
    labels.PackageNameKey:   resolvedRevisionMetadata.Package,
    labels.BundleVersionKey: resolvedRevisionMetadata.Version,
}

// ✅ Annotations for reference data (can exceed 63 chars)
revisionAnnotations := map[string]string{
    labels.BundleReferenceKey: resolvedRevisionMetadata.Image,
}

// ✅ Clear what goes where
rolloutSucceeded, rolloutStatus, err := r.Applier.Apply(ctx, imageFS, ext, objLbls, revisionLabels, revisionAnnotations)

Rationale

Following Kubernetes best practices:

Labels (for selection/filtering)

  • Indexed by Kubernetes for efficient queries
  • ✅ Used in label selectors (kubectl get -l)
  • ✅ Enable cache filtering and controller logic
  • ⚠️ Limited to 63 characters

Annotations (for reference data)

  • ✅ Can be large (up to 256KB total)
  • ✅ For non-queryable metadata
  • ❌ Not indexed or selectable

Decision:

  • package-name, bundle-name, bundle-versionLabels (short, queryable)
  • bundle-referenceAnnotation (can be >63 chars: quay.io/org/image@sha256:...)

References

Fix bundle metadata storage to use labels instead of annotations,
following Kubernetes best practices for queryable metadata. This
enables kubectl queries like:
  kubectl get clusterextensionrevisions -l package-name=prometheus

Also fixes inconsistent owner labels - now uses owner-name + owner-kind
everywhere (previously ClusterExtensionRevision used just owner).

Fixed issues:
- Bundle metadata was in annotations (not queryable/indexed)
- Owner labels were inconsistent across object types
- Variable storeLbls was misleadingly named (actually annotations)

Boxcutter runtime only - Helm unchanged except interface signature.

Refs: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels

Assisted-by: Cursor
@camilamacedo86 camilamacedo86 requested a review from a team as a code owner November 18, 2025 18:49
Copilot AI review requested due to automatic review settings November 18, 2025 19:05
@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented Nov 18, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign thetechnick for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@netlify
Copy link
Copy Markdown

netlify Bot commented Nov 18, 2025

Deploy Preview for olmv1 ready!

Name Link
🔨 Latest commit 5fafe40
🔍 Latest deploy log https://app.netlify.com/projects/olmv1/deploys/691cc384bf94b8000812cf46
😎 Deploy Preview https://deploy-preview-2345--olmv1.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR improves ClusterExtensionRevision observability by moving bundle metadata (package-name, bundle-name, bundle-version) from annotations to labels, enabling kubectl queries and filtering. It also unifies owner label patterns across all resources by using both owner-kind and owner-name labels consistently, and improves code clarity by renaming variables to better reflect their purpose.

  • Bundle metadata moved to labels for queryability via kubectl get -l
  • Owner labels unified to use owner-kind + owner-name pattern on ClusterExtensionRevision objects
  • Variable names improved (storeLblsrevisionLabels/revisionAnnotations) for clarity

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
internal/operator-controller/controllers/clusterextensionrevision_controller.go Updated owner label constant from owner to owner-name
internal/operator-controller/controllers/clusterextension_controller.go Split bundle metadata into labels (queryable) and annotations (reference); updated interface documentation
internal/operator-controller/applier/boxcutter.go Updated revision generation to use labels for bundle metadata and added owner-kind/owner-name labels consistently
internal/operator-controller/applier/boxcutter_test.go Updated all tests to expect bundle metadata in labels instead of annotations, and verify new owner label patterns
internal/operator-controller/applier/helm.go Added new parameter for revision annotations (ignored by Helm applier)
internal/operator-controller/applier/helm_test.go Updated all test calls to include new revision annotations parameter
internal/operator-controller/controllers/suite_test.go Updated MockApplier signature to match new interface with three map parameters

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +85 to +86
// It takes objectLabels to be applied to all managed resources, revisionLabels to be applied to the
// ClusterExtensionRevision for selection/querying, and revisionAnnotations for non-queryable metadata.
Copy link

Copilot AI Nov 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface documentation is specific to the Boxcutter implementation (mentioning "ClusterExtensionRevision") but this interface is also implemented by the Helm applier which doesn't use ClusterExtensionRevision.

Consider making the documentation more generic to cover both implementations:

// It takes objectLabels to be applied to all managed resources, revisionLabels for queryable 
// bundle metadata (stored on ClusterExtensionRevision for Boxcutter or Helm release for Helm),
// and revisionAnnotations for non-queryable metadata (ignored by Helm applier).
Suggested change
// It takes objectLabels to be applied to all managed resources, revisionLabels to be applied to the
// ClusterExtensionRevision for selection/querying, and revisionAnnotations for non-queryable metadata.
// It takes objectLabels to be applied to all managed resources, revisionLabels for queryable
// bundle metadata (stored on a resource such as ClusterExtensionRevision for Boxcutter or Helm release for Helm),
// and revisionAnnotations for non-queryable metadata (which may be ignored by some implementations).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants