From 0b9a3a0bcf9b1ba62807af761c22f51fcdd70375 Mon Sep 17 00:00:00 2001 From: reggie-k Date: Thu, 4 Sep 2025 16:17:37 +0300 Subject: [PATCH 1/3] get clusterinfo from cache Signed-off-by: reggie-k --- server/application/application.go | 10 ++++++++-- server/application/application_test.go | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/server/application/application.go b/server/application/application.go index 4697928825793..a55082a243a57 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -474,10 +474,16 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan return fmt.Errorf("error getting application cluster config: %w", err) } - serverVersion, err := s.kubectl.GetServerVersion(config) + var ci v1alpha1.ClusterInfo + destCluster, err := argo.GetDestinationCluster(ctx, a.Spec.Destination, s.db) if err != nil { - return fmt.Errorf("error getting server version: %w", err) + return fmt.Errorf("error getting destination cluster: %w", err) + } + getClusterInfoErr := s.cache.GetClusterInfo(destCluster.Server, &ci) + if getClusterInfoErr != nil { + return fmt.Errorf("error getting server version: %w", getClusterInfoErr) } + serverVersion := ci.ServerVersion apiResources, err := s.kubectl.GetAPIResources(config, false, kubecache.NewNoopSettings()) if err != nil { diff --git a/server/application/application_test.go b/server/application/application_test.go index 84d082f134c40..b5edb107cfbc7 100644 --- a/server/application/application_test.go +++ b/server/application/application_test.go @@ -287,6 +287,13 @@ func newTestAppServerWithEnforcerConfigure(t *testing.T, f func(*rbac.Enforcer), } appCache := servercache.NewCache(appStateCache, time.Hour, time.Hour, time.Hour) + // Seed cluster info so server version lookup in GetManifests succeeds + + require.NoError(t, appCache.SetClusterInfo( + fakeCluster().Server, + &v1alpha1.ClusterInfo{ServerVersion: "v1.27.0"}, + )) + kubectl := &kubetest.MockKubectlCmd{} kubectl = kubectl.WithGetResourceFunc(func(_ context.Context, _ *rest.Config, gvk schema.GroupVersionKind, name string, namespace string) (*unstructured.Unstructured, error) { for _, obj := range objects { @@ -450,6 +457,13 @@ func newTestAppServerWithEnforcerConfigureWithBenchmark(b *testing.B, f func(*rb } appCache := servercache.NewCache(appStateCache, time.Hour, time.Hour, time.Hour) + // Seed cluster info so server version lookup in GetManifests succeeds + + require.NoError(b, appCache.SetClusterInfo( + fakeCluster().Server, + &v1alpha1.ClusterInfo{ServerVersion: "v1.27.0"}, + )) + kubectl := &kubetest.MockKubectlCmd{} kubectl = kubectl.WithGetResourceFunc(func(_ context.Context, _ *rest.Config, gvk schema.GroupVersionKind, name string, namespace string) (*unstructured.Unstructured, error) { for _, obj := range objects { From cf9887c5493fb7fe2616cca5a0a4bacff15b6f70 Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Mon, 8 Sep 2025 12:09:07 +0300 Subject: [PATCH 2/3] added tracing --- server/application/application.go | 21 +++++++++++++++++++++ util/argo/argo.go | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/server/application/application.go b/server/application/application.go index a55082a243a57..23ffc0dc05f37 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -13,6 +13,7 @@ import ( "time" "github.com/argoproj/gitops-engine/pkg/health" + "go.opentelemetry.io/otel" cacheutil "github.com/argoproj/argo-cd/v3/util/cache" @@ -412,6 +413,9 @@ func (s *Server) queryRepoServer(ctx context.Context, proj *v1alpha1.AppProject, enabledSourceTypes map[string]bool, ) error, ) error { + ctx, span := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "queryRepoServer") + defer span.End() + closer, client, err := s.repoClientset.NewRepoServerClient() if err != nil { return fmt.Errorf("error creating repo server client: %w", err) @@ -448,6 +452,9 @@ func (s *Server) queryRepoServer(ctx context.Context, proj *v1alpha1.AppProject, // GetManifests returns application manifests func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationManifestQuery) (*apiclient.ManifestResponse, error) { + ctx, span := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "Server.GetManifests") + defer span.End() + if q.Name == nil || *q.Name == "" { return nil, errors.New("invalid request: application name is missing") } @@ -485,7 +492,9 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan } serverVersion := ci.ServerVersion + _, kubectlSpan := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "kubectl.GetAPIResources") apiResources, err := s.kubectl.GetAPIResources(config, false, kubecache.NewNoopSettings()) + kubectlSpan.End() if err != nil { return fmt.Errorf("error getting API resources: %w", err) } @@ -1364,6 +1373,9 @@ func (s *Server) getCachedAppState(ctx context.Context, a *v1alpha1.Application, } func (s *Server) getAppResources(ctx context.Context, a *v1alpha1.Application) (*v1alpha1.ApplicationTree, error) { + ctx, span := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "Server.getAppResources") + defer span.End() + var tree v1alpha1.ApplicationTree err := s.getCachedAppState(ctx, a, func() error { return s.cache.GetAppResourcesTree(a.InstanceName(s.ns), &tree) @@ -1378,6 +1390,9 @@ func (s *Server) getAppResources(ctx context.Context, a *v1alpha1.Application) ( } func (s *Server) getAppLiveResource(ctx context.Context, action string, q *application.ApplicationResourceRequest) (*v1alpha1.ResourceNode, *rest.Config, *v1alpha1.Application, error) { + ctx, span := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "Server.getAppLiveResource") + defer span.End() + fineGrainedInheritanceDisabled, err := s.settingsMgr.ApplicationFineGrainedRBACInheritanceDisabled() if err != nil { return nil, nil, nil, err @@ -1412,6 +1427,9 @@ func (s *Server) getAppLiveResource(ctx context.Context, action string, q *appli } func (s *Server) GetResource(ctx context.Context, q *application.ApplicationResourceRequest) (*application.ApplicationResourceResponse, error) { + ctx, span := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "Server.GetResource") + defer span.End() + res, config, _, err := s.getAppLiveResource(ctx, rbac.ActionGet, q) if err != nil { return nil, err @@ -1421,7 +1439,10 @@ func (s *Server) GetResource(ctx context.Context, q *application.ApplicationReso if q.GetVersion() != "" { res.Version = q.GetVersion() } + + _, kubectlSpan := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "kbuectl.GetResource") obj, err := s.kubectl.GetResource(ctx, config, res.GroupKindVersion(), res.Name, res.Namespace) + kubectlSpan.End() if err != nil { return nil, fmt.Errorf("error getting resource: %w", err) } diff --git a/util/argo/argo.go b/util/argo/argo.go index aa8792357f3f5..d28404659b45b 100644 --- a/util/argo/argo.go +++ b/util/argo/argo.go @@ -15,6 +15,7 @@ import ( "github.com/argoproj/gitops-engine/pkg/utils/kube" "github.com/r3labs/diff/v3" log "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -457,6 +458,9 @@ func validateRepo(ctx context.Context, // This function also validates the references use allowed characters and does not define the same ref key more than // once (which would lead to ambiguous references). func GetRefSources(ctx context.Context, sources argoappv1.ApplicationSources, project string, getRepository func(ctx context.Context, url string, project string) (*argoappv1.Repository, error), revisions []string, isRollback bool) (argoappv1.RefTargetRevisionMapping, error) { + ctx, span := otel.GetTracerProvider().Tracer("argocd-server").Start(ctx, "GetRefSources") + defer span.End() + refSources := make(argoappv1.RefTargetRevisionMapping) if len(sources) > 1 { // Validate first to avoid unnecessary DB calls. From 1a285ce7524d663847e1fd4b6419a57bb33da868 Mon Sep 17 00:00:00 2001 From: Noam Gal Date: Mon, 8 Sep 2025 12:57:05 +0300 Subject: [PATCH 3/3] switch over to our tracer init func --- cmd/argocd-server/commands/argocd_server.go | 9 ++++---- util/trace/trace.go | 25 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/cmd/argocd-server/commands/argocd_server.go b/cmd/argocd-server/commands/argocd_server.go index c17aed5c9bd18..fc3032f3d6984 100644 --- a/cmd/argocd-server/commands/argocd_server.go +++ b/cmd/argocd-server/commands/argocd_server.go @@ -270,10 +270,11 @@ func NewCommand() *cobra.Command { lns, err := argocd.Listen() errors.CheckError(err) if otlpAddress != "" { - closer, err = traceutil.InitTracer(serverCtx, "argocd-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) - if err != nil { - log.Fatalf("failed to initialize tracing: %v", err) - } + // closer, err = traceutil.InitTracer(serverCtx, "argocd-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) + // if err != nil { + // log.Fatalf("failed to initialize tracing: %v", err) + // } + traceutil.InitGlobalTraceProvider(serverCtx) } argocd.Run(serverCtx, lns) if closer != nil { diff --git a/util/trace/trace.go b/util/trace/trace.go index 9d281bf0d4c76..4aa5e1cdfb079 100644 --- a/util/trace/trace.go +++ b/util/trace/trace.go @@ -76,3 +76,28 @@ func InitTracer(ctx context.Context, serviceName, otlpAddress string, otlpInsecu } }, nil } + +func InitGlobalTraceProvider(ctx context.Context) (func(), error) { + exporter, err := otlptracegrpc.New(ctx) + if err != nil { + return nil, err + } + + tp := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(exporter), + sdktrace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceNameKey.String("argocd-server"))), + ) + + // set the global tracer provider + otel.SetTracerProvider(tp) + // set the global propagator to use TraceContext and Baggage + otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator( + propagation.TraceContext{}, + propagation.Baggage{}, + )) + return func() { + if err := exporter.Shutdown(ctx); err != nil { + log.Errorf("failed to stop exporter: %v", err) + } + }, nil +}