diff --git a/api/go.mod b/api/go.mod
index 65bb9357..8d729c03 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -3,7 +3,7 @@ module github.com/fluxcd/kustomize-controller/api
go 1.23.0
require (
- github.com/fluxcd/pkg/apis/kustomize v1.8.0
+ github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58
github.com/fluxcd/pkg/apis/meta v1.9.0
k8s.io/apiextensions-apiserver v0.32.0
k8s.io/apimachinery v0.32.0
diff --git a/api/go.sum b/api/go.sum
index f94d2b82..553688c2 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -3,8 +3,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fluxcd/pkg/apis/kustomize v1.8.0 h1:HH6YRa3SMS72KK4cUyb9m5sK/dZH+Eti1qhjWDCgwKg=
-github.com/fluxcd/pkg/apis/kustomize v1.8.0/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
+github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58 h1:zhTfTbXKv+R+f1gwu2ekEu0b1Q5CjinCtj1prVEVbVo=
+github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
github.com/fluxcd/pkg/apis/meta v1.9.0 h1:wPgm7bWNJZ/ImS5GqikOxt362IgLPFBG73dZ27uWRiQ=
github.com/fluxcd/pkg/apis/meta v1.9.0/go.mod h1:pMea8eEZcsFSI7ngRnTHFtDZk2CEZGgtrueNgI6Iu70=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
diff --git a/api/v1/kustomization_types.go b/api/v1/kustomization_types.go
index 8d54113a..3ec92635 100644
--- a/api/v1/kustomization_types.go
+++ b/api/v1/kustomization_types.go
@@ -179,6 +179,11 @@ type KustomizationSpec struct {
// Components specifies relative paths to specifications of other Components.
// +optional
Components []string `json:"components,omitempty"`
+
+ // HealthCheckExprs is a list of healthcheck expressions for evaluating the
+ // health of custom resources using Common Expression Language (CEL).
+ // +optional
+ HealthCheckExprs []kustomize.CustomHealthCheck `json:"healthCheckExprs,omitempty"`
}
// CommonMetadata defines the common labels and annotations.
diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go
index b270e309..a4ccb2ff 100644
--- a/api/v1/zz_generated.deepcopy.go
+++ b/api/v1/zz_generated.deepcopy.go
@@ -212,6 +212,11 @@ func (in *KustomizationSpec) DeepCopyInto(out *KustomizationSpec) {
*out = make([]string, len(*in))
copy(*out, *in)
}
+ if in.HealthCheckExprs != nil {
+ in, out := &in.HealthCheckExprs, &out.HealthCheckExprs
+ *out = make([]kustomize.CustomHealthCheck, len(*in))
+ copy(*out, *in)
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizationSpec.
diff --git a/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml b/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
index a47520a8..969764f7 100644
--- a/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
+++ b/config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
@@ -136,6 +136,41 @@ spec:
Force instructs the controller to recreate resources
when patching fails due to an immutable field change.
type: boolean
+ healthCheckExprs:
+ description: |-
+ HealthCheckExprs is a list of healthcheck expressions for evaluating the
+ health of custom resources using Common Expression Language (CEL).
+ items:
+ description: CustomHealthCheck defines the health check for custom
+ resources.
+ properties:
+ apiVersion:
+ description: APIVersion of the custom resource under evaluation.
+ type: string
+ current:
+ description: |-
+ Current is the CEL expression that determines if the status
+ of the custom resource has reached the desired state.
+ type: string
+ failed:
+ description: |-
+ Failed is the CEL expression that determines if the status
+ of the custom resource has failed to reach the desired state.
+ type: string
+ inProgress:
+ description: |-
+ InProgress is the CEL expression that determines if the status
+ of the custom resource has not yet reached the desired state.
+ type: string
+ kind:
+ description: Kind of the custom resource under evaluation.
+ type: string
+ required:
+ - apiVersion
+ - current
+ - kind
+ type: object
+ type: array
healthChecks:
description: A list of resources to be included in the health assessment.
items:
diff --git a/docs/api/v1/kustomize.md b/docs/api/v1/kustomize.md
index 25e0e636..955f3f33 100644
--- a/docs/api/v1/kustomize.md
+++ b/docs/api/v1/kustomize.md
@@ -395,6 +395,21 @@ resources. When enabled, the HealthChecks are ignored. Defaults to false.
Components specifies relative paths to specifications of other Components.
+
+
+healthCheckExprs
+
+
+[]github.com/fluxcd/pkg/apis/kustomize.CustomHealthCheck
+
+
+ |
+
+(Optional)
+ HealthCheckExprs is a list of healthcheck expressions for evaluating the
+health of custom resources using Common Expression Language (CEL).
+ |
+
@@ -918,6 +933,21 @@ resources. When enabled, the HealthChecks are ignored. Defaults to false.
Components specifies relative paths to specifications of other Components.
+
+
+healthCheckExprs
+
+
+[]github.com/fluxcd/pkg/apis/kustomize.CustomHealthCheck
+
+
+ |
+
+(Optional)
+ HealthCheckExprs is a list of healthcheck expressions for evaluating the
+health of custom resources using Common Expression Language (CEL).
+ |
+
diff --git a/docs/spec/v1/kustomizations.md b/docs/spec/v1/kustomizations.md
index 03ccb158..d65442bd 100644
--- a/docs/spec/v1/kustomizations.md
+++ b/docs/spec/v1/kustomizations.md
@@ -339,6 +339,67 @@ spec:
If all the HelmRelease objects are successfully installed or upgraded, then
the Kustomization will be marked as ready.
+### Health check expressions
+
+`.spec.healthCheckExprs` can be used to define custom logic for performing
+health checks on custom resources. This is done through Common Expression
+Language (CEL) expressions. This field accepts a list of objects with the
+following fields:
+
+- `apiVersion`: The API version of the custom resource. Required.
+- `kind`: The kind of the custom resource. Required.
+- `current`: A required CEL expression that returns `true` if the resource is ready.
+- `inProgress`: An optional CEL expression that returns `true` if the resource
+ is still being reconciled.
+- `failed`: An optional CEL expression that returns `true` if the resource
+ failed to reconcile.
+
+The controller will evaluate the expressions in the following order:
+
+1. `inProgress` if specified
+2. `failed` if specified
+3. `current`
+
+The first expression that evaluates to `true` will determine the health
+status of the custom resource.
+
+For example, to define a set of health check expressions for the `SealedSecret`
+custom resource:
+
+```yaml
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+ name: sealed-secrets
+ namespace: flux-system
+spec:
+ interval: 5m
+ path: ./path/to/sealed/secrets
+ prune: true
+ sourceRef:
+ kind: GitRepository
+ name: flux-system
+ timeout: 1m
+ wait: true # Tells the controller to wait for all resources to be ready by performing health checks.
+ healthCheckExprs:
+ - apiVersion: bitnami.com/v1alpha1
+ kind: SealedSecret
+ inProgress: has(status.observedGeneration) && status.observedGeneration != metadata.generation
+ failed: status.conditions.filter(e, e.type == 'Synced').all(e, e.status == 'False')
+ current: status.conditions.filter(e, e.type == 'Synced').all(e, e.status == 'True')
+```
+
+A common error is writing expressions that reference fields that do not
+exist in the custom resource. This will cause the controller to wait
+for the resource to be ready until the timeout is reached. To avoid this,
+make sure your CEL expressions are correct. The
+[CEL Playground](https://playcel.undistro.io/) is a useful resource for
+this task. The input passed to each expression is the custom resource
+object itself.
+
+It's worth checking if [the library](/flux/cheatsheets/cel-healthchecks/)
+has expressions for the custom resources you are using.
+
### Wait
`.spec.wait` is an optional boolean field to perform health checks for __all__
diff --git a/go.mod b/go.mod
index e90db310..0eeaf1b3 100644
--- a/go.mod
+++ b/go.mod
@@ -20,11 +20,11 @@ require (
github.com/fluxcd/kustomize-controller/api v1.4.0
github.com/fluxcd/pkg/apis/acl v0.5.0
github.com/fluxcd/pkg/apis/event v0.15.0
- github.com/fluxcd/pkg/apis/kustomize v1.8.0
+ github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58
github.com/fluxcd/pkg/apis/meta v1.9.0
github.com/fluxcd/pkg/http/fetch v0.14.0
github.com/fluxcd/pkg/kustomize v1.15.0
- github.com/fluxcd/pkg/runtime v0.52.0
+ github.com/fluxcd/pkg/runtime v0.52.1-0.20250124073354-c595d8c1eb90
github.com/fluxcd/pkg/ssa v0.43.0
github.com/fluxcd/pkg/tar v0.10.0
github.com/fluxcd/pkg/testserver v0.9.0
@@ -78,6 +78,7 @@ require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
+ github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/aws/aws-sdk-go-v2 v1.32.6 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
github.com/aws/aws-sdk-go-v2/config v1.28.6 // indirect
@@ -141,6 +142,7 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.2 // indirect
+ github.com/google/cel-go v0.22.0 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
@@ -199,6 +201,7 @@ require (
github.com/ryanuber/go-glob v1.0.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cobra v1.8.1 // indirect
+ github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/urfave/cli v1.22.16 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
diff --git a/go.sum b/go.sum
index 895d5814..02738bb2 100644
--- a/go.sum
+++ b/go.sum
@@ -69,6 +69,8 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEV
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
+github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go-v2 v1.32.6 h1:7BokKRgRPuGmKkFMhEg/jSul+tB9VvXhcViILtfG8b4=
@@ -183,8 +185,8 @@ github.com/fluxcd/pkg/apis/acl v0.5.0 h1:+ykKezgerKUlZwSYFUy03lPMOIAyWlqvMNNLIWW
github.com/fluxcd/pkg/apis/acl v0.5.0/go.mod h1:IVDZx3MAoDWjlLrJHMF9Z27huFuXAEQlnbWw0M6EcTs=
github.com/fluxcd/pkg/apis/event v0.15.0 h1:k1suqIfVxnhEeKlGkvlHAbOYXjY8wRixT/OZcIuakqA=
github.com/fluxcd/pkg/apis/event v0.15.0/go.mod h1:aRK2AONnjjSNW61B6Iy3SW4YHozACntnJeGm3fFqDqA=
-github.com/fluxcd/pkg/apis/kustomize v1.8.0 h1:HH6YRa3SMS72KK4cUyb9m5sK/dZH+Eti1qhjWDCgwKg=
-github.com/fluxcd/pkg/apis/kustomize v1.8.0/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
+github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58 h1:zhTfTbXKv+R+f1gwu2ekEu0b1Q5CjinCtj1prVEVbVo=
+github.com/fluxcd/pkg/apis/kustomize v1.8.1-0.20250123112748-c55030369b58/go.mod h1:QCKIFj1ocdndaWSkrLs5JKvdGNYyTzQX1ZB3lYTwma0=
github.com/fluxcd/pkg/apis/meta v1.9.0 h1:wPgm7bWNJZ/ImS5GqikOxt362IgLPFBG73dZ27uWRiQ=
github.com/fluxcd/pkg/apis/meta v1.9.0/go.mod h1:pMea8eEZcsFSI7ngRnTHFtDZk2CEZGgtrueNgI6Iu70=
github.com/fluxcd/pkg/envsubst v1.3.0 h1:84Ain+8EBvyzu6y0FsKRwNsvaSiKuqhTqeh/4yoGFFU=
@@ -193,8 +195,8 @@ github.com/fluxcd/pkg/http/fetch v0.14.0 h1:65iI38Vrl21v0YxT8IFCj/63I9/l43b7dPLa
github.com/fluxcd/pkg/http/fetch v0.14.0/go.mod h1:/Ir27MZbgG11yN/npQwF32+oIETeJ+QdceoaxvvkLzQ=
github.com/fluxcd/pkg/kustomize v1.15.0 h1:lII4FW9EJl0rI20dk+Glg5C2JZhP343FBov7HwW+SQo=
github.com/fluxcd/pkg/kustomize v1.15.0/go.mod h1:e2SGi7cl28c9cnBVZ8YV8HAS4VBgUsiM6HMqv/AHJWQ=
-github.com/fluxcd/pkg/runtime v0.52.0 h1:bgYgXURy94MNbHzthJ8SRZJxuZB1X4atj/LLeR6AgDk=
-github.com/fluxcd/pkg/runtime v0.52.0/go.mod h1:66sowtjeLubCmwBTDC+2t41xgjs2eRlNzaWbPWN2nhk=
+github.com/fluxcd/pkg/runtime v0.52.1-0.20250124073354-c595d8c1eb90 h1:awrUaChnkZkBSkP3osz3oDB2mL7NiDg7knUvR83lVfk=
+github.com/fluxcd/pkg/runtime v0.52.1-0.20250124073354-c595d8c1eb90/go.mod h1:t67yJDmlO8PKVZ1AZsnUNUpL9Jguhnq2UBHKKbmM5oU=
github.com/fluxcd/pkg/sourceignore v0.10.0 h1:z5Bhh0G990uLbwjKNj7SzYqbGkicpGcXxF/Z4ZSVB64=
github.com/fluxcd/pkg/sourceignore v0.10.0/go.mod h1:d1d9hcFxf+grda6JL3k+mC09nVTtBb9kJVzQn6J77B0=
github.com/fluxcd/pkg/ssa v0.43.0 h1:XmADD3C0erYZayKfGI0WTsMlW9TtS4bp5gy4Axo1dcA=
@@ -264,6 +266,8 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/cel-go v0.22.0 h1:b3FJZxpiv1vTMo2/5RDUqAHPxkT8mmMfJIrq1llbf7g=
+github.com/google/cel-go v0.22.0/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -430,6 +434,8 @@ github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
+github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
diff --git a/internal/controller/kustomization_controller.go b/internal/controller/kustomization_controller.go
index 9a5f7f01..896c1ff6 100644
--- a/internal/controller/kustomization_controller.go
+++ b/internal/controller/kustomization_controller.go
@@ -56,6 +56,7 @@ import (
"github.com/fluxcd/pkg/http/fetch"
generator "github.com/fluxcd/pkg/kustomize"
"github.com/fluxcd/pkg/runtime/acl"
+ "github.com/fluxcd/pkg/runtime/cel"
runtimeClient "github.com/fluxcd/pkg/runtime/client"
"github.com/fluxcd/pkg/runtime/conditions"
runtimeCtrl "github.com/fluxcd/pkg/runtime/controller"
@@ -89,6 +90,7 @@ type KustomizationReconciler struct {
artifactFetchRetries int
requeueDependency time.Duration
+ Mapper apimeta.RESTMapper
APIReader client.Reader
StatusPoller *polling.StatusPoller
PollingOpts polling.Options
@@ -362,10 +364,11 @@ func (r *KustomizationReconciler) reconcile(
}
// Configure the Kubernetes client for impersonation.
+ statusPoller, pollingOpts := r.getPollerAndOptions(obj)
impersonation := runtimeClient.NewImpersonator(
r.Client,
- r.StatusPoller,
- r.PollingOpts,
+ statusPoller,
+ pollingOpts,
obj.Spec.KubeConfig,
r.KubeConfigOpts,
r.DefaultServiceAccount,
@@ -475,7 +478,7 @@ func (r *KustomizationReconciler) reconcile(
conditions.MarkTrue(obj,
meta.ReadyCondition,
meta.ReconciliationSucceededReason,
- fmt.Sprintf("Applied revision: %s", revision))
+ "Applied revision: %s", revision)
return nil
}
@@ -980,10 +983,11 @@ func (r *KustomizationReconciler) finalize(ctx context.Context,
obj.Status.Inventory.Entries != nil {
objects, _ := inventory.List(obj.Status.Inventory)
+ statusPoller, pollingOpts := r.getPollerAndOptions(obj)
impersonation := runtimeClient.NewImpersonator(
r.Client,
- r.StatusPoller,
- r.PollingOpts,
+ statusPoller,
+ pollingOpts,
obj.Spec.KubeConfig,
r.KubeConfigOpts,
r.DefaultServiceAccount,
@@ -1130,3 +1134,20 @@ func getOriginRevision(src sourcev1.Source) string {
}
return a.Metadata[OCIArtifactOriginRevisionAnnotation]
}
+
+// getPollerAndOptions returns the status poller and polling options
+// based on the healthcheck expressions defined in the Kustomization
+// object spec.
+func (r *KustomizationReconciler) getPollerAndOptions(
+ obj *kustomizev1.Kustomization) (*polling.StatusPoller, polling.Options) {
+
+ poller := r.StatusPoller
+ opts := r.PollingOpts
+
+ if hc := obj.Spec.HealthCheckExprs; len(hc) > 0 {
+ opts = cel.PollerWithCustomHealthChecks(hc, r.Mapper, opts)
+ poller = polling.NewStatusPoller(r.Client, r.Mapper, opts)
+ }
+
+ return poller, opts
+}
diff --git a/internal/controller/kustomization_fuzzer_test.go b/internal/controller/kustomization_fuzzer_test.go
index c4ffd3f7..523f9e6a 100644
--- a/internal/controller/kustomization_fuzzer_test.go
+++ b/internal/controller/kustomization_fuzzer_test.go
@@ -125,6 +125,7 @@ func Fuzz_Controllers(f *testing.F) {
reconciler := &KustomizationReconciler{
ControllerName: controllerName,
Client: testEnv,
+ Mapper: testEnv.GetRESTMapper(),
}
if err := (reconciler).SetupWithManager(ctx, testEnv, KustomizationReconcilerOptions{}); err != nil {
panic(fmt.Sprintf("Failed to start GitRepositoryReconciler: %v", err))
diff --git a/internal/controller/kustomization_wait_test.go b/internal/controller/kustomization_wait_test.go
index 78b7a30e..5129de63 100644
--- a/internal/controller/kustomization_wait_test.go
+++ b/internal/controller/kustomization_wait_test.go
@@ -29,6 +29,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
+ "github.com/fluxcd/pkg/apis/kustomize"
"github.com/fluxcd/pkg/apis/meta"
"github.com/fluxcd/pkg/runtime/conditions"
"github.com/fluxcd/pkg/testserver"
@@ -275,3 +276,87 @@ parameters:
}, timeout, time.Second).Should(BeTrue())
})
}
+
+func TestKustomizationReconciler_WaitsForCustomHealthChecks(t *testing.T) {
+ g := NewWithT(t)
+ id := "wait-" + randStringRunes(5)
+ revision := "v1.0.0"
+ resultK := &kustomizev1.Kustomization{}
+ timeout := 60 * time.Second
+
+ err := createNamespace(id)
+ g.Expect(err).NotTo(HaveOccurred(), "failed to create test namespace")
+
+ manifests := func(name string) []testserver.File {
+ return []testserver.File{
+ {
+ Name: "config.yaml",
+ Body: fmt.Sprintf(`---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: %[1]s
+data: {}
+`, name),
+ },
+ }
+ }
+
+ artifact, err := testServer.ArtifactFromFiles(manifests(id))
+ g.Expect(err).NotTo(HaveOccurred())
+
+ repositoryName := types.NamespacedName{
+ Name: fmt.Sprintf("wait-%s", randStringRunes(5)),
+ Namespace: id,
+ }
+
+ err = applyGitRepository(repositoryName, artifact, revision)
+ g.Expect(err).NotTo(HaveOccurred())
+
+ kustomizationKey := types.NamespacedName{
+ Name: fmt.Sprintf("wait-%s", randStringRunes(5)),
+ Namespace: id,
+ }
+ kustomization := &kustomizev1.Kustomization{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: kustomizationKey.Name,
+ Namespace: kustomizationKey.Namespace,
+ },
+ Spec: kustomizev1.KustomizationSpec{
+ Interval: metav1.Duration{Duration: 2 * time.Minute},
+ Path: "./",
+ SourceRef: kustomizev1.CrossNamespaceSourceReference{
+ Name: repositoryName.Name,
+ Namespace: repositoryName.Namespace,
+ Kind: sourcev1.GitRepositoryKind,
+ },
+ TargetNamespace: id,
+ Prune: true,
+ Timeout: &metav1.Duration{Duration: time.Second},
+ Wait: true,
+ HealthCheckExprs: []kustomize.CustomHealthCheck{{
+ APIVersion: "v1",
+ Kind: "ConfigMap",
+ HealthCheckExpressions: kustomize.HealthCheckExpressions{
+ InProgress: "has(data.foo.bar)",
+ Current: "true",
+ },
+ }},
+ },
+ }
+
+ err = k8sClient.Create(context.Background(), kustomization)
+ g.Expect(err).NotTo(HaveOccurred())
+
+ g.Eventually(func() bool {
+ _ = k8sClient.Get(context.Background(), client.ObjectKeyFromObject(kustomization), resultK)
+ return conditions.IsFalse(resultK, meta.ReadyCondition)
+ }, timeout, time.Second).Should(BeTrue())
+ logStatus(t, resultK)
+
+ msg := conditions.GetMessage(resultK, meta.ReadyCondition)
+ g.Expect(msg).
+ To(ContainSubstring("timeout waiting for: [ConfigMap"))
+ g.Expect(msg).
+ To(ContainSubstring("failed to evaluate the CEL expression: no such attribute(s): data.foo.bar"))
+}
diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go
index bd4bbb6f..2f7053a7 100644
--- a/internal/controller/suite_test.go
+++ b/internal/controller/suite_test.go
@@ -176,6 +176,7 @@ func TestMain(m *testing.M) {
reconciler = &KustomizationReconciler{
ControllerName: controllerName,
Client: testEnv,
+ Mapper: testEnv.GetRESTMapper(),
APIReader: testEnv,
EventRecorder: testEnv.GetEventRecorderFor(controllerName),
Metrics: testMetricsH,
diff --git a/main.go b/main.go
index a04bd5fb..65d7fec5 100644
--- a/main.go
+++ b/main.go
@@ -238,6 +238,7 @@ func main() {
ControllerName: controllerName,
DefaultServiceAccount: defaultServiceAccount,
Client: mgr.GetClient(),
+ Mapper: mgr.GetRESTMapper(),
APIReader: mgr.GetAPIReader(),
Metrics: metricsH,
EventRecorder: eventRecorder,