From c88aa5414d9a7da46435c1bb323d8499d08d892d Mon Sep 17 00:00:00 2001 From: Camila Macedo <7708031+camilamacedo86@users.noreply.github.com> Date: Wed, 24 Dec 2025 17:04:55 +0000 Subject: [PATCH] (fix) Priority field to use pointer type with correct markers Change ClusterCatalog Priority field from int32 to *int32 to properly represent an optional field with a default value. - Update Priority to *int32 with json:"priority,omitempty" - Fix kubebuilder markers: Minimum/Maximum capitalization - Add Format:=int32 marker for OpenAPI schema - Add GetPriority() helper method for safe nil handling - Update resolver to use GetPriority() instead of direct access - Update tests to use ptr.To[int32]() for pointer values The kubebuilder default marker ensures the API server sets Priority to 0 when omitted, while the pointer type allows proper detection of user-specified vs defaulted values. Assisted-by: CLAUDE --- api/v1/clustercatalog_types.go | 7 ++++--- api/v1/zz_generated.deepcopy.go | 5 +++++ docs/api-reference/olmv1-api-reference.md | 2 +- .../olm.operatorframework.io_clustercatalogs.yaml | 2 ++ .../olm.operatorframework.io_clustercatalogs.yaml | 2 ++ internal/operator-controller/resolve/catalog.go | 6 +++++- .../operator-controller/resolve/catalog_test.go | 14 +++++++------- manifests/experimental-e2e.yaml | 2 ++ manifests/experimental.yaml | 2 ++ manifests/standard-e2e.yaml | 2 ++ manifests/standard.yaml | 2 ++ 11 files changed, 34 insertions(+), 12 deletions(-) diff --git a/api/v1/clustercatalog_types.go b/api/v1/clustercatalog_types.go index 8df90a806..0a6a7acad 100644 --- a/api/v1/clustercatalog_types.go +++ b/api/v1/clustercatalog_types.go @@ -125,10 +125,11 @@ type ClusterCatalogSpec struct { // The highest possible value is 2147483647. // // +kubebuilder:default:=0 - // +kubebuilder:validation:minimum:=-2147483648 - // +kubebuilder:validation:maximum:=2147483647 + // +kubebuilder:validation:Minimum:=-2147483648 + // +kubebuilder:validation:Maximum:=2147483647 + // +kubebuilder:validation:Format:=int32 // +optional - Priority int32 `json:"priority"` + Priority *int32 `json:"priority,omitempty"` // availabilityMode is an optional field that defines how the ClusterCatalog is made available to clients on the cluster. // diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 0c5c67c16..8650df83e 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -162,6 +162,11 @@ func (in *ClusterCatalogList) DeepCopyObject() runtime.Object { func (in *ClusterCatalogSpec) DeepCopyInto(out *ClusterCatalogSpec) { *out = *in in.Source.DeepCopyInto(&out.Source) + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(int32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterCatalogSpec. diff --git a/docs/api-reference/olmv1-api-reference.md b/docs/api-reference/olmv1-api-reference.md index 6aeb4c8f4..5c6ed95d7 100644 --- a/docs/api-reference/olmv1-api-reference.md +++ b/docs/api-reference/olmv1-api-reference.md @@ -178,7 +178,7 @@ _Appears in:_ | Field | Description | Default | Validation | | --- | --- | --- | --- | | `source` _[CatalogSource](#catalogsource)_ | source is a required field that defines the source of a catalog.
A catalog contains information on content that can be installed on a cluster.
The catalog source makes catalog contents discoverable and usable by other on-cluster components.
These components can present the content in a GUI dashboard or install content from the catalog on the cluster.
The catalog source must contain catalog metadata in the File-Based Catalog (FBC) format.
For more information on FBC, see https://olm.operatorframework.io/docs/reference/file-based-catalogs/#docs.
Below is a minimal example of a ClusterCatalogSpec that sources a catalog from an image:
source:
type: Image
image:
ref: quay.io/operatorhubio/catalog:latest | | Required: \{\}
| -| `priority` _integer_ | priority is an optional field that defines a priority for this ClusterCatalog.
Clients use the ClusterCatalog priority as a tie-breaker between ClusterCatalogs that meet their requirements.
Higher numbers mean higher priority.
Clients decide how to handle scenarios where multiple ClusterCatalogs with the same priority meet their requirements.
Clients should prompt users for additional input to break the tie.
When omitted, the default priority is 0.
Use negative numbers to specify a priority lower than the default.
Use positive numbers to specify a priority higher than the default.
The lowest possible value is -2147483648.
The highest possible value is 2147483647. | 0 | | +| `priority` _integer_ | priority is an optional field that defines a priority for this ClusterCatalog.
Clients use the ClusterCatalog priority as a tie-breaker between ClusterCatalogs that meet their requirements.
Higher numbers mean higher priority.
Clients decide how to handle scenarios where multiple ClusterCatalogs with the same priority meet their requirements.
Clients should prompt users for additional input to break the tie.
When omitted, the default priority is 0.
Use negative numbers to specify a priority lower than the default.
Use positive numbers to specify a priority higher than the default.
The lowest possible value is -2147483648.
The highest possible value is 2147483647. | 0 | Format: int32
Maximum: 2.147483647e+09
Minimum: -2.147483648e+09
| | `availabilityMode` _[AvailabilityMode](#availabilitymode)_ | availabilityMode is an optional field that defines how the ClusterCatalog is made available to clients on the cluster.
Allowed values are "Available", "Unavailable", or omitted.
When omitted, the default value is "Available".
When set to "Available", the catalog contents are unpacked and served over the catalog content HTTP server.
Clients should consider this ClusterCatalog and its contents as usable.
When set to "Unavailable", the catalog contents are no longer served over the catalog content HTTP server.
Treat this the same as if the ClusterCatalog does not exist.
Use "Unavailable" when you want to keep the ClusterCatalog but treat it as if it doesn't exist. | Available | Enum: [Unavailable Available]
| diff --git a/helm/olmv1/base/catalogd/crd/experimental/olm.operatorframework.io_clustercatalogs.yaml b/helm/olmv1/base/catalogd/crd/experimental/olm.operatorframework.io_clustercatalogs.yaml index 7508ab775..bc637024b 100644 --- a/helm/olmv1/base/catalogd/crd/experimental/olm.operatorframework.io_clustercatalogs.yaml +++ b/helm/olmv1/base/catalogd/crd/experimental/olm.operatorframework.io_clustercatalogs.yaml @@ -92,6 +92,8 @@ spec: The lowest possible value is -2147483648. The highest possible value is 2147483647. format: int32 + maximum: 2147483647 + minimum: -2147483648 type: integer source: description: |- diff --git a/helm/olmv1/base/catalogd/crd/standard/olm.operatorframework.io_clustercatalogs.yaml b/helm/olmv1/base/catalogd/crd/standard/olm.operatorframework.io_clustercatalogs.yaml index 0bbf9b988..db06adeeb 100644 --- a/helm/olmv1/base/catalogd/crd/standard/olm.operatorframework.io_clustercatalogs.yaml +++ b/helm/olmv1/base/catalogd/crd/standard/olm.operatorframework.io_clustercatalogs.yaml @@ -92,6 +92,8 @@ spec: The lowest possible value is -2147483648. The highest possible value is 2147483647. format: int32 + maximum: 2147483647 + minimum: -2147483648 type: integer source: description: |- diff --git a/internal/operator-controller/resolve/catalog.go b/internal/operator-controller/resolve/catalog.go index f0d4da6fa..112147c8a 100644 --- a/internal/operator-controller/resolve/catalog.go +++ b/internal/operator-controller/resolve/catalog.go @@ -160,7 +160,11 @@ func (r *CatalogResolver) Resolve(ctx context.Context, ext *ocv1.ClusterExtensio } // The current bundle shares deprecation status with prior bundles or // there are no prior bundles. Add it to the list. - resolvedBundles = append(resolvedBundles, foundBundle{&thisBundle, cat.GetName(), cat.Spec.Priority}) + priority := int32(0) + if cat.Spec.Priority != nil { + priority = *cat.Spec.Priority + } + resolvedBundles = append(resolvedBundles, foundBundle{&thisBundle, cat.GetName(), priority}) priorDeprecation = thisDeprecation return nil }, listOptions...); err != nil { diff --git a/internal/operator-controller/resolve/catalog_test.go b/internal/operator-controller/resolve/catalog_test.go index 2ec3192b6..4eebbc864 100644 --- a/internal/operator-controller/resolve/catalog_test.go +++ b/internal/operator-controller/resolve/catalog_test.go @@ -833,7 +833,7 @@ func TestUnequalPriority(t *testing.T) { genBundle(pkgName, "1.0.0"), }, Deprecations: []declcfg.Deprecation{}, - }, &ocv1.ClusterCatalogSpec{Priority: 1}, nil + }, &ocv1.ClusterCatalogSpec{Priority: ptr.To[int32](1)}, nil }, "b": func() (*declcfg.DeclarativeConfig, *ocv1.ClusterCatalogSpec, error) { return &declcfg.DeclarativeConfig{ @@ -847,7 +847,7 @@ func TestUnequalPriority(t *testing.T) { genBundle(pkgName, "1.1.0"), }, Deprecations: []declcfg.Deprecation{}, - }, &ocv1.ClusterCatalogSpec{Priority: 0}, nil + }, &ocv1.ClusterCatalogSpec{Priority: ptr.To[int32](0)}, nil }, } r := CatalogResolver{WalkCatalogsFunc: w.WalkCatalogs} @@ -862,13 +862,13 @@ func TestMultiplePriority(t *testing.T) { pkgName := randPkg() w := staticCatalogWalker{ "a": func() (*declcfg.DeclarativeConfig, *ocv1.ClusterCatalogSpec, error) { - return genPackage(pkgName), &ocv1.ClusterCatalogSpec{Priority: 1}, nil + return genPackage(pkgName), &ocv1.ClusterCatalogSpec{Priority: ptr.To[int32](1)}, nil }, "b": func() (*declcfg.DeclarativeConfig, *ocv1.ClusterCatalogSpec, error) { - return genPackage(pkgName), &ocv1.ClusterCatalogSpec{Priority: 0}, nil + return genPackage(pkgName), &ocv1.ClusterCatalogSpec{Priority: ptr.To[int32](0)}, nil }, "c": func() (*declcfg.DeclarativeConfig, *ocv1.ClusterCatalogSpec, error) { - return genPackage(pkgName), &ocv1.ClusterCatalogSpec{Priority: 1}, nil + return genPackage(pkgName), &ocv1.ClusterCatalogSpec{Priority: ptr.To[int32](1)}, nil }, } r := CatalogResolver{WalkCatalogsFunc: w.WalkCatalogs} @@ -944,7 +944,7 @@ func TestSomeCatalogsDisabled(t *testing.T) { Name: "enabledCatalog", }, Spec: ocv1.ClusterCatalogSpec{ - Priority: 1, // Higher priority + Priority: ptr.To[int32](1), // Higher priority AvailabilityMode: ocv1.AvailabilityModeAvailable, }, }, @@ -953,7 +953,7 @@ func TestSomeCatalogsDisabled(t *testing.T) { Name: "disabledCatalog", }, Spec: ocv1.ClusterCatalogSpec{ - Priority: 0, // Lower priority (but disabled) + Priority: ptr.To[int32](0), // Lower priority (but disabled) AvailabilityMode: ocv1.AvailabilityModeUnavailable, }, }, diff --git a/manifests/experimental-e2e.yaml b/manifests/experimental-e2e.yaml index fbc5b4a53..e0b26a7d0 100644 --- a/manifests/experimental-e2e.yaml +++ b/manifests/experimental-e2e.yaml @@ -278,6 +278,8 @@ spec: The lowest possible value is -2147483648. The highest possible value is 2147483647. format: int32 + maximum: 2147483647 + minimum: -2147483648 type: integer source: description: |- diff --git a/manifests/experimental.yaml b/manifests/experimental.yaml index 22c7db269..8bbb22716 100644 --- a/manifests/experimental.yaml +++ b/manifests/experimental.yaml @@ -239,6 +239,8 @@ spec: The lowest possible value is -2147483648. The highest possible value is 2147483647. format: int32 + maximum: 2147483647 + minimum: -2147483648 type: integer source: description: |- diff --git a/manifests/standard-e2e.yaml b/manifests/standard-e2e.yaml index 9b8b95c9d..b518a6064 100644 --- a/manifests/standard-e2e.yaml +++ b/manifests/standard-e2e.yaml @@ -278,6 +278,8 @@ spec: The lowest possible value is -2147483648. The highest possible value is 2147483647. format: int32 + maximum: 2147483647 + minimum: -2147483648 type: integer source: description: |- diff --git a/manifests/standard.yaml b/manifests/standard.yaml index b5166be98..4a52fce58 100644 --- a/manifests/standard.yaml +++ b/manifests/standard.yaml @@ -239,6 +239,8 @@ spec: The lowest possible value is -2147483648. The highest possible value is 2147483647. format: int32 + maximum: 2147483647 + minimum: -2147483648 type: integer source: description: |-