From 4a714c916ad79e03d70eb9c9dfc633cdd8a00b05 Mon Sep 17 00:00:00 2001 From: Pranshu Srivastava Date: Fri, 11 Oct 2024 15:34:04 +0530 Subject: [PATCH] Update `library-go` To address the recent regression faced here. Signed-off-by: Pranshu Srivastava --- go.mod | 2 + go.sum | 4 +- pkg/cmd/certregenerationcontroller/cmd.go | 2 + pkg/operator/starter.go | 2 + test/e2e/certrotation_test.go | 2 + test/e2e/operator_test.go | 2 + .../audit/manifests/base-policy.yaml | 1 + .../dynamic_operator_client.go | 43 +++++----- .../dynamic_staticpod_operator_client.go | 39 +++------ .../test_operator_client.go | 37 ++++++++ .../resource/resourceapply/monitoring.go | 85 ++++++------------- .../resource/resourcemerge/object_merger.go | 46 ++++++++++ .../staticpodstate_controller.go | 47 +++++----- .../pkg/operator/staticpod/controllers.go | 1 + .../pkg/operator/v1helpers/canonicalize.go | 13 +-- vendor/modules.txt | 3 +- 16 files changed, 186 insertions(+), 143 deletions(-) create mode 100644 vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/test_operator_client.go diff --git a/go.mod b/go.mod index a158669ac8..c800337952 100644 --- a/go.mod +++ b/go.mod @@ -128,3 +128,5 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) + +replace github.com/openshift/library-go => github.com/rexagod/library-go v0.0.0-20241011095547-5a2eb4344baa diff --git a/go.sum b/go.sum index aa1b350212..4268a88f2b 100644 --- a/go.sum +++ b/go.sum @@ -167,8 +167,6 @@ github.com/openshift/build-machinery-go v0.0.0-20240613134303-8359781da660 h1:F0 github.com/openshift/build-machinery-go v0.0.0-20240613134303-8359781da660/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE= github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f h1:FRc0bVNWprihWS0GqQWzb3dY4dkCwpOP3mDw5NwSoR4= github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f/go.mod h1:KiZi2mJRH1TOJ3FtBDYS6YvUL30s/iIXaGSUrSa36mo= -github.com/openshift/library-go v0.0.0-20241001171606-756adf2188fc h1:QXYkFJn7wLTHAI56l+9DJnLrNynGtXjyOZLgiIglTnE= -github.com/openshift/library-go v0.0.0-20241001171606-756adf2188fc/go.mod h1:9B1MYPoLtP9tqjWxcbUNVpwxy68zOH/3EIP6c31dAM0= github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -187,6 +185,8 @@ github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rexagod/library-go v0.0.0-20241011095547-5a2eb4344baa h1:IQsSihF2fuzEglhjrdEqtUosUrFa5pzF7gU5Z6MgPUo= +github.com/rexagod/library-go v0.0.0-20241011095547-5a2eb4344baa/go.mod h1:9B1MYPoLtP9tqjWxcbUNVpwxy68zOH/3EIP6c31dAM0= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= diff --git a/pkg/cmd/certregenerationcontroller/cmd.go b/pkg/cmd/certregenerationcontroller/cmd.go index b151c75660..4a1e5ba925 100644 --- a/pkg/cmd/certregenerationcontroller/cmd.go +++ b/pkg/cmd/certregenerationcontroller/cmd.go @@ -6,6 +6,7 @@ import ( "time" "github.com/spf13/cobra" + "k8s.io/utils/clock" "k8s.io/client-go/kubernetes" @@ -94,6 +95,7 @@ func (o *Options) Run(ctx context.Context) error { ) operatorClient, dynamicInformers, err := genericoperatorclient.NewStaticPodOperatorClient( + clock.RealClock{}, o.controllerContext.KubeConfig, operatorv1.GroupVersion.WithResource("kubeapiservers"), operatorv1.GroupVersion.WithKind("KubeAPIServer"), diff --git a/pkg/operator/starter.go b/pkg/operator/starter.go index ae41cb56b8..d802d3c1ff 100644 --- a/pkg/operator/starter.go +++ b/pkg/operator/starter.go @@ -9,6 +9,7 @@ import ( "time" "github.com/blang/semver/v4" + "k8s.io/utils/clock" configv1 "github.com/openshift/api/config/v1" operatorv1 "github.com/openshift/api/operator/v1" @@ -132,6 +133,7 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle ) configInformers := configv1informers.NewSharedInformerFactory(configClient, 10*time.Minute) operatorClient, dynamicInformersForAllNamespaces, err := genericoperatorclient.NewStaticPodOperatorClient( + clock.RealClock{}, controllerContext.KubeConfig, operatorv1.GroupVersion.WithResource("kubeapiservers"), operatorv1.GroupVersion.WithKind("KubeAPIServer"), diff --git a/test/e2e/certrotation_test.go b/test/e2e/certrotation_test.go index 6d7ead88e1..7a3571b186 100644 --- a/test/e2e/certrotation_test.go +++ b/test/e2e/certrotation_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/require" + "k8s.io/utils/clock" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -30,6 +31,7 @@ func TestCertRotationTimeUpgradeable(t *testing.T) { kubeConfig, err := test.NewClientConfigForTest() require.NoError(t, err) operatorClient, _, err := genericoperatorclient.NewStaticPodOperatorClient( + clock.RealClock{}, kubeConfig, operatorv1.GroupVersion.WithResource("kubeapiservers"), operatorv1.GroupVersion.WithKind("KubeAPIServer"), diff --git a/test/e2e/operator_test.go b/test/e2e/operator_test.go index a6932ae98c..b3da6ca04e 100644 --- a/test/e2e/operator_test.go +++ b/test/e2e/operator_test.go @@ -17,6 +17,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/kubernetes" + "k8s.io/utils/clock" ) func TestOperatorNamespace(t *testing.T) { @@ -50,6 +51,7 @@ func TestRevisionLimits(t *testing.T) { kubeClient, err := kubernetes.NewForConfig(kubeConfig) require.NoError(t, err) operatorClient, _, err := genericoperatorclient.NewStaticPodOperatorClient( + clock.RealClock{}, kubeConfig, operatorv1.GroupVersion.WithResource("kubeapiservers"), operatorv1.GroupVersion.WithKind("KubeAPIServer"), diff --git a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/audit/manifests/base-policy.yaml b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/audit/manifests/base-policy.yaml index 0dc21b31a4..df0dfd7d2d 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/apiserver/audit/manifests/base-policy.yaml +++ b/vendor/github.com/openshift/library-go/pkg/operator/apiserver/audit/manifests/base-policy.yaml @@ -14,6 +14,7 @@ - "/version" - "/healthz" - "/readyz" + - "/livez" # Don't log requests by "system:apiserver" on apirequestcounts - level: None users: ["system:apiserver"] diff --git a/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_operator_client.go b/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_operator_client.go index 477224b05b..7c50d42b30 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_operator_client.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_operator_client.go @@ -22,6 +22,7 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" "k8s.io/klog/v2" + "k8s.io/utils/clock" "k8s.io/utils/ptr" ) @@ -32,20 +33,22 @@ type StaticPodOperatorStatusExtractorFunc func(obj *unstructured.Unstructured, f type OperatorSpecExtractorFunc func(obj *unstructured.Unstructured, fieldManager string) (*applyoperatorv1.OperatorSpecApplyConfiguration, error) type OperatorStatusExtractorFunc func(obj *unstructured.Unstructured, fieldManager string) (*applyoperatorv1.OperatorStatusApplyConfiguration, error) -func newClusterScopedOperatorClient(config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, extractApplySpec StaticPodOperatorSpecExtractorFunc, extractApplyStatus StaticPodOperatorStatusExtractorFunc) (*dynamicOperatorClient, dynamicinformer.DynamicSharedInformerFactory, error) { - dynamicClient, err := dynamic.NewForConfig(config) - if err != nil { - return nil, nil, err +func newClusterScopedOperatorClient(clock clock.PassiveClock, dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, instanceName string, extractApplySpec StaticPodOperatorSpecExtractorFunc, extractApplyStatus StaticPodOperatorStatusExtractorFunc) (*dynamicOperatorClient, dynamicinformer.DynamicSharedInformerFactory, error) { + if len(instanceName) < 1 { + return nil, nil, fmt.Errorf("config name cannot be empty") } + client := dynamicClient.Resource(gvr) informers := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 12*time.Hour) informer := informers.ForResource(gvr) return &dynamicOperatorClient{ + clock: clock, gvk: gvk, informer: informer, client: client, + configName: instanceName, extractApplySpec: extractApplySpec, extractApplyStatus: extractApplyStatus, }, informers, nil @@ -81,32 +84,26 @@ func convertOperatorStatusToStaticPodOperatorStatus(extractApplyStatus OperatorS } } -func NewClusterScopedOperatorClient(config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, extractApplySpec OperatorSpecExtractorFunc, extractApplyStatus OperatorStatusExtractorFunc) (v1helpers.OperatorClientWithFinalizers, dynamicinformer.DynamicSharedInformerFactory, error) { - d, informers, err := newClusterScopedOperatorClient(config, gvr, gvk, - convertOperatorSpecToStaticPodOperatorSpec(extractApplySpec), convertOperatorStatusToStaticPodOperatorStatus(extractApplyStatus)) - if err != nil { - return nil, nil, err - } - d.configName = defaultConfigName - return d, informers, nil +func NewClusterScopedOperatorClient(clock clock.PassiveClock, config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, extractApplySpec OperatorSpecExtractorFunc, extractApplyStatus OperatorStatusExtractorFunc) (v1helpers.OperatorClientWithFinalizers, dynamicinformer.DynamicSharedInformerFactory, error) { + return NewClusterScopedOperatorClientWithConfigName(clock, config, gvr, gvk, defaultConfigName, extractApplySpec, extractApplyStatus) } -func NewClusterScopedOperatorClientWithConfigName(config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, configName string, extractApplySpec OperatorSpecExtractorFunc, extractApplyStatus OperatorStatusExtractorFunc) (v1helpers.OperatorClientWithFinalizers, dynamicinformer.DynamicSharedInformerFactory, error) { - if len(configName) < 1 { - return nil, nil, fmt.Errorf("config name cannot be empty") - } - d, informers, err := newClusterScopedOperatorClient(config, gvr, gvk, - convertOperatorSpecToStaticPodOperatorSpec(extractApplySpec), convertOperatorStatusToStaticPodOperatorStatus(extractApplyStatus)) +func NewClusterScopedOperatorClientWithConfigName(clock clock.PassiveClock, config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, configName string, extractApplySpec OperatorSpecExtractorFunc, extractApplyStatus OperatorStatusExtractorFunc) (v1helpers.OperatorClientWithFinalizers, dynamicinformer.DynamicSharedInformerFactory, error) { + dynamicClient, err := dynamic.NewForConfig(config) if err != nil { return nil, nil, err } - d.configName = configName - return d, informers, nil + return newClusterScopedOperatorClient(clock, dynamicClient, gvr, gvk, configName, + convertOperatorSpecToStaticPodOperatorSpec(extractApplySpec), convertOperatorStatusToStaticPodOperatorStatus(extractApplyStatus)) } type dynamicOperatorClient struct { + // clock is used to allow apply-configuration to choose a fixed, "execute as though time/X", which is needed for stable + // testing output. + clock clock.PassiveClock + gvk schema.GroupVersionKind configName string informer informers.GenericInformer @@ -298,7 +295,7 @@ func (c dynamicOperatorClient) applyOperatorStatus(ctx context.Context, fieldMan // set last transitionTimes and then apply // If our cache improperly 404's (the lister wasn't synchronized), then we will improperly reset all the last transition times. // This isn't ideal, but we shouldn't hit this case unless a loop isn't waiting for HasSynced. - v1helpers.SetApplyConditionsLastTransitionTime(&desiredConfiguration.Conditions, nil) + v1helpers.SetApplyConditionsLastTransitionTime(c.clock, &desiredConfiguration.Conditions, nil) case err != nil: return fmt.Errorf("unable to read existing %q: %w", c.configName, err) @@ -325,9 +322,9 @@ func (c dynamicOperatorClient) applyOperatorStatus(ctx context.Context, fieldMan // This only becomes pathological if the condition is also flapping, but if that happens the time should also update. switch { case desiredConfiguration != nil && desiredConfiguration.Conditions != nil && previouslyDesiredConfiguration != nil: - v1helpers.SetApplyConditionsLastTransitionTime(&desiredConfiguration.Conditions, previouslyDesiredConfiguration.Conditions) + v1helpers.SetApplyConditionsLastTransitionTime(c.clock, &desiredConfiguration.Conditions, previouslyDesiredConfiguration.Conditions) case desiredConfiguration != nil && desiredConfiguration.Conditions != nil && previouslyDesiredConfiguration == nil: - v1helpers.SetApplyConditionsLastTransitionTime(&desiredConfiguration.Conditions, nil) + v1helpers.SetApplyConditionsLastTransitionTime(c.clock, &desiredConfiguration.Conditions, nil) } // canonicalize so the DeepEqual works consistently diff --git a/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_staticpod_operator_client.go b/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_staticpod_operator_client.go index 77b7824169..3e13f01d89 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_staticpod_operator_client.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/dynamic_staticpod_operator_client.go @@ -2,51 +2,32 @@ package genericoperatorclient import ( "context" - "time" - - applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1" "github.com/imdario/mergo" - - "k8s.io/apimachinery/pkg/runtime" - operatorv1 "github.com/openshift/api/operator/v1" + applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1" "github.com/openshift/library-go/pkg/operator/v1helpers" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic/dynamicinformer" "k8s.io/client-go/rest" + "k8s.io/utils/clock" ) -func NewStaticPodOperatorClient(config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, extractApplySpec StaticPodOperatorSpecExtractorFunc, extractApplyStatus StaticPodOperatorStatusExtractorFunc) (v1helpers.StaticPodOperatorClient, dynamicinformer.DynamicSharedInformerFactory, error) { +func NewStaticPodOperatorClient(clock clock.PassiveClock, config *rest.Config, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, extractApplySpec StaticPodOperatorSpecExtractorFunc, extractApplyStatus StaticPodOperatorStatusExtractorFunc) (v1helpers.StaticPodOperatorClient, dynamicinformer.DynamicSharedInformerFactory, error) { dynamicClient, err := dynamic.NewForConfig(config) if err != nil { return nil, nil, err } - client := dynamicClient.Resource(gvr) - - informers := dynamicinformer.NewDynamicSharedInformerFactory(dynamicClient, 12*time.Hour) - informer := informers.ForResource(gvr) - - return &dynamicStaticPodOperatorClient{ - dynamicOperatorClient: dynamicOperatorClient{ - gvk: gvk, - configName: defaultConfigName, - informer: informer, - client: client, - extractApplySpec: extractApplySpec, - extractApplyStatus: extractApplyStatus, - }, - }, informers, nil -} -type dynamicStaticPodOperatorClient struct { - dynamicOperatorClient + return newClusterScopedOperatorClient(clock, dynamicClient, gvr, gvk, defaultConfigName, + extractApplySpec, extractApplyStatus) } -func (c dynamicStaticPodOperatorClient) GetStaticPodOperatorState() (*operatorv1.StaticPodOperatorSpec, *operatorv1.StaticPodOperatorStatus, string, error) { +func (c dynamicOperatorClient) GetStaticPodOperatorState() (*operatorv1.StaticPodOperatorSpec, *operatorv1.StaticPodOperatorStatus, string, error) { uncastInstance, err := c.informer.Lister().Get("cluster") if err != nil { return nil, nil, "", err @@ -69,7 +50,7 @@ func getStaticPodOperatorStateFromInstance(instance *unstructured.Unstructured) return spec, status, instance.GetResourceVersion(), nil } -func (c dynamicStaticPodOperatorClient) GetStaticPodOperatorStateWithQuorum(ctx context.Context) (*operatorv1.StaticPodOperatorSpec, *operatorv1.StaticPodOperatorStatus, string, error) { +func (c dynamicOperatorClient) GetStaticPodOperatorStateWithQuorum(ctx context.Context) (*operatorv1.StaticPodOperatorSpec, *operatorv1.StaticPodOperatorStatus, string, error) { instance, err := c.client.Get(ctx, "cluster", metav1.GetOptions{}) if err != nil { return nil, nil, "", err @@ -78,7 +59,7 @@ func (c dynamicStaticPodOperatorClient) GetStaticPodOperatorStateWithQuorum(ctx return getStaticPodOperatorStateFromInstance(instance) } -func (c dynamicStaticPodOperatorClient) UpdateStaticPodOperatorSpec(ctx context.Context, resourceVersion string, spec *operatorv1.StaticPodOperatorSpec) (*operatorv1.StaticPodOperatorSpec, string, error) { +func (c dynamicOperatorClient) UpdateStaticPodOperatorSpec(ctx context.Context, resourceVersion string, spec *operatorv1.StaticPodOperatorSpec) (*operatorv1.StaticPodOperatorSpec, string, error) { uncastOriginal, err := c.informer.Lister().Get("cluster") if err != nil { return nil, "", err @@ -103,7 +84,7 @@ func (c dynamicStaticPodOperatorClient) UpdateStaticPodOperatorSpec(ctx context. return retSpec, ret.GetResourceVersion(), nil } -func (c dynamicStaticPodOperatorClient) UpdateStaticPodOperatorStatus(ctx context.Context, resourceVersion string, status *operatorv1.StaticPodOperatorStatus) (*operatorv1.StaticPodOperatorStatus, error) { +func (c dynamicOperatorClient) UpdateStaticPodOperatorStatus(ctx context.Context, resourceVersion string, status *operatorv1.StaticPodOperatorStatus) (*operatorv1.StaticPodOperatorStatus, error) { uncastOriginal, err := c.informer.Lister().Get("cluster") if err != nil { return nil, err diff --git a/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/test_operator_client.go b/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/test_operator_client.go new file mode 100644 index 0000000000..2239b15bf1 --- /dev/null +++ b/vendor/github.com/openshift/library-go/pkg/operator/genericoperatorclient/test_operator_client.go @@ -0,0 +1,37 @@ +package genericoperatorclient + +import ( + "net/http" + + "github.com/openshift/library-go/pkg/operator/v1helpers" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" + "k8s.io/client-go/dynamic/dynamicinformer" + "k8s.io/client-go/rest" + "k8s.io/utils/clock" +) + +func NewOperatorClientWithClient(clock clock.PassiveClock, httpClient *http.Client, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, extractApplySpec OperatorSpecExtractorFunc, extractApplyStatus OperatorStatusExtractorFunc) (v1helpers.OperatorClientWithFinalizers, dynamicinformer.DynamicSharedInformerFactory, error) { + return NewOperatorClientWithConfigNameWithClient(clock, httpClient, gvr, gvk, defaultConfigName, extractApplySpec, extractApplyStatus) + +} + +func NewOperatorClientWithConfigNameWithClient(clock clock.PassiveClock, httpClient *http.Client, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, configName string, extractApplySpec OperatorSpecExtractorFunc, extractApplyStatus OperatorStatusExtractorFunc) (v1helpers.OperatorClientWithFinalizers, dynamicinformer.DynamicSharedInformerFactory, error) { + dynamicClient, err := dynamic.NewForConfigAndClient(&rest.Config{}, httpClient) + if err != nil { + return nil, nil, err + } + + return newClusterScopedOperatorClient(clock, dynamicClient, gvr, gvk, configName, + convertOperatorSpecToStaticPodOperatorSpec(extractApplySpec), convertOperatorStatusToStaticPodOperatorStatus(extractApplyStatus)) +} + +func NewStaticPodOperatorClientWithConfigNameWithClient(clock clock.PassiveClock, httpClient *http.Client, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind, configName string, extractApplySpec StaticPodOperatorSpecExtractorFunc, extractApplyStatus StaticPodOperatorStatusExtractorFunc) (v1helpers.StaticPodOperatorClient, dynamicinformer.DynamicSharedInformerFactory, error) { + dynamicClient, err := dynamic.NewForConfigAndClient(&rest.Config{}, httpClient) + if err != nil { + return nil, nil, err + } + + return newClusterScopedOperatorClient(clock, dynamicClient, gvr, gvk, configName, + extractApplySpec, extractApplyStatus) +} diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/monitoring.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/monitoring.go index 99f3ecb73b..d0996a2afb 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/monitoring.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourceapply/monitoring.go @@ -2,23 +2,17 @@ package resourceapply import ( "context" - errorsstdlib "errors" - "fmt" + "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/resource/resourcehelper" + "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "k8s.io/klog/v2" - "k8s.io/utils/ptr" - - "github.com/openshift/library-go/pkg/operator/events" - "github.com/openshift/library-go/pkg/operator/resource/resourcehelper" - - "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" ) var alertmanagerGVR = schema.GroupVersionResource{Group: "monitoring.coreos.com", Version: "v1", Resource: "alertmanagers"} @@ -88,10 +82,10 @@ func ApplyUnstructuredResourceImproved( } existing, err := client.Resource(resourceGVR).Namespace(namespace).Get(ctx, name, metav1.GetOptions{}) if errors.IsNotFound(err) { - want, err := client.Resource(resourceGVR).Namespace(namespace).Create(ctx, required, metav1.CreateOptions{}) - resourcehelper.ReportCreateEvent(recorder, required, err) + want, errCreate := client.Resource(resourceGVR).Namespace(namespace).Create(ctx, required, metav1.CreateOptions{}) + resourcehelper.ReportCreateEvent(recorder, required, errCreate) cache.UpdateCachedResourceMetadata(required, want) - return want, true, err + return want, true, errCreate } if err != nil { return nil, false, err @@ -102,44 +96,15 @@ func ApplyUnstructuredResourceImproved( return existing, false, nil } - // Ensure metadata field is present on the object. existingCopy := existing.DeepCopy() - existingObjectMeta, found, err := unstructured.NestedMap(existingCopy.Object, "metadata") - if err != nil { - return nil, false, err - } - if !found { - return nil, false, errorsstdlib.New(fmt.Sprintf("metadata not found in the existing object: %s/%s", existing.GetNamespace(), existingCopy.GetName())) - } - requiredObjectMeta, found, err := unstructured.NestedMap(required.Object, "metadata") - if err != nil { - return nil, false, err - } - if !found { - return nil, false, errorsstdlib.New(fmt.Sprintf("metadata not found in the required object: %s/%s", required.GetNamespace(), required.GetName())) - } - // Cast the metadata to the correct type. - var existingObjectMetaTyped, requiredObjectMetaTyped metav1.ObjectMeta - err = runtime.DefaultUnstructuredConverter.FromUnstructured(existingObjectMeta, &existingObjectMetaTyped) - if err != nil { - return nil, false, err - } - err = runtime.DefaultUnstructuredConverter.FromUnstructured(requiredObjectMeta, &requiredObjectMetaTyped) + // Replace and/or merge certain metadata fields. + didMetadataModify := false + err = resourcemerge.EnsureObjectMetaForUnstructured(&didMetadataModify, existingCopy, required) if err != nil { return nil, false, err } - // Fail-fast if the resource versions differ. - if requiredObjectMetaTyped.ResourceVersion != "" && existingObjectMetaTyped.ResourceVersion != requiredObjectMetaTyped.ResourceVersion { - err = errors.NewConflict(resourceGVR.GroupResource(), name, fmt.Errorf("rejected to update %s %s because the object has been modified: desired/actual ResourceVersion: %v/%v", existing.GetKind(), existing.GetName(), requiredObjectMetaTyped.ResourceVersion, existingObjectMetaTyped.ResourceVersion)) - return nil, false, err - } - - // Check if the metadata objects differ. - didMetadataModify := ptr.To(false) - resourcemerge.EnsureObjectMeta(didMetadataModify, &existingObjectMetaTyped, requiredObjectMetaTyped) - // Deep-check the spec objects for equality, and update the cache in either case. if defaultingFunc == nil { defaultingFunc = noDefaulting @@ -147,26 +112,26 @@ func ApplyUnstructuredResourceImproved( if equalityChecker == nil { equalityChecker = equality.Semantic } - existingCopy, didSpecModify, err := ensureGenericSpec(required, existingCopy, defaultingFunc, equalityChecker) + didSpecModify := false + err = ensureGenericSpec(&didSpecModify, required, existingCopy, defaultingFunc, equalityChecker) if err != nil { return nil, false, err } - if !didSpecModify && !*didMetadataModify { + if !didSpecModify && !didMetadataModify { // Update cache even if certain fields are not modified, in order to maintain a consistent cache based on the // resource hash. The resource hash depends on the entire metadata, not just the fields that were checked above, cache.UpdateCachedResourceMetadata(required, existingCopy) return existingCopy, false, nil } + // Perform update if resource exists but different from the required (desired) one. if klog.V(4).Enabled() { klog.Infof("%s %q changes: %v", resourceGVR.String(), namespace+"/"+name, JSONPatchNoError(existing, existingCopy)) } - - // Perform update if resource exists but different from the required (desired) one. - actual, err := client.Resource(resourceGVR).Namespace(namespace).Update(ctx, required, metav1.UpdateOptions{}) - resourcehelper.ReportUpdateEvent(recorder, required, err) - cache.UpdateCachedResourceMetadata(required, actual) - return actual, true, err + actual, errUpdate := client.Resource(resourceGVR).Namespace(namespace).Update(ctx, existingCopy, metav1.UpdateOptions{}) + resourcehelper.ReportUpdateEvent(recorder, existingCopy, errUpdate) + cache.UpdateCachedResourceMetadata(existingCopy, actual) + return actual, true, errUpdate } // DeleteUnstructuredResource deletes the unstructured resource. @@ -182,27 +147,27 @@ func DeleteUnstructuredResource(ctx context.Context, client dynamic.Interface, r return nil, true, nil } -func ensureGenericSpec(required, existing *unstructured.Unstructured, mimicDefaultingFn mimicDefaultingFunc, equalityChecker equalityChecker) (*unstructured.Unstructured, bool, error) { +func ensureGenericSpec(didSpecModify *bool, required, existing *unstructured.Unstructured, mimicDefaultingFn mimicDefaultingFunc, equalityChecker equalityChecker) error { mimicDefaultingFn(required) requiredSpec, _, err := unstructured.NestedMap(required.UnstructuredContent(), "spec") if err != nil { - return nil, false, err + return err } existingSpec, _, err := unstructured.NestedMap(existing.UnstructuredContent(), "spec") if err != nil { - return nil, false, err + return err } if equalityChecker.DeepEqual(existingSpec, requiredSpec) { - return existing, false, nil + return nil } - existingCopy := existing.DeepCopy() - if err := unstructured.SetNestedMap(existingCopy.UnstructuredContent(), requiredSpec, "spec"); err != nil { - return nil, true, err + if err = unstructured.SetNestedMap(existing.UnstructuredContent(), requiredSpec, "spec"); err != nil { + return err } + *didSpecModify = true - return existingCopy, true, nil + return nil } // mimicDefaultingFunc is used to set fields that are defaulted. This allows for sparse manifests to apply correctly. diff --git a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourcemerge/object_merger.go b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourcemerge/object_merger.go index 4c5dcacaa7..20e19a78fe 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/resource/resourcemerge/object_merger.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/resource/resourcemerge/object_merger.go @@ -1,10 +1,14 @@ package resourcemerge import ( + errorsstdlib "errors" + "fmt" "reflect" "strings" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) @@ -18,6 +22,48 @@ func EnsureObjectMeta(modified *bool, existing *metav1.ObjectMeta, required meta MergeOwnerRefs(modified, &existing.OwnerReferences, required.OwnerReferences) } +func EnsureObjectMetaForUnstructured(modified *bool, existing *unstructured.Unstructured, required *unstructured.Unstructured) error { + + // Ensure metadata field is present on the object. + existingObjectMeta, found, err := unstructured.NestedMap(existing.Object, "metadata") + if err != nil { + return err + } + if !found { + return errorsstdlib.New(fmt.Sprintf("metadata not found in the existing object: %s/%s", existing.GetNamespace(), existing.GetName())) + } + var requiredObjectMeta map[string]interface{} + requiredObjectMeta, found, err = unstructured.NestedMap(required.Object, "metadata") + if err != nil { + return err + } + if !found { + return errorsstdlib.New(fmt.Sprintf("metadata not found in the required object: %s/%s", required.GetNamespace(), required.GetName())) + } + + // Cast the metadata to the correct type. + var existingObjectMetaTyped, requiredObjectMetaTyped metav1.ObjectMeta + err = runtime.DefaultUnstructuredConverter.FromUnstructured(existingObjectMeta, &existingObjectMetaTyped) + if err != nil { + return err + } + err = runtime.DefaultUnstructuredConverter.FromUnstructured(requiredObjectMeta, &requiredObjectMetaTyped) + if err != nil { + return err + } + + // Check if the metadata objects differ. This only checks for selective fields (excluding the resource version, among others). + EnsureObjectMeta(modified, &existingObjectMetaTyped, requiredObjectMetaTyped) + if *modified { + existing.Object["metadata"], err = runtime.DefaultUnstructuredConverter.ToUnstructured(&existingObjectMetaTyped) + if err != nil { + return err + } + } + + return nil +} + // WithCleanLabelsAndAnnotations cleans the metadata off the removal annotations/labels/ownerrefs // (those that end with trailing "-") func WithCleanLabelsAndAnnotations(obj metav1.Object) metav1.Object { diff --git a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/staticpodstate/staticpodstate_controller.go b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/staticpodstate/staticpodstate_controller.go index 72176a4c2b..3a7c323203 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/staticpodstate/staticpodstate_controller.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controller/staticpodstate/staticpodstate_controller.go @@ -7,6 +7,7 @@ import ( "time" operatorv1 "github.com/openshift/api/operator/v1" + applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,9 +26,10 @@ import ( // StaticPodStateController is a controller that watches static pods and will produce a failing status if the // // static pods start crashing for some reason. type StaticPodStateController struct { - targetNamespace string - staticPodName string - operandName string + controllerInstanceName string + targetNamespace string + staticPodName string + operandName string operatorClient v1helpers.StaticPodOperatorClient podsGetter corev1client.PodsGetter @@ -37,7 +39,7 @@ type StaticPodStateController struct { // NewStaticPodStateController creates a controller that watches static pods and will produce a failing status if the // static pods start crashing for some reason. func NewStaticPodStateController( - targetNamespace, staticPodName, operandName string, + instanceName, targetNamespace, staticPodName, operandName string, kubeInformersForTargetNamespace informers.SharedInformerFactory, operatorClient v1helpers.StaticPodOperatorClient, podsGetter corev1client.PodsGetter, @@ -45,12 +47,13 @@ func NewStaticPodStateController( eventRecorder events.Recorder, ) factory.Controller { c := &StaticPodStateController{ - targetNamespace: targetNamespace, - staticPodName: staticPodName, - operandName: operandName, - operatorClient: operatorClient, - podsGetter: podsGetter, - versionRecorder: versionRecorder, + controllerInstanceName: factory.ControllerInstanceName(instanceName, "StaticPodState"), + targetNamespace: targetNamespace, + staticPodName: staticPodName, + operandName: operandName, + operatorClient: operatorClient, + podsGetter: podsGetter, + versionRecorder: versionRecorder, } return factory.New(). WithInformers( @@ -60,7 +63,7 @@ func NewStaticPodStateController( WithSync(c.sync). ResyncEvery(time.Minute). ToController( - "StaticPodStateController", // don't change what is passed here unless you also remove the old FooDegraded condition + c.controllerInstanceName, eventRecorder, ) } @@ -162,25 +165,25 @@ func (c *StaticPodStateController) sync(ctx context.Context, syncCtx factory.Syn } // update failing condition - cond := operatorv1.OperatorCondition{ - Type: condition.StaticPodsDegradedConditionType, - Status: operatorv1.ConditionFalse, - } + cond := applyoperatorv1.OperatorCondition(). + WithType(condition.StaticPodsDegradedConditionType). + WithStatus(operatorv1.ConditionFalse) // Failing errors if failingErrorCount > 0 { - cond.Status = operatorv1.ConditionTrue - cond.Reason = "Error" - cond.Message = v1helpers.NewMultiLineAggregate(errs).Error() + cond = cond.WithStatus(operatorv1.ConditionTrue). + WithReason("Error"). + WithMessage(v1helpers.NewMultiLineAggregate(errs).Error()) } // Not failing errors if failingErrorCount == 0 && len(errs) > 0 { - cond.Reason = "Error" - cond.Message = v1helpers.NewMultiLineAggregate(errs).Error() + cond = cond.WithReason("Error"). + WithMessage(v1helpers.NewMultiLineAggregate(errs).Error()) } - if _, _, updateError := v1helpers.UpdateStaticPodStatus(ctx, c.operatorClient, v1helpers.UpdateStaticPodConditionFn(cond), v1helpers.UpdateStaticPodConditionFn(cond)); updateError != nil { + + status := applyoperatorv1.StaticPodOperatorStatus().WithConditions(cond) + if updateError := c.operatorClient.ApplyStaticPodOperatorStatus(ctx, c.controllerInstanceName, status); updateError != nil { return updateError } - return err } diff --git a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controllers.go b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controllers.go index 1c6a23cffa..6a1c693c55 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controllers.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/staticpod/controllers.go @@ -285,6 +285,7 @@ func (b *staticPodOperatorControllerBuilder) ToControllers() (manager.Controller if len(b.operandName) > 0 { // TODO add handling for operator configmap changes to get version-mapping changes manager.WithController(staticpodstate.NewStaticPodStateController( + b.operandName, b.operandNamespace, b.staticPodName, b.operandName, diff --git a/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/canonicalize.go b/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/canonicalize.go index d4747ef4c7..b6a59e243e 100644 --- a/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/canonicalize.go +++ b/vendor/github.com/openshift/library-go/pkg/operator/v1helpers/canonicalize.go @@ -2,14 +2,15 @@ package v1helpers import ( "fmt" - operatorv1 "github.com/openshift/api/operator/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/json" - "k8s.io/utils/ptr" "slices" "strings" + operatorv1 "github.com/openshift/api/operator/v1" applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/json" + "k8s.io/utils/clock" + "k8s.io/utils/ptr" ) // ToStaticPodOperator returns the equivalent typed kind for the applyconfiguration. Due to differences in serialization like @@ -32,12 +33,12 @@ func ToStaticPodOperator(in *applyoperatorv1.StaticPodOperatorStatusApplyConfigu return ret, nil } -func SetApplyConditionsLastTransitionTime(newConditions *[]applyoperatorv1.OperatorConditionApplyConfiguration, oldConditions []applyoperatorv1.OperatorConditionApplyConfiguration) { +func SetApplyConditionsLastTransitionTime(clock clock.PassiveClock, newConditions *[]applyoperatorv1.OperatorConditionApplyConfiguration, oldConditions []applyoperatorv1.OperatorConditionApplyConfiguration) { if newConditions == nil { return } - now := metav1.Now() + now := metav1.NewTime(clock.Now()) for i := range *newConditions { newCondition := (*newConditions)[i] diff --git a/vendor/modules.txt b/vendor/modules.txt index 30ead574d5..003ca8c1e2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -349,7 +349,7 @@ github.com/openshift/client-go/security/informers/externalversions/internalinter github.com/openshift/client-go/security/informers/externalversions/security github.com/openshift/client-go/security/informers/externalversions/security/v1 github.com/openshift/client-go/security/listers/security/v1 -# github.com/openshift/library-go v0.0.0-20241001171606-756adf2188fc +# github.com/openshift/library-go v0.0.0-20241001171606-756adf2188fc => github.com/rexagod/library-go v0.0.0-20241011095547-5a2eb4344baa ## explicit; go 1.22.0 github.com/openshift/library-go/pkg/assets github.com/openshift/library-go/pkg/authorization/hardcodedauthorizer @@ -1541,3 +1541,4 @@ sigs.k8s.io/structured-merge-diff/v4/value ## explicit; go 1.12 sigs.k8s.io/yaml sigs.k8s.io/yaml/goyaml.v2 +# github.com/openshift/library-go => github.com/rexagod/library-go v0.0.0-20241011095547-5a2eb4344baa