diff --git a/cmd/main.go b/cmd/main.go index b8188608d..c9c3ace58 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -30,6 +30,7 @@ import ( intController "github.com/splunk/splunk-operator/internal/controller" "github.com/splunk/splunk-operator/internal/controller/debug" "github.com/splunk/splunk-operator/pkg/config" + splcommon "github.com/splunk/splunk-operator/pkg/splunk/common" "github.com/splunk/splunk-operator/pkg/splunk/enterprise/validation" "sigs.k8s.io/controller-runtime/pkg/certwatcher" @@ -198,8 +199,10 @@ func main() { os.Exit(1) } + controllerClient := splcommon.NewAPIAwareClient(mgr.GetClient(), mgr.GetAPIReader()) + if err = (&intController.ClusterManagerReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("clustermanager-controller"), }).SetupWithManager(mgr); err != nil { @@ -209,7 +212,7 @@ func main() { } fmt.Printf("%v", err) if err = (&intController.ClusterMasterReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("clustermaster-controller"), }).SetupWithManager(mgr); err != nil { @@ -217,7 +220,7 @@ func main() { os.Exit(1) } if err = (&intController.IndexerClusterReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("indexercluster-controller"), }).SetupWithManager(mgr); err != nil { @@ -225,7 +228,7 @@ func main() { os.Exit(1) } if err = (&intController.LicenseMasterReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("licensemaster-controller"), }).SetupWithManager(mgr); err != nil { @@ -233,7 +236,7 @@ func main() { os.Exit(1) } if err = (&intController.LicenseManagerReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("licensemanager-controller"), }).SetupWithManager(mgr); err != nil { @@ -241,7 +244,7 @@ func main() { os.Exit(1) } if err = (&intController.MonitoringConsoleReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("monitoringconsole-controller"), }).SetupWithManager(mgr); err != nil { @@ -249,7 +252,7 @@ func main() { os.Exit(1) } if err = (&intController.SearchHeadClusterReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("searchheadcluster-controller"), }).SetupWithManager(mgr); err != nil { @@ -257,7 +260,7 @@ func main() { os.Exit(1) } if err = (&intController.StandaloneReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("standalone-controller"), }).SetupWithManager(mgr); err != nil { @@ -265,7 +268,7 @@ func main() { os.Exit(1) } if err := (&controller.IngestorClusterReconciler{ - Client: mgr.GetClient(), + Client: controllerClient, Scheme: mgr.GetScheme(), Recorder: mgr.GetEventRecorderFor("ingestorcluster-controller"), }).SetupWithManager(mgr); err != nil { diff --git a/pkg/splunk/common/client.go b/pkg/splunk/common/client.go new file mode 100644 index 000000000..a7d2a2764 --- /dev/null +++ b/pkg/splunk/common/client.go @@ -0,0 +1,63 @@ +// Copyright (c) 2018-2022 Splunk Inc. All rights reserved. + +// +// 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 common + +import "sigs.k8s.io/controller-runtime/pkg/client" + +// APIReaderProvider exposes a direct API reader alongside a controller client. +type APIReaderProvider interface { + GetAPIReader() client.Reader +} + +// APIAwareClient keeps the standard controller client behavior while exposing a +// direct API reader for code paths that need a live read before a write. +type APIAwareClient struct { + client.Client + apiReader client.Reader +} + +// NewAPIAwareClient returns a client wrapper that exposes the provided API reader. +func NewAPIAwareClient(baseClient client.Client, apiReader client.Reader) client.Client { + if baseClient == nil || apiReader == nil { + return baseClient + } + + return &APIAwareClient{ + Client: baseClient, + apiReader: apiReader, + } +} + +// GetAPIReader returns the live API reader associated with the wrapped client. +func (c *APIAwareClient) GetAPIReader() client.Reader { + if c.apiReader != nil { + return c.apiReader + } + + return c.Client +} + +// ResolveAPIReader returns a live API reader when one is available, otherwise +// it falls back to the provided client. +func ResolveAPIReader(baseClient client.Client) client.Reader { + if provider, ok := baseClient.(APIReaderProvider); ok { + if apiReader := provider.GetAPIReader(); apiReader != nil { + return apiReader + } + } + + return baseClient +} diff --git a/pkg/splunk/enterprise/util.go b/pkg/splunk/enterprise/util.go index fd7900787..4a373de80 100644 --- a/pkg/splunk/enterprise/util.go +++ b/pkg/splunk/enterprise/util.go @@ -2261,10 +2261,11 @@ func isAppFrameworkMigrationNeeded(afwStatusContext *enterpriseApi.AppDeployment func updateCRStatus(ctx context.Context, client splcommon.ControllerClient, origCR splcommon.MetaObject, crError *error) { reqLogger := log.FromContext(ctx) scopedLog := reqLogger.WithName("updateCRStatus").WithValues("original cr version", origCR.GetResourceVersion()) + liveReader := splcommon.ResolveAPIReader(client) var tryCnt int for tryCnt = 0; tryCnt < maxRetryCountForCRStatusUpdate; tryCnt++ { - latestCR, err := fetchCurrentCRWithStatusUpdate(ctx, client, origCR, crError) + latestCR, err := fetchCurrentCRWithStatusUpdate(ctx, liveReader, origCR, crError) if err != nil { if origCR.GetDeletionTimestamp() == nil { scopedLog.Error(err, "Unable to Read the latest CR from the K8s") @@ -2315,14 +2316,14 @@ func updateCRStatus(ctx context.Context, client splcommon.ControllerClient, orig // fetchCurrentCRWithStatusUpdate returns a CR (fresh Read) with latest status copied // Use this API to update the CR status message with an error if any. This aviods multiple // hops of CR specific logic to determine CR type. -func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.ControllerClient, origCR splcommon.MetaObject, crError *error) (splcommon.MetaObject, error) { +func fetchCurrentCRWithStatusUpdate(ctx context.Context, reader client.Reader, origCR splcommon.MetaObject, crError *error) (splcommon.MetaObject, error) { namespacedName := types.NamespacedName{Name: origCR.GetName(), Namespace: origCR.GetNamespace()} var err error switch origCR.GetObjectKind().GroupVersionKind().Kind { case "Standalone": latestStdlnCR := &enterpriseApi.Standalone{} - err = client.Get(ctx, namespacedName, latestStdlnCR) + err = reader.Get(ctx, namespacedName, latestStdlnCR) if err != nil { return nil, err } @@ -2337,7 +2338,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "IngestorCluster": latestIngCR := &enterpriseApi.IngestorCluster{} - err = client.Get(ctx, namespacedName, latestIngCR) + err = reader.Get(ctx, namespacedName, latestIngCR) if err != nil { return nil, err } @@ -2351,7 +2352,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "Queue": latestQueueCR := &enterpriseApi.Queue{} - err = client.Get(ctx, namespacedName, latestQueueCR) + err = reader.Get(ctx, namespacedName, latestQueueCR) if err != nil { return nil, err } @@ -2365,7 +2366,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "ObjectStorage": latestOsCR := &enterpriseApi.ObjectStorage{} - err = client.Get(ctx, namespacedName, latestOsCR) + err = reader.Get(ctx, namespacedName, latestOsCR) if err != nil { return nil, err } @@ -2379,7 +2380,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "LicenseMaster": latestLmCR := &enterpriseApiV3.LicenseMaster{} - err = client.Get(ctx, namespacedName, latestLmCR) + err = reader.Get(ctx, namespacedName, latestLmCR) if err != nil { return nil, err } @@ -2388,7 +2389,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "LicenseManager": latestLmCR := &enterpriseApi.LicenseManager{} - err = client.Get(ctx, namespacedName, latestLmCR) + err = reader.Get(ctx, namespacedName, latestLmCR) if err != nil { return nil, err } @@ -2403,7 +2404,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "SearchHeadCluster": latestShcCR := &enterpriseApi.SearchHeadCluster{} - err = client.Get(ctx, namespacedName, latestShcCR) + err = reader.Get(ctx, namespacedName, latestShcCR) if err != nil { return nil, err } @@ -2418,7 +2419,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "IndexerCluster": latestIdxcCR := &enterpriseApi.IndexerCluster{} - err = client.Get(ctx, namespacedName, latestIdxcCR) + err = reader.Get(ctx, namespacedName, latestIdxcCR) if err != nil { return nil, err } @@ -2433,7 +2434,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "ClusterMaster": latestCmCR := &enterpriseApiV3.ClusterMaster{} - err = client.Get(ctx, namespacedName, latestCmCR) + err = reader.Get(ctx, namespacedName, latestCmCR) if err != nil { return nil, err } @@ -2442,7 +2443,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "ClusterManager": latestCmCR := &enterpriseApi.ClusterManager{} - err = client.Get(ctx, namespacedName, latestCmCR) + err = reader.Get(ctx, namespacedName, latestCmCR) if err != nil { return nil, err } @@ -2457,7 +2458,7 @@ func fetchCurrentCRWithStatusUpdate(ctx context.Context, client splcommon.Contro case "MonitoringConsole": latestMcCR := &enterpriseApi.MonitoringConsole{} - err = client.Get(ctx, namespacedName, latestMcCR) + err = reader.Get(ctx, namespacedName, latestMcCR) if err != nil { return nil, err }