Skip to content

Commit

Permalink
[RFC-0009] Add CEL custom healthchecks
Browse files Browse the repository at this point in the history
Signed-off-by: Matheus Pimenta <matheuscscp@gmail.com>
  • Loading branch information
matheuscscp committed Jan 27, 2025
1 parent 5967686 commit d0ff0bf
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 14 deletions.
2 changes: 1 addition & 1 deletion api/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions api/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
5 changes: 5 additions & 0 deletions api/v1/kustomization_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions config/crd/bases/kustomize.toolkit.fluxcd.io_kustomizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
30 changes: 30 additions & 0 deletions docs/api/v1/kustomize.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,21 @@ resources. When enabled, the HealthChecks are ignored. Defaults to false.</p>
<p>Components specifies relative paths to specifications of other Components.</p>
</td>
</tr>
<tr>
<td>
<code>healthCheckExprs</code><br>
<em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/kustomize#CustomHealthCheck">
[]github.com/fluxcd/pkg/apis/kustomize.CustomHealthCheck
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>HealthCheckExprs is a list of healthcheck expressions for evaluating the
health of custom resources using Common Expression Language (CEL).</p>
</td>
</tr>
</table>
</td>
</tr>
Expand Down Expand Up @@ -918,6 +933,21 @@ resources. When enabled, the HealthChecks are ignored. Defaults to false.</p>
<p>Components specifies relative paths to specifications of other Components.</p>
</td>
</tr>
<tr>
<td>
<code>healthCheckExprs</code><br>
<em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/kustomize#CustomHealthCheck">
[]github.com/fluxcd/pkg/apis/kustomize.CustomHealthCheck
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>HealthCheckExprs is a list of healthcheck expressions for evaluating the
health of custom resources using Common Expression Language (CEL).</p>
</td>
</tr>
</tbody>
</table>
</div>
Expand Down
61 changes: 61 additions & 0 deletions docs/spec/v1/kustomizations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
14 changes: 10 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand All @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
31 changes: 26 additions & 5 deletions internal/controller/kustomization_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -89,6 +90,7 @@ type KustomizationReconciler struct {
artifactFetchRetries int
requeueDependency time.Duration

Mapper apimeta.RESTMapper
APIReader client.Reader
StatusPoller *polling.StatusPoller
PollingOpts polling.Options
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
1 change: 1 addition & 0 deletions internal/controller/kustomization_fuzzer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Loading

0 comments on commit d0ff0bf

Please sign in to comment.