From 7a95e6e2daf74cc33961760954068e082c016135 Mon Sep 17 00:00:00 2001 From: B Rahul Date: Wed, 9 Oct 2024 07:33:28 +0530 Subject: [PATCH 1/5] feat: added methods to expose argocd instance url info in managed resources Signed-off-by: B Rahul --- .../commands/argocd_repo_server.go | 3 ++ cmd/argocd/commands/app.go | 4 +++ common/common.go | 3 ++ .../server-commands/argocd-repo-server.md | 1 + .../argocd-repo-server-deployment.yaml | 6 ++++ manifests/core-install.yaml | 6 ++++ manifests/ha/install.yaml | 6 ++++ manifests/ha/namespace-install.yaml | 6 ++++ manifests/install.yaml | 6 ++++ manifests/namespace-install.yaml | 6 ++++ reposerver/repository/repository.go | 15 ++++++++- util/argo/resource_tracking.go | 27 ++++++++++++++++ util/argo/resource_tracking_test.go | 31 +++++++++++++++++++ 13 files changed, 119 insertions(+), 1 deletion(-) diff --git a/cmd/argocd-repo-server/commands/argocd_repo_server.go b/cmd/argocd-repo-server/commands/argocd_repo_server.go index ec863c26647f0..00a6969927227 100644 --- a/cmd/argocd-repo-server/commands/argocd_repo_server.go +++ b/cmd/argocd-repo-server/commands/argocd_repo_server.go @@ -75,6 +75,7 @@ func NewCommand() *cobra.Command { helmRegistryMaxIndexSize string disableManifestMaxExtractedSize bool includeHiddenDirectories bool + argocdInstanceID string ) command := cobra.Command{ Use: cliName, @@ -136,6 +137,7 @@ func NewCommand() *cobra.Command { HelmManifestMaxExtractedSize: helmManifestMaxExtractedSizeQuantity.ToDec().Value(), HelmRegistryMaxIndexSize: helmRegistryMaxIndexSizeQuantity.ToDec().Value(), IncludeHiddenDirectories: includeHiddenDirectories, + ArgoCDInstanceID: argocdInstanceID, }, askPassServer) errors.CheckError(err) @@ -241,6 +243,7 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&helmRegistryMaxIndexSize, "helm-registry-max-index-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_INDEX_SIZE", "1G"), "Maximum size of registry index file") command.Flags().BoolVar(&disableManifestMaxExtractedSize, "disable-helm-manifest-max-extracted-size", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE", false), "Disable maximum size of helm manifest archives when extracted") command.Flags().BoolVar(&includeHiddenDirectories, "include-hidden-directories", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_INCLUDE_HIDDEN_DIRECTORIES", false), "Include hidden directories from Git") + command.Flags().StringVar(&argocdInstanceID, "argocd-instance-id", env.StringFromEnv("ARGOCD_INSTANCE_ID", ""), "Server URL of the argocd instance that the repo server is part of") tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command) cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, cacheutil.Options{ OnClientCreated: func(client *redis.Client) { diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 00c5c14834e2f..c40e513d1b15f 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -1378,6 +1378,10 @@ func groupObjsForDiff(resources *application.ManagedResourcesResponse, objs map[ errors.CheckError(err) } + if err := resourceTracking.SetAppInstanceID(local, argoSettings.URL); err != nil { + log.Warnf("Failed to set Application Instance ID due to missing or invalid ArgoCD URL in ArgoCD Configmap") + } + items = append(items, objKeyLiveTarget{key, live, local}) delete(objs, key) } diff --git a/common/common.go b/common/common.go index 2383a33f844cf..c78baae4747f0 100644 --- a/common/common.go +++ b/common/common.go @@ -179,6 +179,9 @@ const ( // AnnotationKeyAppInstance is the Argo CD application name is used as the instance name AnnotationKeyAppInstance = "argocd.argoproj.io/tracking-id" + // AnnotationKeyAppInstanceID is the Argo CD server URL that is managing this resource + AnnotationKeyAppInstanceID = "argocd.argoproj.io/instance-id" + // AnnotationCompareOptions is a comma-separated list of options for comparison AnnotationCompareOptions = "argocd.argoproj.io/compare-options" diff --git a/docs/operator-manual/server-commands/argocd-repo-server.md b/docs/operator-manual/server-commands/argocd-repo-server.md index 3532fc6c30b4a..0c51098a2d10a 100644 --- a/docs/operator-manual/server-commands/argocd-repo-server.md +++ b/docs/operator-manual/server-commands/argocd-repo-server.md @@ -17,6 +17,7 @@ argocd-repo-server [flags] ``` --address string Listen on given address for incoming connections (default "0.0.0.0") --allow-oob-symlinks Allow out-of-bounds symlinks in repositories (not recommended) + --argocd-instance-id string Server URL of the argocd instance that the repo server is part of --default-cache-expiration duration Cache expiration default (default 24h0m0s) --disable-helm-manifest-max-extracted-size Disable maximum size of helm manifest archives when extracted --disable-tls Disable TLS on the gRPC endpoint diff --git a/manifests/base/repo-server/argocd-repo-server-deployment.yaml b/manifests/base/repo-server/argocd-repo-server-deployment.yaml index 0e86acd3e3b5e..77cf16d772489 100644 --- a/manifests/base/repo-server/argocd-repo-server-deployment.yaml +++ b/manifests/base/repo-server/argocd-repo-server-deployment.yaml @@ -215,6 +215,12 @@ spec: key: reposerver.include.hidden.directories name: argocd-cmd-params-cm optional: true + - name: ARGOCD_INSTANCE_ID + valueFrom: + configMapKeyRef: + key: url + name: argocd-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml index f558902d4692d..902ad05243307 100644 --- a/manifests/core-install.yaml +++ b/manifests/core-install.yaml @@ -22923,6 +22923,12 @@ spec: key: reposerver.include.hidden.directories name: argocd-cmd-params-cm optional: true + - name: ARGOCD_INSTANCE_ID + valueFrom: + configMapKeyRef: + key: url + name: argocd-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index ba37a63431b6b..e2240c00d9fb6 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -24518,6 +24518,12 @@ spec: key: reposerver.include.hidden.directories name: argocd-cmd-params-cm optional: true + - name: ARGOCD_INSTANCE_ID + valueFrom: + configMapKeyRef: + key: url + name: argocd-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml index deefe124a2048..27873da5205a0 100644 --- a/manifests/ha/namespace-install.yaml +++ b/manifests/ha/namespace-install.yaml @@ -2311,6 +2311,12 @@ spec: key: reposerver.include.hidden.directories name: argocd-cmd-params-cm optional: true + - name: ARGOCD_INSTANCE_ID + valueFrom: + configMapKeyRef: + key: url + name: argocd-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/manifests/install.yaml b/manifests/install.yaml index 6fd35145cb0ca..66e7c5703d2f6 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -23588,6 +23588,12 @@ spec: key: reposerver.include.hidden.directories name: argocd-cmd-params-cm optional: true + - name: ARGOCD_INSTANCE_ID + valueFrom: + configMapKeyRef: + key: url + name: argocd-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 0d9c0816cfe30..63a62254589af 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -1381,6 +1381,12 @@ spec: key: reposerver.include.hidden.directories name: argocd-cmd-params-cm optional: true + - name: ARGOCD_INSTANCE_ID + valueFrom: + configMapKeyRef: + key: url + name: argocd-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 601697778cffc..beee134fe30a3 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -113,6 +113,7 @@ type RepoServerInitConstants struct { HelmRegistryMaxIndexSize int64 DisableHelmManifestMaxExtractedSize bool IncludeHiddenDirectories bool + ArgoCDInstanceID string } // NewService returns a new instance of the Manifest service @@ -805,7 +806,7 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, } } - manifestGenResult, err = GenerateManifests(ctx, opContext.appPath, repoRoot, commitSHA, q, false, s.gitCredsStore, s.initConstants.MaxCombinedDirectoryManifestsSize, s.gitRepoPaths, WithCMPTarDoneChannel(ch.tarDoneCh), WithCMPTarExcludedGlobs(s.initConstants.CMPTarExcludedGlobs)) + manifestGenResult, err = GenerateManifests(ctx, opContext.appPath, repoRoot, commitSHA, q, false, s.gitCredsStore, s.initConstants.MaxCombinedDirectoryManifestsSize, s.gitRepoPaths, WithCMPTarDoneChannel(ch.tarDoneCh), WithCMPTarExcludedGlobs(s.initConstants.CMPTarExcludedGlobs), WithArgoCDInstanceID(s.initConstants.ArgoCDInstanceID)) } refSourceCommitSHAs := make(map[string]string) if len(repoRefs) > 0 { @@ -1378,6 +1379,7 @@ type ( generateManifestOpt struct { cmpTarDoneCh chan<- bool cmpTarExcludedGlobs []string + argocdInstanceID string } ) @@ -1406,6 +1408,13 @@ func WithCMPTarExcludedGlobs(excludedGlobs []string) GenerateManifestOpt { } } +// WithArgoCDInstanceID sets the argocd instance server url which manages this resource. +func WithArgoCDInstanceID(argocdInstanceID string) GenerateManifestOpt { + return func(o *generateManifestOpt) { + o.argocdInstanceID = argocdInstanceID + } +} + // GenerateManifests generates manifests from a path. Overrides are applied as a side effect on the given ApplicationSource. func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, q *apiclient.ManifestRequest, isLocal bool, gitCredsStore git.CredsStore, maxCombinedManifestQuantity resource.Quantity, gitRepoPaths io.TempPaths, opts ...GenerateManifestOpt) (*apiclient.ManifestResponse, error) { opt := newGenerateManifestOpt(opts...) @@ -1494,6 +1503,10 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, if err != nil { return nil, fmt.Errorf("failed to set app instance tracking info on manifest: %w", err) } + if err := resourceTracking.SetAppInstanceID(target, opt.argocdInstanceID); err != nil { + log.Warnf("Failed to set Application Instance ID due to missing or invalid ArgoCD URL in ArgoCD Configmap") + } + } manifestStr, err := json.Marshal(target.Object) if err != nil { diff --git a/util/argo/resource_tracking.go b/util/argo/resource_tracking.go index e904f2aa1d466..6529de7355ffa 100644 --- a/util/argo/resource_tracking.go +++ b/util/argo/resource_tracking.go @@ -31,7 +31,9 @@ var ( type ResourceTracking interface { GetAppName(un *unstructured.Unstructured, key string, trackingMethod v1alpha1.TrackingMethod) string GetAppInstance(un *unstructured.Unstructured, key string, trackingMethod v1alpha1.TrackingMethod) *AppInstanceValue + GetAppInstanceID(un *unstructured.Unstructured) string SetAppInstance(un *unstructured.Unstructured, key, val, namespace string, trackingMethod v1alpha1.TrackingMethod) error + SetAppInstanceID(un *unstructured.Unstructured, url string) error BuildAppInstanceValue(value AppInstanceValue) string ParseAppInstanceValue(value string) (*AppInstanceValue, error) Normalize(config, live *unstructured.Unstructured, labelKey, trackingMethod string) error @@ -77,6 +79,14 @@ func (rt *resourceTracking) getAppInstanceValue(un *unstructured.Unstructured) * return value } +func (rt *resourceTracking) getAppInstanceIdValue(un *unstructured.Unstructured) string { + appInstanceIdValue, err := argokube.GetAppInstanceAnnotation(un, common.AnnotationKeyAppInstanceID) + if err != nil { + return "" + } + return appInstanceIdValue +} + // GetAppName retrieve application name base on tracking method func (rt *resourceTracking) GetAppName(un *unstructured.Unstructured, key string, trackingMethod v1alpha1.TrackingMethod) string { retrieveAppInstanceValue := func() string { @@ -118,6 +128,11 @@ func (rt *resourceTracking) GetAppInstance(un *unstructured.Unstructured, key st } } +// GetAppInstanceID retrieve instance ID of the resource. +func (rt *resourceTracking) GetAppInstanceID(un *unstructured.Unstructured) string { + return rt.getAppInstanceIdValue(un) +} + // UnstructuredToAppInstanceValue will build the AppInstanceValue based // on the provided unstructured. The given namespace works as a default // value if the resource's namespace is not defined. It should be the @@ -137,6 +152,18 @@ func UnstructuredToAppInstanceValue(un *unstructured.Unstructured, appName, name } } +// SetAppInstanceID sets the app instance ID annotation if the URL is not empty. +func (rt *resourceTracking) SetAppInstanceID(un *unstructured.Unstructured, url string) error { + if url == "" { + return fmt.Errorf("ArgoCD URL is missing") + } + err := argokube.SetAppInstanceAnnotation(un, common.AnnotationKeyAppInstanceID, url) + if err != nil { + return fmt.Errorf("failed to set app instance ID annotation: %w", err) + } + return nil +} + // SetAppInstance set label/annotation base on tracking method func (rt *resourceTracking) SetAppInstance(un *unstructured.Unstructured, key, val, namespace string, trackingMethod v1alpha1.TrackingMethod) error { setAppInstanceAnnotation := func() error { diff --git a/util/argo/resource_tracking_test.go b/util/argo/resource_tracking_test.go index 3c747edf69fcb..1fb930f117e11 100644 --- a/util/argo/resource_tracking_test.go +++ b/util/argo/resource_tracking_test.go @@ -131,6 +131,37 @@ func TestSetAppInstanceAnnotationNotFound(t *testing.T) { assert.Equal(t, "", app) } +func TestSetAppInstanceIdAnnotation(t *testing.T) { + yamlBytes, err := os.ReadFile("testdata/svc.yaml") + require.NoError(t, err) + + var obj unstructured.Unstructured + err = yaml.Unmarshal(yamlBytes, &obj) + require.NoError(t, err) + + resourceTracking := NewResourceTracking() + + err = resourceTracking.SetAppInstanceID(&obj, "argocd.com") + require.NoError(t, err) + + value := resourceTracking.GetAppInstanceID(&obj) + assert.Equal(t, "argocd.com", value) +} + +func TestSetAppInstanceIdAnnotationNotFound(t *testing.T) { + yamlBytes, err := os.ReadFile("testdata/svc.yaml") + require.NoError(t, err) + + var obj unstructured.Unstructured + err = yaml.Unmarshal(yamlBytes, &obj) + require.NoError(t, err) + + resourceTracking := NewResourceTracking() + + value := resourceTracking.GetAppInstanceID(&obj) + assert.Equal(t, "", value) +} + func TestParseAppInstanceValue(t *testing.T) { resourceTracking := NewResourceTracking() appInstanceValue, err := resourceTracking.ParseAppInstanceValue("app:/:/") From 7c119e4f95cd8e913f5bfc8b05dbc8ceaec91d85 Mon Sep 17 00:00:00 2001 From: B Rahul Date: Thu, 10 Oct 2024 17:03:51 +0530 Subject: [PATCH 2/5] fixed linting issue Signed-off-by: B Rahul --- reposerver/repository/repository.go | 1 - 1 file changed, 1 deletion(-) diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index fbcf2be14c813..9b791fa459969 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -1517,7 +1517,6 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, if err := resourceTracking.SetAppInstanceID(target, opt.argocdInstanceID); err != nil { log.Warnf("Failed to set Application Instance ID due to missing or invalid ArgoCD URL in ArgoCD Configmap") } - } manifestStr, err := json.Marshal(target.Object) if err != nil { From 9ac956b8aa493241939f5eccc6791beb064b4c98 Mon Sep 17 00:00:00 2001 From: B Rahul Date: Thu, 10 Oct 2024 17:20:40 +0530 Subject: [PATCH 3/5] format repository.go to comply with gofumpt Signed-off-by: B Rahul --- reposerver/repository/repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 9b791fa459969..4b2144bf80cb2 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -1382,7 +1382,7 @@ type ( cmpTarDoneCh chan<- bool cmpTarExcludedGlobs []string cmpUseManifestGeneratePaths bool - argocdInstanceID string + argocdInstanceID string } ) From 94d1e8a2bf6837d5a120090a19f2b7037bf5f942 Mon Sep 17 00:00:00 2001 From: B Rahul Date: Thu, 10 Oct 2024 19:19:13 +0530 Subject: [PATCH 4/5] fixing code coverage error handling Signed-off-by: B Rahul --- util/argo/resource_tracking.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/util/argo/resource_tracking.go b/util/argo/resource_tracking.go index 136c50c67a081..92f59f74bce51 100644 --- a/util/argo/resource_tracking.go +++ b/util/argo/resource_tracking.go @@ -82,12 +82,12 @@ func (rt *resourceTracking) getAppInstanceValue(un *unstructured.Unstructured, i return value } -func (rt *resourceTracking) getAppInstanceIdValue(un *unstructured.Unstructured) string { - appInstanceIdValue, err := argokube.GetAppInstanceAnnotation(un, common.AnnotationKeyAppInstanceID) - if err != nil { - return "" - } - return appInstanceIdValue +func (rt *resourceTracking) getAppInstanceIdValue(un *unstructured.Unstructured) *string { + appInstanceIdValue, err := argokube.GetAppInstanceAnnotation(un, common.AnnotationKeyAppInstanceID) + if err != nil { + return nil + } + return &appInstanceIdValue } // GetAppName retrieve application name base on tracking method @@ -133,7 +133,11 @@ func (rt *resourceTracking) GetAppInstance(un *unstructured.Unstructured, key st // GetAppInstanceID retrieve instance ID of the resource. func (rt *resourceTracking) GetAppInstanceID(un *unstructured.Unstructured) string { - return rt.getAppInstanceIdValue(un) + appInstanceIdValue := rt.getAppInstanceIdValue(un) + if appInstanceIdValue == nil { + return "" + } + return *appInstanceIdValue } // UnstructuredToAppInstanceValue will build the AppInstanceValue based From 09ec13602560c9d9da7c90ab81e0d27460da65f7 Mon Sep 17 00:00:00 2001 From: B Rahul Date: Fri, 11 Oct 2024 17:39:09 +0530 Subject: [PATCH 5/5] added test cases for resource_tracking Signed-off-by: B Rahul --- util/argo/resource_tracking.go | 18 +++++++----------- util/argo/resource_tracking_test.go | 4 ++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/util/argo/resource_tracking.go b/util/argo/resource_tracking.go index 92f59f74bce51..136c50c67a081 100644 --- a/util/argo/resource_tracking.go +++ b/util/argo/resource_tracking.go @@ -82,12 +82,12 @@ func (rt *resourceTracking) getAppInstanceValue(un *unstructured.Unstructured, i return value } -func (rt *resourceTracking) getAppInstanceIdValue(un *unstructured.Unstructured) *string { - appInstanceIdValue, err := argokube.GetAppInstanceAnnotation(un, common.AnnotationKeyAppInstanceID) - if err != nil { - return nil - } - return &appInstanceIdValue +func (rt *resourceTracking) getAppInstanceIdValue(un *unstructured.Unstructured) string { + appInstanceIdValue, err := argokube.GetAppInstanceAnnotation(un, common.AnnotationKeyAppInstanceID) + if err != nil { + return "" + } + return appInstanceIdValue } // GetAppName retrieve application name base on tracking method @@ -133,11 +133,7 @@ func (rt *resourceTracking) GetAppInstance(un *unstructured.Unstructured, key st // GetAppInstanceID retrieve instance ID of the resource. func (rt *resourceTracking) GetAppInstanceID(un *unstructured.Unstructured) string { - appInstanceIdValue := rt.getAppInstanceIdValue(un) - if appInstanceIdValue == nil { - return "" - } - return *appInstanceIdValue + return rt.getAppInstanceIdValue(un) } // UnstructuredToAppInstanceValue will build the AppInstanceValue based diff --git a/util/argo/resource_tracking_test.go b/util/argo/resource_tracking_test.go index 0356f44717a4e..9c417be895044 100644 --- a/util/argo/resource_tracking_test.go +++ b/util/argo/resource_tracking_test.go @@ -146,6 +146,10 @@ func TestSetAppInstanceIdAnnotation(t *testing.T) { value := resourceTracking.GetAppInstanceID(&obj) assert.Equal(t, "argocd.com", value) + + err = resourceTracking.SetAppInstanceID(&obj, "") + require.Error(t, err) + assert.Contains(t, err.Error(), "ArgoCD URL is missing") } func TestSetAppInstanceIdAnnotationNotFound(t *testing.T) {