From e12836d70833835db04aa83cf2b509c3ee276f7f Mon Sep 17 00:00:00 2001 From: Leela Venkaiah G Date: Tue, 19 Dec 2023 15:31:37 +0530 Subject: [PATCH 1/3] godeps: go mod tidy and vendor Signed-off-by: Leela Venkaiah G --- go.mod | 3 +- go.sum | 6 +- .../api/pkg/operators/v1/olmconfig_types.go | 19 ++ .../pkg/operators/v1/zz_generated.deepcopy.go | 5 + .../operators/v1alpha1/catalogsource_types.go | 30 +++ .../v1alpha1/clusterserviceversion.go | 15 +- .../operators/v1alpha1/subscription_types.go | 13 ++ .../v1alpha1/zz_generated.deepcopy.go | 25 +++ .../api/pkg/operators/v2/doc.go | 4 + .../api/pkg/operators/v2/groupversion_info.go | 28 +++ .../operators/v2/operatorcondition_types.go | 54 +++++ .../pkg/operators/v2/zz_generated.deepcopy.go | 146 +++++++++++++ .../operator-framework/operator-lib/LICENSE | 201 ++++++++++++++++++ .../operator-lib/conditions/conditions.go | 76 +++++++ .../operator-lib/conditions/factory.go | 119 +++++++++++ .../operator-lib/conditions/interface.go | 60 ++++++ .../operator-lib/internal/utils/utils.go | 43 ++++ vendor/modules.txt | 7 +- 18 files changed, 846 insertions(+), 8 deletions(-) create mode 100644 vendor/github.com/operator-framework/api/pkg/operators/v2/doc.go create mode 100644 vendor/github.com/operator-framework/api/pkg/operators/v2/groupversion_info.go create mode 100644 vendor/github.com/operator-framework/api/pkg/operators/v2/operatorcondition_types.go create mode 100644 vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go create mode 100644 vendor/github.com/operator-framework/operator-lib/LICENSE create mode 100644 vendor/github.com/operator-framework/operator-lib/conditions/conditions.go create mode 100644 vendor/github.com/operator-framework/operator-lib/conditions/factory.go create mode 100644 vendor/github.com/operator-framework/operator-lib/conditions/interface.go create mode 100644 vendor/github.com/operator-framework/operator-lib/internal/utils/utils.go diff --git a/go.mod b/go.mod index 5da25e8c4..f50b01f4d 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/onsi/gomega v1.27.10 github.com/openshift/api v0.0.0-20231212225112-7cca8a108d7b github.com/openshift/custom-resource-status v1.1.2 - github.com/operator-framework/api v0.17.7-0.20230626210316-aa3e49803e7b + github.com/operator-framework/api v0.20.0 github.com/prometheus/client_golang v1.17.0 github.com/red-hat-storage/ocs-operator/api/v4 v4.0.0-20231218123823-334ed88d3c2c github.com/stretchr/testify v1.8.4 @@ -73,6 +73,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/noobaa/noobaa-operator/v5 v5.0.0-20231213124549-5d7b0417716d // indirect + github.com/operator-framework/operator-lib v0.11.1-0.20230717184314-6efbe3a22f6f github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_model v0.5.0 // indirect diff --git a/go.sum b/go.sum index 09ea29086..ac0be1a8a 100644 --- a/go.sum +++ b/go.sum @@ -647,8 +647,10 @@ github.com/openshift/build-machinery-go v0.0.0-20200917070002-f171684f77ab/go.mo github.com/openshift/client-go v0.0.0-20210112165513-ebc401615f47/go.mod h1:u7NRAjtYVAKokiI9LouzTv4mhds8P4S1TwdVAfbjKSk= github.com/openshift/custom-resource-status v1.1.2 h1:C3DL44LEbvlbItfd8mT5jWrqPfHnSOQoQf/sypqA6A4= github.com/openshift/custom-resource-status v1.1.2/go.mod h1:DB/Mf2oTeiAmVVX1gN+NEqweonAPY0TKUwADizj8+ZA= -github.com/operator-framework/api v0.17.7-0.20230626210316-aa3e49803e7b h1:prJEMyFQde4yxxaTuvqx1A/ukuCg/EZ2MbfdZiJwlls= -github.com/operator-framework/api v0.17.7-0.20230626210316-aa3e49803e7b/go.mod h1:lnurXgadLnoZ7pufKMHkErr2BVOIZSpHtvEkHBcKvdk= +github.com/operator-framework/api v0.20.0 h1:A2YCRhr+6s0k3pRJacnwjh1Ue8BqjIGuQ2jvPg9XCB4= +github.com/operator-framework/api v0.20.0/go.mod h1:rXPOhrQ6mMeXqCmpDgt1ALoar9ZlHL+Iy5qut9R99a4= +github.com/operator-framework/operator-lib v0.11.1-0.20230717184314-6efbe3a22f6f h1:CQkdjRsbPtDd3YvENaPMZzw1eHPfujiZTrCzzSCPCsw= +github.com/operator-framework/operator-lib v0.11.1-0.20230717184314-6efbe3a22f6f/go.mod h1:fmVTfDgR/OMPg7eJvXWlyBVzCXUfHAOxIXO8W51HvKY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v0.0.0-20170612153648-e790cca94e6c/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1/olmconfig_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v1/olmconfig_types.go index f1135e6a3..c15b5114f 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1/olmconfig_types.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1/olmconfig_types.go @@ -1,6 +1,8 @@ package v1 import ( + "time" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -23,6 +25,16 @@ type Features struct { // When reenabled, OLM will recreate the "Copied CSVs" for each // cluster scoped operator. DisableCopiedCSVs *bool `json:"disableCopiedCSVs,omitempty"` + // PackageServerSyncInterval is used to define the sync interval for + // packagerserver pods. Packageserver pods periodically check the + // status of CatalogSources; this specifies the period using duration + // format (e.g. "60m"). For this parameter, only hours ("h"), minutes + // ("m"), and seconds ("s") may be specified. When not specified, the + // period defaults to the value specified within the packageserver. + // +optional + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(s|m|h))+$" + PackageServerSyncInterval *metav1.Duration `json:"packageServerSyncInterval,omitempty"` } // OLMConfigStatus is the status for an OLMConfig resource. @@ -69,3 +81,10 @@ func (config *OLMConfig) CopiedCSVsAreEnabled() bool { return !*config.Spec.Features.DisableCopiedCSVs } + +func (config *OLMConfig) PackageServerSyncInterval() *time.Duration { + if config == nil || config.Spec.Features == nil || config.Spec.Features.PackageServerSyncInterval == nil { + return nil + } + return &config.Spec.Features.PackageServerSyncInterval.Duration +} diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go index 89a3007bc..33ea16229 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1/zz_generated.deepcopy.go @@ -84,6 +84,11 @@ func (in *Features) DeepCopyInto(out *Features) { *out = new(bool) **out = **in } + if in.PackageServerSyncInterval != nil { + in, out := &in.PackageServerSyncInterval, &out.PackageServerSyncInterval + *out = new(metav1.Duration) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Features. diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go index ef8b2c8f2..d69341d8a 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/catalogsource_types.go @@ -7,6 +7,7 @@ import ( "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) @@ -140,6 +141,35 @@ type GrpcPodConfig struct { // +kubebuilder:validation:Enum=legacy;restricted // +kubebuilder:default:=legacy SecurityContextConfig SecurityConfig `json:"securityContextConfig,omitempty"` + + // MemoryTarget configures the $GOMEMLIMIT value for the gRPC catalog Pod. This is a soft memory limit for the server, + // which the runtime will attempt to meet but makes no guarantees that it will do so. If this value is set, the Pod + // will have the following modifications made to the container running the server: + // - the $GOMEMLIMIT environment variable will be set to this value in bytes + // - the memory request will be set to this value + // + // This field should be set if it's desired to reduce the footprint of a catalog server as much as possible, or if + // a catalog being served is very large and needs more than the default allocation. If your index image has a file- + // system cache, determine a good approximation for this value by doubling the size of the package cache at + // /tmp/cache/cache/packages.json in the index image. + // + // This field is best-effort; if unset, no default will be used and no Pod memory limit or $GOMEMLIMIT value will be set. + // +optional + MemoryTarget *resource.Quantity `json:"memoryTarget,omitempty"` + + // ExtractContent configures the gRPC catalog Pod to extract catalog metadata from the provided index image and + // use a well-known version of the `opm` server to expose it. The catalog index image that this CatalogSource is + // configured to use *must* be using the file-based catalogs in order to utilize this feature. + // +optional + ExtractContent *ExtractContentConfig `json:"extractContent,omitempty"` +} + +// ExtractContentConfig configures context extraction from a file-based catalog index image. +type ExtractContentConfig struct { + // CacheDir is the directory storing the pre-calculated API cache. + CacheDir string `json:"cacheDir"` + // CatalogDir is the directory storing the file-based catalog contents. + CatalogDir string `json:"catalogDir"` } // UpdateStrategy holds all the different types of catalog source update strategies diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/clusterserviceversion.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/clusterserviceversion.go index ffc357b12..a4c8d1746 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/clusterserviceversion.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/clusterserviceversion.go @@ -120,12 +120,19 @@ func (c *ClusterServiceVersion) IsObsolete() bool { // IsCopied returns true if the CSV has been copied and false otherwise. func (c *ClusterServiceVersion) IsCopied() bool { - operatorNamespace, ok := c.GetAnnotations()[OperatorGroupNamespaceAnnotationKey] - if c.Status.Reason == CSVReasonCopied || ok && c.GetNamespace() != operatorNamespace { - return true + return c.Status.Reason == CSVReasonCopied || IsCopied(c) +} + +func IsCopied(o metav1.Object) bool { + annotations := o.GetAnnotations() + if annotations != nil { + operatorNamespace, ok := annotations[OperatorGroupNamespaceAnnotationKey] + if ok && o.GetNamespace() != operatorNamespace { + return true + } } - if labels := c.GetLabels(); labels != nil { + if labels := o.GetLabels(); labels != nil { if _, ok := labels[CopiedLabelKey]; ok { return true } diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go index 2452f9a1c..672489264 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/subscription_types.go @@ -117,6 +117,19 @@ const ( // SubscriptionBundleUnpackFailed indicates that the unpack job failed SubscriptionBundleUnpackFailed SubscriptionConditionType = "BundleUnpackFailed" + + // SubscriptionDeprecated is a roll-up condition which indicates that the Operator currently installed with this Subscription + //has been deprecated. It will be present when any of the three deprecation types (Package, Channel, Bundle) are present. + SubscriptionDeprecated SubscriptionConditionType = "Deprecated" + + // SubscriptionOperatorDeprecated indicates that the Package currently installed with this Subscription has been deprecated. + SubscriptionPackageDeprecated SubscriptionConditionType = "PackageDeprecated" + + // SubscriptionOperatorDeprecated indicates that the Channel used with this Subscription has been deprecated. + SubscriptionChannelDeprecated SubscriptionConditionType = "ChannelDeprecated" + + // SubscriptionOperatorDeprecated indicates that the Bundle currently installed with this Subscription has been deprecated. + SubscriptionBundleDeprecated SubscriptionConditionType = "BundleDeprecated" ) const ( diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go index cf01001f5..de6ec2b82 100644 --- a/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/operator-framework/api/pkg/operators/v1alpha1/zz_generated.deepcopy.go @@ -690,6 +690,21 @@ func (in *DependentStatus) DeepCopy() *DependentStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExtractContentConfig) DeepCopyInto(out *ExtractContentConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExtractContentConfig. +func (in *ExtractContentConfig) DeepCopy() *ExtractContentConfig { + if in == nil { + return nil + } + out := new(ExtractContentConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GRPCConnectionState) DeepCopyInto(out *GRPCConnectionState) { *out = *in @@ -733,6 +748,16 @@ func (in *GrpcPodConfig) DeepCopyInto(out *GrpcPodConfig) { *out = new(string) **out = **in } + if in.MemoryTarget != nil { + in, out := &in.MemoryTarget, &out.MemoryTarget + x := (*in).DeepCopy() + *out = &x + } + if in.ExtractContent != nil { + in, out := &in.ExtractContent, &out.ExtractContent + *out = new(ExtractContentConfig) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GrpcPodConfig. diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v2/doc.go b/vendor/github.com/operator-framework/api/pkg/operators/v2/doc.go new file mode 100644 index 000000000..f85f79242 --- /dev/null +++ b/vendor/github.com/operator-framework/api/pkg/operators/v2/doc.go @@ -0,0 +1,4 @@ +// +groupName=operators.coreos.com + +// Package v2 contains resources types for version v2 of the operators.coreos.com API group. +package v2 diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v2/groupversion_info.go b/vendor/github.com/operator-framework/api/pkg/operators/v2/groupversion_info.go new file mode 100644 index 000000000..2d2d923d1 --- /dev/null +++ b/vendor/github.com/operator-framework/api/pkg/operators/v2/groupversion_info.go @@ -0,0 +1,28 @@ +// +kubebuilder:object:generate=true + +// Package v2 contains API Schema definitions for the operator v2 API group. +package v2 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects. + GroupVersion = schema.GroupVersion{Group: "operators.coreos.com", Version: "v2"} + + // SchemeGroupVersion is required for compatibility with client generation. + SchemeGroupVersion = GroupVersion + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme. + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return GroupVersion.WithResource(resource).GroupResource() +} diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v2/operatorcondition_types.go b/vendor/github.com/operator-framework/api/pkg/operators/v2/operatorcondition_types.go new file mode 100644 index 000000000..ef1c56de6 --- /dev/null +++ b/vendor/github.com/operator-framework/api/pkg/operators/v2/operatorcondition_types.go @@ -0,0 +1,54 @@ +package v2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + // Upgradeable indicates that the operator is upgradeable + Upgradeable string = "Upgradeable" +) + +// ConditionType codifies a condition's type. +type ConditionType string + +// OperatorConditionSpec allows an operator to report state to OLM and provides +// cluster admin with the ability to manually override state reported by the operator. +type OperatorConditionSpec struct { + ServiceAccounts []string `json:"serviceAccounts,omitempty"` + Deployments []string `json:"deployments,omitempty"` + Overrides []metav1.Condition `json:"overrides,omitempty"` + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// OperatorConditionStatus allows OLM to convey which conditions have been observed. +type OperatorConditionStatus struct { + Conditions []metav1.Condition `json:"conditions,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient +// +kubebuilder:storageversion +// +kubebuilder:resource:shortName=condition,categories=olm +// +kubebuilder:subresource:status +// OperatorCondition is a Custom Resource of type `OperatorCondition` which is used to convey information to OLM about the state of an operator. +type OperatorCondition struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + Spec OperatorConditionSpec `json:"spec,omitempty"` + Status OperatorConditionStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// OperatorConditionList represents a list of Conditions. +type OperatorConditionList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []OperatorCondition `json:"items"` +} + +func init() { + SchemeBuilder.Register(&OperatorCondition{}, &OperatorConditionList{}) +} diff --git a/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go b/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go new file mode 100644 index 000000000..8f7498c35 --- /dev/null +++ b/vendor/github.com/operator-framework/api/pkg/operators/v2/zz_generated.deepcopy.go @@ -0,0 +1,146 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v2 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorCondition) DeepCopyInto(out *OperatorCondition) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorCondition. +func (in *OperatorCondition) DeepCopy() *OperatorCondition { + if in == nil { + return nil + } + out := new(OperatorCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OperatorCondition) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConditionList) DeepCopyInto(out *OperatorConditionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OperatorCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConditionList. +func (in *OperatorConditionList) DeepCopy() *OperatorConditionList { + if in == nil { + return nil + } + out := new(OperatorConditionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OperatorConditionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConditionSpec) DeepCopyInto(out *OperatorConditionSpec) { + *out = *in + if in.ServiceAccounts != nil { + in, out := &in.ServiceAccounts, &out.ServiceAccounts + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Deployments != nil { + in, out := &in.Deployments, &out.Deployments + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Overrides != nil { + in, out := &in.Overrides, &out.Overrides + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConditionSpec. +func (in *OperatorConditionSpec) DeepCopy() *OperatorConditionSpec { + if in == nil { + return nil + } + out := new(OperatorConditionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OperatorConditionStatus) DeepCopyInto(out *OperatorConditionStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperatorConditionStatus. +func (in *OperatorConditionStatus) DeepCopy() *OperatorConditionStatus { + if in == nil { + return nil + } + out := new(OperatorConditionStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/operator-framework/operator-lib/LICENSE b/vendor/github.com/operator-framework/operator-lib/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lib/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/operator-framework/operator-lib/conditions/conditions.go b/vendor/github.com/operator-framework/operator-lib/conditions/conditions.go new file mode 100644 index 000000000..7dc365d68 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lib/conditions/conditions.go @@ -0,0 +1,76 @@ +// Copyright 2020 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conditions + +import ( + "context" + "fmt" + + apiv2 "github.com/operator-framework/api/pkg/operators/v2" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var ( + // ErrNoOperatorCondition indicates that the operator condition CRD is nil + ErrNoOperatorCondition = fmt.Errorf("operator Condition CRD is nil") +) + +// condition is a Condition that gets and sets a specific +// conditionType in the OperatorCondition CR. +type condition struct { + namespacedName types.NamespacedName + condType apiv2.ConditionType + client client.Client +} + +var _ Condition = &condition{} + +// Get implements conditions.Get +func (c *condition) Get(ctx context.Context) (*metav1.Condition, error) { + operatorCond := &apiv2.OperatorCondition{} + err := c.client.Get(ctx, c.namespacedName, operatorCond) + if err != nil { + return nil, err + } + con := meta.FindStatusCondition(operatorCond.Spec.Conditions, string(c.condType)) + + if con == nil { + return nil, fmt.Errorf("conditionType %v not found", c.condType) + } + return con, nil +} + +// Set implements conditions.Set +func (c *condition) Set(ctx context.Context, status metav1.ConditionStatus, option ...Option) error { + operatorCond := &apiv2.OperatorCondition{} + err := c.client.Get(ctx, c.namespacedName, operatorCond) + if err != nil { + return err + } + + newCond := &metav1.Condition{ + Type: string(c.condType), + Status: status, + } + + for _, opt := range option { + opt(newCond) + } + meta.SetStatusCondition(&operatorCond.Spec.Conditions, *newCond) + return c.client.Update(ctx, operatorCond) +} diff --git a/vendor/github.com/operator-framework/operator-lib/conditions/factory.go b/vendor/github.com/operator-framework/operator-lib/conditions/factory.go new file mode 100644 index 000000000..64ff9bb9a --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lib/conditions/factory.go @@ -0,0 +1,119 @@ +// Copyright 2021 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conditions + +import ( + "fmt" + "os" + + apiv2 "github.com/operator-framework/api/pkg/operators/v2" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "github.com/operator-framework/operator-lib/internal/utils" +) + +// Factory define the interface for building Conditions. +type Factory interface { + NewCondition(apiv2.ConditionType) (Condition, error) + GetNamespacedName() (*types.NamespacedName, error) +} + +// InClusterFactory is a conditions factory that can build conditions and get +// the namespaced name of the operator's condition based on an in-cluster +// configuration. +type InClusterFactory struct { + Client client.Client +} + +// NewCondition creates a new Condition using the provided client and condition +// type. The condition's name and namespace are determined by the Factory's GetName +// and GetNamespace functions. +func (f InClusterFactory) NewCondition(condType apiv2.ConditionType) (Condition, error) { + objKey, err := f.GetNamespacedName() + if err != nil { + return nil, err + } + return &condition{ + namespacedName: *objKey, + condType: condType, + client: f.Client, + }, nil +} + +// GetNamespacedName returns the NamespacedName of the CR. It returns an error +// when the name of the CR cannot be found from the environment variable set by +// OLM. Hence, GetNamespacedName() can provide the NamespacedName when the operator +// is running on cluster and is being managed by OLM. +func (f InClusterFactory) GetNamespacedName() (*types.NamespacedName, error) { + conditionName, err := f.getConditionName() + if err != nil { + return nil, fmt.Errorf("get operator condition name: %v", err) + } + conditionNamespace, err := f.getConditionNamespace() + if err != nil { + return nil, fmt.Errorf("get operator condition namespace: %v", err) + } + + return &types.NamespacedName{Name: conditionName, Namespace: conditionNamespace}, nil +} + +const ( + // operatorCondEnvVar is the env variable which + // contains the name of the Condition CR associated to the operator, + // set by OLM. + operatorCondEnvVar = "OPERATOR_CONDITION_NAME" +) + +// getConditionName reads and returns the OPERATOR_CONDITION_NAME environment +// variable. If the variable is unset or empty, it returns an error. +func (f InClusterFactory) getConditionName() (string, error) { + name := os.Getenv(operatorCondEnvVar) + if name == "" { + return "", fmt.Errorf("could not determine operator condition name: environment variable %s not set", operatorCondEnvVar) + } + return name, nil +} + +// readNamespace gets the namespacedName of the operator. +var readNamespace = utils.GetOperatorNamespace + +// getConditionNamespace reads the namespace file mounted into a pod in a +// cluster via its service account volume. If the file is not found or cannot be +// read, this function returns an error. +func (f InClusterFactory) getConditionNamespace() (string, error) { + return readNamespace() +} + +// NewCondition returns a new Condition interface using the provided client +// for the specified conditionType. The condition will internally fetch the namespacedName +// of the operatorConditionCRD. +// +// Deprecated: Use InClusterFactory{cl}.NewCondition() instead. +func NewCondition(cl client.Client, condType apiv2.ConditionType) (Condition, error) { + return InClusterFactory{cl}.NewCondition(condType) +} + +// GetNamespacedName returns the NamespacedName of the CR. It returns an error +// when the name of the CR cannot be found from the environment variable set by +// OLM. Hence, GetNamespacedName() can provide the NamespacedName when the operator +// is running on cluster and is being managed by OLM. If running locally, operator +// writers are encouraged to skip this method or gracefully handle the errors by logging +// a message. +// +// Deprecated: InClusterFactory{}.GetNamespacedName(). +func GetNamespacedName() (*types.NamespacedName, error) { + return InClusterFactory{}.GetNamespacedName() +} diff --git a/vendor/github.com/operator-framework/operator-lib/conditions/interface.go b/vendor/github.com/operator-framework/operator-lib/conditions/interface.go new file mode 100644 index 000000000..37e9d8711 --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lib/conditions/interface.go @@ -0,0 +1,60 @@ +// Copyright 2020 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conditions + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Condition can Get and Set a conditionType in an Operator Condition custom resource +// associated with the operator. +type Condition interface { + // Get fetches the condition on the operator's + // OperatorCondition. It returns an error if there are problems getting + // the OperatorCondition object or if the specific condition type does not + // exist. + Get(ctx context.Context) (*metav1.Condition, error) + + // Set sets the specific condition on the operator's + // OperatorCondition to the provided status. If the condition is not + // present, it is added to the CR. + // To set a new condition, the user can call this method and provide optional + // parameters if required. It returns an error if there are problems getting or + // updating the OperatorCondition object. + Set(ctx context.Context, status metav1.ConditionStatus, option ...Option) error +} + +// Option is a function that applies a change to a condition. +// This can be used to set optional condition fields, like reasons +// and messages. +type Option func(*metav1.Condition) + +// WithReason is an Option, which adds the reason +// to the condition. +func WithReason(reason string) Option { + return func(c *metav1.Condition) { + c.Reason = reason + } +} + +// WithMessage is an Option, which adds the reason +// to the condition. +func WithMessage(message string) Option { + return func(c *metav1.Condition) { + c.Message = message + } +} diff --git a/vendor/github.com/operator-framework/operator-lib/internal/utils/utils.go b/vendor/github.com/operator-framework/operator-lib/internal/utils/utils.go new file mode 100644 index 000000000..fb1f5985a --- /dev/null +++ b/vendor/github.com/operator-framework/operator-lib/internal/utils/utils.go @@ -0,0 +1,43 @@ +// Copyright 2020 The Operator-SDK Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package utils + +import ( + "fmt" + "os" + "strings" +) + +// ErrNoNamespace indicates that a namespace could not be found for the current +// environment +var ErrNoNamespace = fmt.Errorf("namespace not found for current environment") + +var readSAFile = func() ([]byte, error) { + return os.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/namespace") +} + +// GetOperatorNamespace returns the namespace the operator should be running in from +// the associated service account secret. +var GetOperatorNamespace = func() (string, error) { + nsBytes, err := readSAFile() + if err != nil { + if os.IsNotExist(err) { + return "", ErrNoNamespace + } + return "", err + } + ns := strings.TrimSpace(string(nsBytes)) + return ns, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 47f6e36c1..0b0530f29 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -247,12 +247,17 @@ github.com/openshift/api/security/v1 # github.com/openshift/custom-resource-status v1.1.2 ## explicit; go 1.12 github.com/openshift/custom-resource-status/conditions/v1 -# github.com/operator-framework/api v0.17.7-0.20230626210316-aa3e49803e7b +# github.com/operator-framework/api v0.20.0 ## explicit; go 1.19 github.com/operator-framework/api/pkg/lib/version github.com/operator-framework/api/pkg/operators github.com/operator-framework/api/pkg/operators/v1 github.com/operator-framework/api/pkg/operators/v1alpha1 +github.com/operator-framework/api/pkg/operators/v2 +# github.com/operator-framework/operator-lib v0.11.1-0.20230717184314-6efbe3a22f6f +## explicit; go 1.19 +github.com/operator-framework/operator-lib/conditions +github.com/operator-framework/operator-lib/internal/utils # github.com/pkg/errors v0.9.1 ## explicit github.com/pkg/errors From a8db2626e48b153a0fe393bcf23038caf36cf504 Mon Sep 17 00:00:00 2001 From: Leela Venkaiah G Date: Tue, 19 Dec 2023 15:30:13 +0530 Subject: [PATCH 2/3] controllers: surface dependent operator upgradeable conditions - odf-operator brings dependencies using OLM - this PR ensures odf-operator sets it's own operator condition based on upgradeability of it's dependents. Signed-off-by: Leela Venkaiah G --- controllers/subscription_controller.go | 146 ++++++++++++++++++++++++- main.go | 18 ++- pkg/util/openshift.go | 18 +++ pkg/util/strings.go | 11 ++ 4 files changed, 189 insertions(+), 4 deletions(-) diff --git a/controllers/subscription_controller.go b/controllers/subscription_controller.go index 3b7d6423e..694872aff 100644 --- a/controllers/subscription_controller.go +++ b/controllers/subscription_controller.go @@ -23,23 +23,32 @@ import ( "github.com/go-logr/logr" "go.uber.org/multierr" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/predicate" + "sigs.k8s.io/controller-runtime/pkg/reconcile" operatorv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorv2 "github.com/operator-framework/api/pkg/operators/v2" + "github.com/operator-framework/operator-lib/conditions" odfv1alpha1 "github.com/red-hat-storage/odf-operator/api/v1alpha1" + "github.com/red-hat-storage/odf-operator/pkg/util" ) // SubscriptionReconciler reconciles a Subscription object type SubscriptionReconciler struct { client.Client - Scheme *runtime.Scheme - Recorder *EventReporter + Scheme *runtime.Scheme + Recorder *EventReporter + ConditionName string + OperatorCondition conditions.Condition } //+kubebuilder:rbac:groups=operators.coreos.com,resources=subscriptions,verbs=get;list;watch;create;update;patch;delete @@ -47,6 +56,7 @@ type SubscriptionReconciler struct { //+kubebuilder:rbac:groups=operators.coreos.com,resources=subscriptions/finalizers,verbs=update //+kubebuilder:rbac:groups=operators.coreos.com,resources=installplans,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=operators.coreos.com,resources=clusterserviceversions/finalizers,verbs=update +//+kubebuilder:rbac:groups=operators.coreos.com,resources=operatorconditions,verbs=get;list;watch // For more details, check Reconcile and its Result here: // - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.8.3/pkg/reconcile @@ -65,6 +75,11 @@ func (r *SubscriptionReconciler) Reconcile(ctx context.Context, req ctrl.Request return ctrl.Result{}, err } + err = r.setOperatorCondition(logger, req.NamespacedName.Namespace) + if err != nil { + return ctrl.Result{}, err + } + err = r.ensureSubscriptions(logger, req.NamespacedName.Namespace) if err != nil { return ctrl.Result{}, err @@ -117,6 +132,45 @@ func (r *SubscriptionReconciler) ensureSubscriptions(logger logr.Logger, namespa return err } +func (r *SubscriptionReconciler) setOperatorCondition(logger logr.Logger, namespace string) error { + ocdList := &operatorv2.OperatorConditionList{} + err := r.Client.List(context.TODO(), ocdList, client.InNamespace(namespace)) + if err != nil { + logger.Error(err, "failed to list OperatorConditions") + return err + } + + condNames := append(GetVendorCsvNames(StorageClusterKind), GetVendorCsvNames(FlashSystemKind)...) + + condMap := make(map[string]struct{}, len(condNames)) + for i := range condNames { + condMap[condNames[i]] = struct{}{} + } + + for ocdIdx := range ocdList.Items { + // skip operatorconditions of not dependent operators + if _, exist := condMap[ocdList.Items[ocdIdx].GetName()]; !exist { + continue + } + + ocd := &ocdList.Items[ocdIdx] + cond := getNotUpgradeableCond(ocd) + if cond != nil { + // operator is not upgradeable + msg := fmt.Sprintf("%s:%s", ocd.GetName(), cond.Message) + logger.Info("setting operator upgradeable status", "status", cond.Status) + return r.OperatorCondition.Set(context.TODO(), cond.Status, + conditions.WithReason(cond.Reason), conditions.WithMessage(msg)) + } + } + + // all operators are upgradeable + status := metav1.ConditionTrue + logger.Info("setting operator upgradeable status", "status", status) + return r.OperatorCondition.Set(context.TODO(), status, + conditions.WithReason("Dependents"), conditions.WithMessage("No dependent reports not upgradeable status")) +} + // SetupWithManager sets up the controller with the Manager. func (r *SubscriptionReconciler) SetupWithManager(mgr ctrl.Manager) error { @@ -151,10 +205,98 @@ func (r *SubscriptionReconciler) SetupWithManager(mgr ctrl.Manager) error { }, } + conditionPredicate := predicate.Funcs{ + CreateFunc: func(e event.CreateEvent) bool { + return false + }, + UpdateFunc: func(e event.UpdateEvent) bool { + // not mandatory but these checks wouldn't harm + if e.ObjectOld == nil || e.ObjectNew == nil { + return false + } + oldObj, _ := e.ObjectOld.(*operatorv2.OperatorCondition) + newObj, _ := e.ObjectNew.(*operatorv2.OperatorCondition) + if oldObj == nil || newObj == nil { + return false + } + + // skip sending a reconcile event if our own condition is updated + if newObj.GetName() == r.ConditionName { + return false + } + + // change in admin set conditions for upgradeability + oldOverride := util.Find(oldObj.Spec.Overrides, func(cond *metav1.Condition) bool { + return cond.Type == operatorv2.Upgradeable + }) + newOverride := util.Find(newObj.Spec.Overrides, func(cond *metav1.Condition) bool { + return cond.Type == operatorv2.Upgradeable + }) + if oldOverride != nil && newOverride == nil { + // override is removed + return true + } + if newOverride != nil { + if oldOverride == nil { + return true + } + return oldOverride.Status != newOverride.Status + } + + // change in operator set conditions for upgradeability + oldCond := util.Find(oldObj.Status.Conditions, func(cond *metav1.Condition) bool { + return cond.Type == operatorv2.Upgradeable + }) + newCond := util.Find(newObj.Status.Conditions, func(cond *metav1.Condition) bool { + return cond.Type == operatorv2.Upgradeable + }) + if newCond != nil { + if oldCond == nil { + return true + } + return oldCond.Status != newCond.Status + } + + return false + }, + } + enqueueFromCondition := handler.EnqueueRequestsFromMapFunc( + func(ctx context.Context, obj client.Object) []reconcile.Request { + if _, ok := obj.(*operatorv2.OperatorCondition); !ok { + return []reconcile.Request{} + } + logger := log.FromContext(ctx) + sub, err := GetOdfSubscription(r.Client) + if err != nil { + logger.Error(err, "failed to get ODF Subscription") + return []reconcile.Request{} + } + return []reconcile.Request{{NamespacedName: types.NamespacedName{Name: sub.Name, Namespace: sub.Namespace}}} + }, + ) + return ctrl.NewControllerManagedBy(mgr). For(&operatorv1alpha1.Subscription{}, builder.WithPredicates(generationChangedPredicate, subscriptionPredicate)). Owns(&operatorv1alpha1.Subscription{}, builder.WithPredicates(generationChangedPredicate)). + Watches(&operatorv2.OperatorCondition{}, enqueueFromCondition, builder.WithPredicates(conditionPredicate)). Complete(r) } + +func getNotUpgradeableCond(ocd *operatorv2.OperatorCondition) *metav1.Condition { + cond := util.Find(ocd.Spec.Overrides, func(cd *metav1.Condition) bool { + return cd.Type == operatorv2.Upgradeable + }) + if cond != nil { + if cond.Status != "True" { + return cond + } + // if upgradeable is overridden we should skip checking operator set conditions + return nil + } + + return util.Find(ocd.Status.Conditions, func(cd *metav1.Condition) bool { + return cd.Type == operatorv2.Upgradeable && cd.Status != "True" + }) +} diff --git a/main.go b/main.go index d21e128e5..3a66251ae 100644 --- a/main.go +++ b/main.go @@ -33,6 +33,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" operatorv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorv2 "github.com/operator-framework/api/pkg/operators/v2" ibmv1alpha1 "github.com/IBM/ibm-storage-odf-operator/api/v1alpha1" ocsv1 "github.com/red-hat-storage/ocs-operator/api/v4/v1" @@ -62,6 +63,7 @@ func init() { utilruntime.Must(ibmv1alpha1.AddToScheme(scheme)) utilruntime.Must(operatorv1alpha1.AddToScheme(scheme)) + utilruntime.Must(operatorv2.AddToScheme(scheme)) //+kubebuilder:scaffold:scheme utilruntime.Must(consolev1.AddToScheme(scheme)) @@ -126,9 +128,21 @@ func main() { os.Exit(1) } + conditionName, err := util.GetConditionName(mgr.GetClient()) + if err != nil { + setupLog.Error(err, "unable to get condition name") + os.Exit(1) + } + condition, err := util.NewUpgradeableCondition(mgr.GetClient()) + if err != nil { + setupLog.Error(err, "unable to get OperatorCondition") + os.Exit(1) + } subscriptionReconciler := &controllers.SubscriptionReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + ConditionName: conditionName, + OperatorCondition: condition, } if err = subscriptionReconciler.SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "Subscription") diff --git a/pkg/util/openshift.go b/pkg/util/openshift.go index aff85b004..2fb74bd83 100644 --- a/pkg/util/openshift.go +++ b/pkg/util/openshift.go @@ -20,6 +20,8 @@ import ( "context" configv1 "github.com/openshift/api/config/v1" + operatorv2 "github.com/operator-framework/api/pkg/operators/v2" + "github.com/operator-framework/operator-lib/conditions" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -35,3 +37,19 @@ func DetermineOpenShiftVersion(client client.Client) (string, error) { } return clusterVersion, nil } + +func getConditionFactory(client client.Client) conditions.Factory { + return conditions.InClusterFactory{Client: client} +} + +func GetConditionName(client client.Client) (string, error) { + namespacedName, err := getConditionFactory(client).GetNamespacedName() + if err != nil { + return "", err + } + return namespacedName.Name, nil +} + +func NewUpgradeableCondition(client client.Client) (conditions.Condition, error) { + return getConditionFactory(client).NewCondition(operatorv2.ConditionType(operatorv2.Upgradeable)) +} diff --git a/pkg/util/strings.go b/pkg/util/strings.go index a2dd5a0db..2788b8504 100644 --- a/pkg/util/strings.go +++ b/pkg/util/strings.go @@ -36,3 +36,14 @@ func RemoveFromSlice(slice []string, s string) (result []string) { } return } + +// Find returns the first entry matching the function "f" or else return nil +func Find[T any](list []T, f func(item *T) bool) *T { + for idx := range list { + ele := &list[idx] + if f(ele) { + return ele + } + } + return nil +} From 9ce106bb0fa4e52d92011046109b692d23197671 Mon Sep 17 00:00:00 2001 From: Leela Venkaiah G Date: Tue, 19 Dec 2023 15:32:08 +0530 Subject: [PATCH 3/3] bundle: update role to work with operatorconditions Signed-off-by: Leela Venkaiah G --- .../manifests/odf-operator.clusterserviceversion.yaml | 10 +++++++++- config/rbac/role.yaml | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bundle/manifests/odf-operator.clusterserviceversion.yaml b/bundle/manifests/odf-operator.clusterserviceversion.yaml index 594eabc2d..f8e023f64 100644 --- a/bundle/manifests/odf-operator.clusterserviceversion.yaml +++ b/bundle/manifests/odf-operator.clusterserviceversion.yaml @@ -35,7 +35,7 @@ metadata: categories: Storage console.openshift.io/plugins: '["odf-console"]' containerImage: quay.io/ocs-dev/odf-operator:latest - createdAt: "2023-11-28T10:45:09Z" + createdAt: "2023-12-12T05:53:20Z" description: OpenShift Data Foundation provides a common control plane for storage solutions on OpenShift Container Platform. features.operators.openshift.io/token-auth-aws: "true" @@ -336,6 +336,14 @@ spec: - patch - update - watch + - apiGroups: + - operators.coreos.com + resources: + - operatorconditions + verbs: + - get + - list + - watch - apiGroups: - operators.coreos.com resources: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index e5b61c26d..1c653c73b 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -195,6 +195,14 @@ rules: - patch - update - watch +- apiGroups: + - operators.coreos.com + resources: + - operatorconditions + verbs: + - get + - list + - watch - apiGroups: - operators.coreos.com resources: