From e34d86ff07e82bfb9e39597f55662289b3452411 Mon Sep 17 00:00:00 2001 From: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> Date: Thu, 21 Nov 2024 07:01:11 -0500 Subject: [PATCH 1/4] test: more destination check tests (#20617) Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> --- pkg/apis/application/v1alpha1/types_test.go | 56 ++++++++++++++++++--- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/pkg/apis/application/v1alpha1/types_test.go b/pkg/apis/application/v1alpha1/types_test.go index 83f7028484395f..1d29219d05d9ef 100644 --- a/pkg/apis/application/v1alpha1/types_test.go +++ b/pkg/apis/application/v1alpha1/types_test.go @@ -107,12 +107,16 @@ func TestAppProject_IsNegatedSourcePermitted(t *testing.T) { } func TestAppProject_IsDestinationPermitted(t *testing.T) { + t.Parallel() + testData := []struct { + name string projDest []ApplicationDestination appDest ApplicationDestination isPermitted bool }{ { + name: "server an namespace match", projDest: []ApplicationDestination{{ Server: "https://kubernetes.default.svc", Namespace: "default", }}, @@ -120,6 +124,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: true, }, { + name: "namespace does not match", projDest: []ApplicationDestination{{ Server: "https://kubernetes.default.svc", Namespace: "default", }}, @@ -127,6 +132,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: false, }, { + name: "server does not match", projDest: []ApplicationDestination{{ Server: "https://my-cluster", Namespace: "default", }}, @@ -134,6 +140,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: false, }, { + name: "wildcard namespace", projDest: []ApplicationDestination{{ Server: "https://kubernetes.default.svc", Namespace: "*", }}, @@ -141,6 +148,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: true, }, { + name: "wildcard server", projDest: []ApplicationDestination{{ Server: "https://*.default.svc", Namespace: "default", }}, @@ -148,6 +156,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: true, }, { + name: "wildcard server and namespace", projDest: []ApplicationDestination{{ Server: "https://team1-*", Namespace: "default", }}, @@ -155,6 +164,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: false, }, { + name: "wildcard namespace with prefix", projDest: []ApplicationDestination{{ Server: "https://kubernetes.default.svc", Namespace: "test-*", }}, @@ -162,6 +172,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: true, }, { + name: "wildcard namespace without prefix", projDest: []ApplicationDestination{{ Server: "https://kubernetes.default.svc", Namespace: "test-*", }}, @@ -169,6 +180,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: false, }, { + name: "wildcard server and namespace", projDest: []ApplicationDestination{{ Server: "*", Namespace: "*", }}, @@ -176,6 +188,7 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: true, }, { + name: "wildcard server and namespace with name", projDest: []ApplicationDestination{{ Server: "", Namespace: "*", Name: "test", }}, @@ -183,24 +196,51 @@ func TestAppProject_IsDestinationPermitted(t *testing.T) { isPermitted: true, }, { + name: "wildcard server and namespace with different name", projDest: []ApplicationDestination{{ Server: "", Namespace: "*", Name: "test2", }}, appDest: ApplicationDestination{Name: "test", Namespace: "test"}, isPermitted: false, }, + /** + - name: host-cluster + namespace: '!{kube-system,argocd}' + server: 'https://kubernetes.default.svc' + - name: destination-cluster-01 + namespace: '*' + server: 'https://eks-cluster-endpoint.ap-southeast-1.eks.amazonaws.com' + + destination: + server: https://eks-cluster-endpoint.ap-southeast-1.eks.amazonaws.com + namespace: karpenter + */ + { + name: "negated namespace with multiple values", + projDest: []ApplicationDestination{ + {Name: "host-cluster", Server: "https://kubernetes.default.svc", Namespace: "!{kube-system,argocd}"}, + {Name: "destination-cluster-01", Server: "https://eks-cluster-endpoint.ap-southeast-1.eks.amazonaws.com", Namespace: "*"}, + }, + appDest: ApplicationDestination{Server: "https://eks-cluster-endpoint.ap-southeast-1.eks.amazonaws.com", Namespace: "kube-system"}, + isPermitted: true, + }, } for _, data := range testData { - proj := AppProject{ - Spec: AppProjectSpec{ - Destinations: data.projDest, - }, - } - permitted, _ := proj.IsDestinationPermitted(data.appDest, func(project string) ([]*Cluster, error) { - return []*Cluster{}, nil + data := data + t.Run(data.name, func(t *testing.T) { + t.Parallel() + + proj := AppProject{ + Spec: AppProjectSpec{ + Destinations: data.projDest, + }, + } + permitted, _ := proj.IsDestinationPermitted(data.appDest, func(project string) ([]*Cluster, error) { + return []*Cluster{}, nil + }) + assert.Equal(t, data.isPermitted, permitted) }) - assert.Equal(t, data.isPermitted, permitted) } } From b6cc0e6193df38265aee4230e3b9e5f75d13517d Mon Sep 17 00:00:00 2001 From: jaehanbyun Date: Thu, 21 Nov 2024 21:03:22 +0900 Subject: [PATCH 2/4] docs: Update orphaned resource number metric explanation in doc (#20702) Signed-off-by: jaehanbyun --- docs/operator-manual/metrics.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/operator-manual/metrics.md b/docs/operator-manual/metrics.md index 02a490998307a9..36d3d4dd03b375 100644 --- a/docs/operator-manual/metrics.md +++ b/docs/operator-manual/metrics.md @@ -11,6 +11,7 @@ Metrics about applications. Scraped at the `argocd-metrics:8082/metrics` endpoin | `argocd_app_condition` | gauge | Report Applications conditions. It contains the conditions currently present in the application status. | | `argocd_app_k8s_request_total` | counter | Number of Kubernetes requests executed during application reconciliation | | `argocd_app_labels` | gauge | Argo Application labels converted to Prometheus labels. Disabled by default. See section below about how to enable it. | +| `argocd_app_orphaned_resources_count` | gauge | Number of orphaned resources per application. | | `argocd_app_reconcile` | histogram | Application reconciliation performance in seconds. | | `argocd_app_sync_total` | counter | Counter for application sync history | | `argocd_cluster_api_resource_objects` | gauge | Number of k8s resource objects in the cache. | From 4a140515fea53bb398fc997bce733d6ba34f0633 Mon Sep 17 00:00:00 2001 From: ABBOUD Moncef Date: Thu, 21 Nov 2024 06:16:53 -0600 Subject: [PATCH 3/4] feat(app): add ignore-healthcheck annotation (#20462) Signed-off-by: cef --- common/common.go | 4 +++ controller/health.go | 4 +++ controller/health_test.go | 9 +++++ .../job-failed-ignore-healthcheck.yaml | 36 +++++++++++++++++++ docs/operator-manual/health.md | 13 +++++++ 5 files changed, 66 insertions(+) create mode 100644 controller/testdata/job-failed-ignore-healthcheck.yaml diff --git a/common/common.go b/common/common.go index d2e47aa5b1607a..eea862644d1663 100644 --- a/common/common.go +++ b/common/common.go @@ -185,6 +185,10 @@ const ( // AnnotationCompareOptions is a comma-separated list of options for comparison AnnotationCompareOptions = "argocd.argoproj.io/compare-options" + // AnnotationIgnoreHealthCheck when set on an Application's immediate child indicates that its health check + // can be disregarded. + AnnotationIgnoreHealthCheck = "argocd.argoproj.io/ignore-healthcheck" + // AnnotationKeyManagedBy is annotation name which indicates that k8s resource is managed by an application. AnnotationKeyManagedBy = "managed-by" // AnnotationValueManagedByArgoCD is a 'managed-by' annotation value for resources managed by Argo CD diff --git a/controller/health.go b/controller/health.go index f713a574f57d31..2081ad80716276 100644 --- a/controller/health.go +++ b/controller/health.go @@ -10,6 +10,7 @@ import ( log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/runtime/schema" + "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/util/lua" @@ -24,6 +25,9 @@ func setApplicationHealth(resources []managedResource, statuses []appv1.Resource if res.Target != nil && hookutil.Skip(res.Target) { continue } + if res.Target != nil && res.Target.GetAnnotations() != nil && res.Target.GetAnnotations()[common.AnnotationIgnoreHealthCheck] == "true" { + continue + } if res.Live != nil && (hookutil.IsHook(res.Live) || ignore.Ignore(res.Live)) { continue diff --git a/controller/health_test.go b/controller/health_test.go index efaf4b2a8fc807..8fe848ce5c398e 100644 --- a/controller/health_test.go +++ b/controller/health_test.go @@ -65,6 +65,15 @@ func TestSetApplicationHealth(t *testing.T) { healthStatus, err = setApplicationHealth(resources, resourceStatuses, nil, app, true) require.NoError(t, err) assert.Equal(t, health.HealthStatusHealthy, healthStatus.Status) + + // now we set the `argocd.argoproj.io/ignore-healthcheck: "true"` annotation on the job's target. + // The app is considered healthy + failedJob.SetAnnotations(nil) + failedJobIgnoreHealthcheck := resourceFromFile("./testdata/job-failed-ignore-healthcheck.yaml") + resources[1].Target = &failedJobIgnoreHealthcheck + healthStatus, err = setApplicationHealth(resources, resourceStatuses, nil, app, true) + require.NoError(t, err) + assert.Equal(t, health.HealthStatusHealthy, healthStatus.Status) } func TestSetApplicationHealth_ResourceHealthNotPersisted(t *testing.T) { diff --git a/controller/testdata/job-failed-ignore-healthcheck.yaml b/controller/testdata/job-failed-ignore-healthcheck.yaml new file mode 100644 index 00000000000000..62a952203bd124 --- /dev/null +++ b/controller/testdata/job-failed-ignore-healthcheck.yaml @@ -0,0 +1,36 @@ +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + argocd.argoproj.io/ignore-healthcheck: "true" + labels: + job-name: fail + name: fail + namespace: argoci-workflows + selfLink: /apis/batch/v1/namespaces/argoci-workflows/jobs/fail +spec: + backoffLimit: 0 + completions: 1 + parallelism: 1 + template: + metadata: + creationTimestamp: null + labels: + job-name: fail + spec: + containers: + - command: + - sh + - -c + - exit 1 + image: alpine:latest + imagePullPolicy: Always + name: fail + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Never + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 diff --git a/docs/operator-manual/health.md b/docs/operator-manual/health.md index c034157e7f22ef..ffce008b1f1928 100644 --- a/docs/operator-manual/health.md +++ b/docs/operator-manual/health.md @@ -229,3 +229,16 @@ App (healthy) └── CustomResource (healthy) <- This resource's health check needs to be fixed to mark the App as unhealthy └── CustomChildResource (unhealthy) ``` +## Ignoring Child Resource Health Check in Applications + +To ignore the health check of an immediate child resource within an Application, set the annotation `argocd.argoproj.io/ignore-healthcheck` to `true`. For example: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + argocd.argoproj.io/ignore-healthcheck: "true" +``` + +By doing this, the health status of the Deployment will not affect the health of its parent Application. \ No newline at end of file From c6804e9854823b9f22d85ccff6b8e8d80d2ca83e Mon Sep 17 00:00:00 2001 From: Adam Chandler <31355738+AJChandler@users.noreply.github.com> Date: Thu, 21 Nov 2024 08:07:10 -0700 Subject: [PATCH 4/4] fix: Memory leak in repo-server (#20876) Signed-off-by: Adam Chandler --- util/app/discovery/discovery.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/util/app/discovery/discovery.go b/util/app/discovery/discovery.go index 580e4cd06935db..9f477e3a35a237 100644 --- a/util/app/discovery/discovery.go +++ b/util/app/discovery/discovery.go @@ -170,6 +170,7 @@ func cmpSupports(ctx context.Context, pluginSockFilePath, appPath, repoPath, fil cfg, err := cmpClient.CheckPluginConfiguration(ctx, &empty.Empty{}) if err != nil { log.Errorf("error checking plugin configuration %s, %v", fileName, err) + io.Close(conn) return nil, nil, false } @@ -178,6 +179,7 @@ func cmpSupports(ctx context.Context, pluginSockFilePath, appPath, repoPath, fil if namedPlugin { return conn, cmpClient, true } + io.Close(conn) return nil, nil, false }