From 5b79c34c72300e6e2e6336051ce6992f6d54011c Mon Sep 17 00:00:00 2001 From: Andrii Korotkov <137232734+andrii-korotkov-verkada@users.noreply.github.com> Date: Fri, 7 Feb 2025 09:26:03 -0800 Subject: [PATCH] fix: New kube applier for server side diff dry run with refactoring (#21488) (#21749) Signed-off-by: Andrii Korotkov --- cmd/argocd/commands/admin/app.go | 22 +++++++++++++++++++++- controller/appcontroller.go | 2 +- controller/state.go | 9 ++++++--- controller/sync.go | 10 ++++++---- go.mod | 2 +- go.sum | 4 ++-- util/kube/kubectl.go | 24 +++++++++++++++++++++--- 7 files changed, 58 insertions(+), 15 deletions(-) diff --git a/cmd/argocd/commands/admin/app.go b/cmd/argocd/commands/admin/app.go index b20b998b790d7..bffb68a383a71 100644 --- a/cmd/argocd/commands/admin/app.go +++ b/cmd/argocd/commands/admin/app.go @@ -10,6 +10,7 @@ import ( "sort" "time" + "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -403,7 +404,26 @@ func reconcileApplications( ) appStateManager := controller.NewAppStateManager( - argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false, 0, serverSideDiff, ignoreNormalizerOpts) + argoDB, + appClientset, + repoServerClient, + namespace, + kubeutil.NewKubectl(), + func(_ string) (kube.CleanupFunc, error) { + return func() {}, nil + }, + settingsMgr, + stateCache, + projInformer, + server, + cache, + time.Second, + argo.NewResourceTracking(), + false, + 0, + serverSideDiff, + ignoreNormalizerOpts, + ) appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(ctx, metav1.ListOptions{LabelSelector: selector}) if err != nil { diff --git a/controller/appcontroller.go b/controller/appcontroller.go index 9ef906724a27f..ff051bff3eb46 100644 --- a/controller/appcontroller.go +++ b/controller/appcontroller.go @@ -309,7 +309,7 @@ func NewApplicationController( } } stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterSharding, argo.NewResourceTracking()) - appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff, ignoreNormalizerOpts) + appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.onKubectlRun, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff, ignoreNormalizerOpts) ctrl.appInformer = appInformer ctrl.appLister = appLister ctrl.projInformer = projInformer diff --git a/controller/state.go b/controller/state.go index 5ea71e80909eb..bfd3e49e765a6 100644 --- a/controller/state.go +++ b/controller/state.go @@ -108,6 +108,7 @@ type appStateManager struct { appclientset appclientset.Interface projInformer cache.SharedIndexInformer kubectl kubeutil.Kubectl + onKubectlRun kubeutil.OnKubectlRunFunc repoClientset apiclient.Clientset liveStateCache statecache.LiveStateCache cache *appstatecache.Cache @@ -747,13 +748,13 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 diffConfigBuilder.WithServerSideDiff(serverSideDiff) if serverSideDiff { - resourceOps, cleanup, err := m.getResourceOperations(destCluster) + applier, cleanup, err := m.getServerSideDiffDryRunApplier(destCluster) if err != nil { - log.Errorf("CompareAppState error getting resource operations: %s", err) + log.Errorf("CompareAppState error getting server side diff dry run applier: %s", err) conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionUnknownError, Message: err.Error(), LastTransitionTime: &now}) } defer cleanup() - diffConfigBuilder.WithServerSideDryRunner(diff.NewK8sServerSideDryRunner(resourceOps)) + diffConfigBuilder.WithServerSideDryRunner(diff.NewK8sServerSideDryRunner(applier)) } // enable structured merge diff if application syncs with server-side apply @@ -1065,6 +1066,7 @@ func NewAppStateManager( repoClientset apiclient.Clientset, namespace string, kubectl kubeutil.Kubectl, + onKubectlRun kubeutil.OnKubectlRunFunc, settingsMgr *settings.SettingsManager, liveStateCache statecache.LiveStateCache, projInformer cache.SharedIndexInformer, @@ -1083,6 +1085,7 @@ func NewAppStateManager( db: db, appclientset: appclientset, kubectl: kubectl, + onKubectlRun: onKubectlRun, repoClientset: repoClientset, namespace: namespace, settingsMgr: settingsMgr, diff --git a/controller/sync.go b/controller/sync.go index 1ab59e35e8bc5..4f11920466502 100644 --- a/controller/sync.go +++ b/controller/sync.go @@ -14,6 +14,7 @@ import ( cdcommon "github.com/argoproj/argo-cd/v3/common" + gitopsDiff "github.com/argoproj/gitops-engine/pkg/diff" "github.com/argoproj/gitops-engine/pkg/sync" "github.com/argoproj/gitops-engine/pkg/sync/common" "github.com/argoproj/gitops-engine/pkg/utils/kube" @@ -33,6 +34,7 @@ import ( "github.com/argoproj/argo-cd/v3/util/argo" "github.com/argoproj/argo-cd/v3/util/argo/diff" "github.com/argoproj/argo-cd/v3/util/glob" + kubeutil "github.com/argoproj/argo-cd/v3/util/kube" logutils "github.com/argoproj/argo-cd/v3/util/log" "github.com/argoproj/argo-cd/v3/util/lua" "github.com/argoproj/argo-cd/v3/util/rand" @@ -66,11 +68,11 @@ func (m *appStateManager) getGVKParser(server *v1alpha1.Cluster) (*managedfields return cluster.GetGVKParser(), nil } -// getResourceOperations will return the kubectl implementation of the ResourceOperations -// interface that provides functionality to manage kubernetes resources. Returns a +// getServerSideDiffDryRunApplier will return the kubectl implementation of the KubeApplier +// interface that provides functionality to dry run apply kubernetes resources. Returns a // cleanup function that must be called to remove the generated kube config for this // server. -func (m *appStateManager) getResourceOperations(cluster *v1alpha1.Cluster) (kube.ResourceOperations, func(), error) { +func (m *appStateManager) getServerSideDiffDryRunApplier(cluster *v1alpha1.Cluster) (gitopsDiff.KubeApplier, func(), error) { clusterCache, err := m.liveStateCache.GetClusterCache(cluster) if err != nil { return nil, nil, fmt.Errorf("error getting cluster cache: %w", err) @@ -80,7 +82,7 @@ func (m *appStateManager) getResourceOperations(cluster *v1alpha1.Cluster) (kube if err != nil { return nil, nil, fmt.Errorf("error getting cluster REST config: %w", err) } - ops, cleanup, err := m.kubectl.ManageResources(rawConfig, clusterCache.GetOpenAPISchema()) + ops, cleanup, err := kubeutil.ManageServerSideDiffDryRuns(rawConfig, clusterCache.GetOpenAPISchema(), m.onKubectlRun) if err != nil { return nil, nil, fmt.Errorf("error creating kubectl ResourceOperations: %w", err) } diff --git a/go.mod b/go.mod index adf031b94ebb3..71e1fec861105 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d github.com/alicebob/miniredis/v2 v2.34.0 github.com/antonmedv/expr v1.15.1 - github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-7e21b91e9d0f + github.com/argoproj/gitops-engine v0.7.1-0.20250207161338-3ef5ab187edd github.com/argoproj/notifications-engine v0.4.1-0.20241007194503-2fef5c9049fd github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 github.com/aws/aws-sdk-go v1.55.6 diff --git a/go.sum b/go.sum index 2e13823082c5a..c45447d7e93b5 100644 --- a/go.sum +++ b/go.sum @@ -90,8 +90,8 @@ github.com/antonmedv/expr v1.15.1/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4J github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE= -github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-7e21b91e9d0f h1:6amQW2gmWyBr/3xz/YzpgrQ+91xKxtpaWiLBkgjjV8o= -github.com/argoproj/gitops-engine v0.7.1-0.20250129155113-7e21b91e9d0f/go.mod h1:WsnykM8idYRUnneeT31cM/Fq/ZsjkefCbjiD8ioCJkU= +github.com/argoproj/gitops-engine v0.7.1-0.20250207161338-3ef5ab187edd h1:aCjdkkizo+PWig7csetbazm3VSBUZYbRj37YVqpqMOE= +github.com/argoproj/gitops-engine v0.7.1-0.20250207161338-3ef5ab187edd/go.mod h1:bXZN8czlc8J79DDqt8+mqhTrtO4YZIh57s9xseacy8I= github.com/argoproj/notifications-engine v0.4.1-0.20241007194503-2fef5c9049fd h1:lOVVoK89j9Nd4+JYJiKAaMNYC1402C0jICROOfUPWn0= github.com/argoproj/notifications-engine v0.4.1-0.20241007194503-2fef5c9049fd/go.mod h1:N0A4sEws2soZjEpY4hgZpQS8mRIEw6otzwfkgc3g9uQ= github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo= diff --git a/util/kube/kubectl.go b/util/kube/kubectl.go index c1c1208113661..5c5996bcdd23e 100644 --- a/util/kube/kubectl.go +++ b/util/kube/kubectl.go @@ -3,20 +3,38 @@ package kube import ( "os" + "github.com/go-logr/logr" + "k8s.io/client-go/rest" + "k8s.io/kubectl/pkg/util/openapi" + "github.com/argoproj/argo-cd/v3/util/log" + "github.com/argoproj/gitops-engine/pkg/diff" "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/argoproj/gitops-engine/pkg/utils/tracing" ) -var tracer tracing.Tracer = &tracing.NopTracer{} +var ( + tracer tracing.Tracer = &tracing.NopTracer{} + logger logr.Logger = log.NewLogrusLogger(log.NewWithCurrentConfig()) +) func init() { if os.Getenv("ARGOCD_TRACING_ENABLED") == "1" { - tracer = tracing.NewLoggingTracer(log.NewLogrusLogger(log.NewWithCurrentConfig())) + tracer = tracing.NewLoggingTracer(logger) } } func NewKubectl() kube.Kubectl { - return &kube.KubectlCmd{Tracer: tracer, Log: log.NewLogrusLogger(log.NewWithCurrentConfig())} + return &kube.KubectlCmd{Tracer: tracer, Log: logger} +} + +func ManageServerSideDiffDryRuns(config *rest.Config, openAPISchema openapi.Resources, onKubectlRun kube.OnKubectlRunFunc) (diff.KubeApplier, func(), error) { + return kube.ManageServerSideDiffDryRuns( + config, + openAPISchema, + tracer, + logger, + onKubectlRun, + ) }