From 0087deb1401c53cf9d07fd34b4974b0876a5f1c3 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Fri, 29 May 2026 13:28:26 +0200 Subject: [PATCH] Allow for a custom healthcheck field in the operator configmap By populating the `gitops.customHealthChecks` in the `patterns-operator-config` it is possible to customize the healthchecks in the argocd clusterwide hub instance. Tested as follows: 1. Observe stock argocd healthcheck: ```sh oc get argocd -n vp-gitops vp-gitops -o jsonpath='{.spec.resourceHealthChecks}' | jq -r '.[].kind' Subscription ``` 2. Patch operator configmap ```sh cat > custom-hc.yaml - group: app kind: Deployment check: | hs = {} if obj.status ~= nil then if obj.status.readyReplicas == obj.status.replicas then hs.status = "Healthy" else hs.status = "Progressing" end end return hs - group: batch kind: Job check: | hs = {} if obj.status ~= nil and obj.status.succeeded ~= nil and obj.status.succeeded > 0 then hs.status = "Healthy" else hs.status = "Progressing" end return hs oc patch configmap patterns-operator-config \ -n patterns-operator \ --type merge \ -p "$(jq -n --arg v "$(cat ~/custom-hc.yaml)" '{"data":{"gitops.customHealthChecks":$v}}')" ``` 3. Observe the change (no pod restarts needed): ```sh oc get argocd -n vp-gitops vp-gitops -o jsonpath='{.spec.resourceHealthChecks}' | jq -r '.[].kind' Subscription Deployment Job ``` 4. Edit the configmap and remove the Job healthcheck: ```sh oc get argocd -n vp-gitops vp-gitops -o jsonpath='{.spec.resourceHealthChecks}' | jq -r '.[].kind' Subscription Deployment ``` --- internal/controller/argo.go | 10 ++++ internal/controller/argo_test.go | 50 +++++++++++++++++++ .../controller/patterns_operator_config.go | 1 + 3 files changed, 61 insertions(+) diff --git a/internal/controller/argo.go b/internal/controller/argo.go index 37d20580f..bc4cd9c3c 100644 --- a/internal/controller/argo.go +++ b/internal/controller/argo.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/yaml" argooperator "github.com/argoproj-labs/argocd-operator/api/v1beta1" argoapi "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" @@ -192,6 +193,15 @@ return health_status`, }) } + if customChecksYAML := patternsOperatorConfig.getStringValue("gitops.customHealthChecks"); customChecksYAML != "" { + var customChecks []argooperator.ResourceHealthCheck + if err := yaml.Unmarshal([]byte(customChecksYAML), &customChecks); err != nil { + log.Printf("Failed to parse gitops.customHealthChecks: %v", err) + } else { + resourceHealthChecks = append(resourceHealthChecks, customChecks...) + } + } + trueBool := true initVolumes := []v1.Volume{ { diff --git a/internal/controller/argo_test.go b/internal/controller/argo_test.go index 0e8afa6a2..cf2d6d035 100644 --- a/internal/controller/argo_test.go +++ b/internal/controller/argo_test.go @@ -2241,6 +2241,56 @@ var _ = Describe("newArgoCD", func() { Expect(argo.Spec.ResourceHealthChecks[1].Kind).To(Equal("Application")) }) + It("should append custom health checks from gitops.customHealthChecks", func() { + customYAML := `- group: apps + kind: Deployment + check: | + hs = {} + hs.status = "Healthy" + return hs +- group: batch + kind: Job + check: | + hs = {} + hs.status = "Progressing" + return hs` + argo = newArgoCD("test-argo", "test-ns", PatternsOperatorConfig{"gitops.customHealthChecks": customYAML}) + Expect(argo.Spec.ResourceHealthChecks).To(HaveLen(3)) + Expect(argo.Spec.ResourceHealthChecks[0].Group).To(Equal("operators.coreos.com")) + Expect(argo.Spec.ResourceHealthChecks[1].Group).To(Equal("apps")) + Expect(argo.Spec.ResourceHealthChecks[1].Kind).To(Equal("Deployment")) + Expect(argo.Spec.ResourceHealthChecks[2].Group).To(Equal("batch")) + Expect(argo.Spec.ResourceHealthChecks[2].Kind).To(Equal("Job")) + }) + + It("should append custom health checks alongside Application health check when both are enabled", func() { + customYAML := `- group: apps + kind: Deployment + check: | + hs = {} + hs.status = "Healthy" + return hs` + argo = newArgoCD("test-argo", "test-ns", PatternsOperatorConfig{ + "gitops.applicationHealthCheckEnabled": "true", + "gitops.customHealthChecks": customYAML, + }) + Expect(argo.Spec.ResourceHealthChecks).To(HaveLen(3)) + Expect(argo.Spec.ResourceHealthChecks[0].Group).To(Equal("operators.coreos.com")) + Expect(argo.Spec.ResourceHealthChecks[1].Group).To(Equal("argoproj.io")) + Expect(argo.Spec.ResourceHealthChecks[2].Group).To(Equal("apps")) + }) + + It("should handle invalid YAML in gitops.customHealthChecks gracefully", func() { + argo = newArgoCD("test-argo", "test-ns", PatternsOperatorConfig{"gitops.customHealthChecks": "not: valid: yaml: list"}) + Expect(argo.Spec.ResourceHealthChecks).To(HaveLen(1)) + Expect(argo.Spec.ResourceHealthChecks[0].Group).To(Equal("operators.coreos.com")) + }) + + It("should not add custom health checks when gitops.customHealthChecks is empty", func() { + argo = newArgoCD("test-argo", "test-ns", PatternsOperatorConfig{"gitops.customHealthChecks": ""}) + Expect(argo.Spec.ResourceHealthChecks).To(HaveLen(1)) + }) + }) var _ = Describe("commonSyncPolicy", func() { diff --git a/internal/controller/patterns_operator_config.go b/internal/controller/patterns_operator_config.go index 09f1be048..28bed07c0 100644 --- a/internal/controller/patterns_operator_config.go +++ b/internal/controller/patterns_operator_config.go @@ -20,6 +20,7 @@ var DefaultPatternsOperatorConfig = PatternsOperatorConfig{ "gitops.csv": GitOpsDefaultCSV, "gitops.additionalArgoAdmins": "", "gitops.applicationHealthCheckEnabled": "false", + "gitops.customHealthChecks": "", "gitea.chartName": GiteaChartName, "gitea.helmRepoUrl": GiteaHelmRepoUrl, "gitea.chartVersion": GiteaDefaultChartVersion,