Skip to content

Commit 960d853

Browse files
feat(api): typed waitStrategy/healthCheckExprs for kstatus readiness (#2642) (#3273)
## What Adds typed `waitStrategy` + `healthCheckExprs` fields so a package/app can declare the Flux helm-controller v1.5.0 kstatus health gate for the custom resource it wraps — making `HelmRelease.Ready` mean "the CR is actually healthy" instead of "helm applied the CR". This is the operator/apiserver foundation of the kstatus epic (#2642); the API surface was reviewed and approved by the API owner in #3263. Commits (per the review's "isolated step-0" request): 1. `build(deps)` — the dependency bump (see below). 2. `feat(api)` — the fields, plumbing, tests, and regenerated code. 3. `fix(api)` — match the openapi code-generator pin to the 0.35 runtime (fixes an aggregated-apiserver crash the bump surfaced). 4. `fix(api)` — declare `OpenAPIModelName` on the apps types so SSA resolves catalog kinds. 5. `docs(api)` — note that `disableWait` silently defeats `healthCheckExprs`. ## API surface Typed fields on **both** HelmRelease-building paths: - `ApplicationDefinition.spec.release` (apiserver / catalog apps → `convertApplicationToHelmRelease`) - `ComponentInstall` (operator / platform packages → `buildHelmReleaseSpec`) ```go // WaitStrategy maps to HelmReleaseSpec.WaitStrategy.Name — a deliberate scalar // simplification of the upstream {name} object. One of poller|legacy. WaitStrategy string // HealthCheckExprs maps to HelmReleaseSpec.HealthCheckExprs (the upstream // kustomize.CustomHealthCheck type verbatim). HealthCheckExprs []kustomize.CustomHealthCheck ``` `config.ResolveWaitStrategy` is shared by both builders and **couples the default**: `healthCheckExprs` are only evaluated under the `poller` strategy, so when expressions are set and no strategy is given, the generated HelmRelease defaults to `poller`. A package that sets only `healthCheckExprs` is therefore self-contained, independent of the controller's global default. ## The dependency bump (commit 1) The `WaitStrategy` / `kustomize.CustomHealthCheck` / `HelmReleaseSpec.HealthCheckExprs` types do not exist below `helm-controller/api` v1.5.0 — the runtime is already v1.5.0 (shipped by #2602), so this closes a Go-types-vs-runtime skew. It is **not** an isolated bump: v1.5.x requires **k8s 0.35 + controller-runtime 0.23**, cascading the k8s stack 0.34 → 0.35 (and the go directive to 1.26). cozystack replaces `k8s.io/apimachinery` with a fork carrying the still-open upstream `ConvertToVersion` patch (k/k#135537). That single commit rebases cleanly onto apimachinery v0.35.0; published at `cozystack/[email protected]`, and `go.mod` pins its pseudo-version. **The repo builds with zero source changes under the new stack.** > Maintainer note: please confirm the `release-1.35-pr135537` fork branch naming, or fold it into the `cozystack` branch as you prefer — the pin can be updated to match. ## Not included (conscious YAGNI) `disableWait` is intentionally omitted. The only known need (the kubernetes tenant-addon deadlock) was resolved child-side, and `waitStrategy: legacy` is not equivalent (legacy still waits Helm-v3-style; `disableWait` skips waiting entirely). Add it later when a concrete leaf needs a true no-gate escape hatch. ## Tests - `config.TestResolveWaitStrategy` — the couple-the-default logic (unset+exprs→poller; explicit legacy honored; unset+no-exprs→nil). - Operator + apiserver cases mirror each other (`TestBuildHelmReleaseSpecHealthCheckExprs` / `TestConvertApplicationToHelmRelease_HealthCheckExprs`). - `go build ./...` clean, `go vet` clean, `gofmt` clean, codegen regenerated and committed. The 4 backupstrategy CRDs regenerate with benign k8s-0.35 PodSpec description drift (DynamicResourceAllocation alpha→stable, toleration Lt/Gt, resizePolicy note) — no functional change. ## Follow-up Phase 3 (per-leaf adoption — postgres/kafka/mongodb/etc. declaring their CEL via these fields) builds on this. The full CRD→CEL catalog is maintained in the epic's readiness audit. Refs #2642 ```release-note feat(api): add `waitStrategy` and `healthCheckExprs` to ApplicationDefinition and ComponentInstall, so a HelmRelease reports Ready only once the custom resource it wraps is actually healthy ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added configurable CEL health-check expressions for application releases and package components. * Added `waitStrategy` support (`poller` and `legacy`) with automatic `poller` selection when health checks are configured and no strategy is set. * Propagated these settings into generated Helm releases, affecting readiness/wait behavior. * **Documentation** * Updated Application and PackageSource schemas to include `healthCheckExprs` and `waitStrategy`. * Extended related Kubernetes CRD documentation, including projected pod certificate annotations and workload reference fields. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents e73ad68 + f161921 commit 960d853

26 files changed

Lines changed: 1118 additions & 358 deletions

‎api/api-rules/cozystack_api_violation_exceptions.list‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiexten
2929
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaPropsOrBool,Schema
3030
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaPropsOrStringArray,Property
3131
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaPropsOrStringArray,Schema
32+
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,Format
33+
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,d
34+
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,i
35+
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,Quantity,s
36+
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,int64Amount,scale
37+
API rule violation: names_match,k8s.io/apimachinery/pkg/api/resource,int64Amount,value
3238
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,APIResourceList,APIResources
3339
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,Duration,Duration
3440
API rule violation: names_match,k8s.io/apimachinery/pkg/apis/meta/v1,InternalEvent,Object

‎api/v1alpha1/applicationdefinitions_types.go‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1alpha1
1818

1919
import (
2020
helmv2 "github.com/fluxcd/helm-controller/api/v2"
21+
"github.com/fluxcd/pkg/apis/kustomize"
2122
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2223
)
2324

@@ -80,6 +81,29 @@ type ApplicationDefinitionRelease struct {
8081
Labels map[string]string `json:"labels,omitempty"`
8182
// Prefix for the release name
8283
Prefix string `json:"prefix"`
84+
85+
// WaitStrategy maps to HelmReleaseSpec.WaitStrategy.Name — a deliberate
86+
// scalar simplification of the upstream {name} object, since there is only
87+
// one value to set. One of poller|legacy. When healthCheckExprs is set and
88+
// this is empty, the generated HelmRelease defaults to poller, because
89+
// healthCheckExprs are only evaluated under the poller wait strategy.
90+
// +optional
91+
// +kubebuilder:validation:Enum=poller;legacy
92+
WaitStrategy string `json:"waitStrategy,omitempty"`
93+
94+
// HealthCheckExprs maps to HelmReleaseSpec.HealthCheckExprs — CEL health
95+
// expressions for the custom resource(s) this application renders, so the
96+
// HelmRelease reports Ready only when the CR is actually healthy instead of
97+
// as soon as helm applies it. OpenAPI validates only the struct shape, not
98+
// that the CEL compiles or that the referenced apiVersion/kind CRD is
99+
// installed; a bad expression or a not-yet-installed CRD makes the
100+
// HelmRelease hang until its timeout (the backstop).
101+
// Upstream evaluates these only when the Helm action itself has wait
102+
// enabled, so the release.cozystack.io/helm-install-disable-wait annotation
103+
// makes them a silent no-op whatever waitStrategy says: the HelmRelease
104+
// reports Ready as soon as helm applies the CR, with no error or warning.
105+
// +optional
106+
HealthCheckExprs []kustomize.CustomHealthCheck `json:"healthCheckExprs,omitempty"`
83107
}
84108

85109
// ApplicationDefinitionResourceSelector extends metav1.LabelSelector with resourceNames support.

‎api/v1alpha1/packagesource_types.go‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1alpha1
1818

1919
import (
20+
"github.com/fluxcd/pkg/apis/kustomize"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122
)
2223

@@ -142,6 +143,25 @@ type ComponentInstall struct {
142143
// +optional
143144
// +kubebuilder:validation:Enum=Skip;Create;CreateReplace
144145
UpgradeCRDs string `json:"upgradeCRDs,omitempty"`
146+
147+
// WaitStrategy maps to HelmReleaseSpec.WaitStrategy.Name — a deliberate
148+
// scalar simplification of the upstream {name} object. One of poller|legacy.
149+
// When healthCheckExprs is set and this is empty, the generated HelmRelease
150+
// defaults to poller, because healthCheckExprs are only evaluated under the
151+
// poller wait strategy.
152+
// +optional
153+
// +kubebuilder:validation:Enum=poller;legacy
154+
WaitStrategy string `json:"waitStrategy,omitempty"`
155+
156+
// HealthCheckExprs maps to HelmReleaseSpec.HealthCheckExprs — CEL health
157+
// expressions for the custom resource(s) this component renders, so the
158+
// HelmRelease reports Ready only when the CR is actually healthy. OpenAPI
159+
// validates only the struct shape, not that the CEL compiles or that the
160+
// referenced apiVersion/kind CRD is installed; a bad expression or a
161+
// not-yet-installed CRD makes the HelmRelease hang until its timeout (the
162+
// backstop).
163+
// +optional
164+
HealthCheckExprs []kustomize.CustomHealthCheck `json:"healthCheckExprs,omitempty"`
145165
}
146166

147167
// Component defines a single Helm release component within a package source

‎api/v1alpha1/zz_generated.deepcopy.go‎

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎go.mod‎

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,42 @@ require (
88
github.com/cert-manager/cert-manager v1.17.4
99
github.com/cozystack/cozystack-scheduler/pkg/apis v0.1.1
1010
github.com/emicklei/dot v1.10.0
11-
github.com/fluxcd/helm-controller/api v1.4.3
12-
github.com/fluxcd/pkg/apis/meta v1.23.0
11+
github.com/fluxcd/helm-controller/api v1.5.1
12+
github.com/fluxcd/pkg/apis/kustomize v1.15.0
13+
github.com/fluxcd/pkg/apis/meta v1.25.0
1314
github.com/fluxcd/source-controller/api v1.7.4
1415
github.com/fluxcd/source-watcher/api/v2 v2.0.3
1516
github.com/go-logr/logr v1.4.3
1617
github.com/go-logr/zapr v1.3.0
1718
github.com/go-task/slim-sprig/v3 v3.0.0
18-
github.com/onsi/ginkgo/v2 v2.23.3
19-
github.com/onsi/gomega v1.37.0
20-
github.com/prometheus/client_golang v1.23.0
19+
github.com/onsi/ginkgo/v2 v2.27.2
20+
github.com/onsi/gomega v1.38.2
21+
github.com/prometheus/client_golang v1.23.2
2122
github.com/robfig/cron/v3 v3.0.1
22-
github.com/spf13/cobra v1.9.1
23+
github.com/spf13/cobra v1.10.0
2324
github.com/vmware-tanzu/velero v1.17.1
2425
go.uber.org/zap v1.27.0
2526
gomodules.xyz/jsonpatch/v2 v2.4.0
26-
k8s.io/api v0.34.1
27-
k8s.io/apiextensions-apiserver v0.34.1
28-
k8s.io/apimachinery v0.34.2
29-
k8s.io/apiserver v0.34.1
30-
k8s.io/client-go v0.34.1
31-
k8s.io/component-base v0.34.1
27+
k8s.io/api v0.35.0
28+
k8s.io/apiextensions-apiserver v0.35.0
29+
k8s.io/apimachinery v0.35.0
30+
k8s.io/apiserver v0.35.0
31+
k8s.io/client-go v0.35.0
32+
k8s.io/component-base v0.35.0
3233
k8s.io/klog/v2 v2.130.1
33-
k8s.io/kube-openapi v0.0.0-20250814151709-d7b6acb124c3
34-
k8s.io/utils v0.0.0-20250820121507-0af2bda4dd1d
34+
k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912
35+
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4
3536
sigs.k8s.io/container-object-storage-interface-api v0.1.0
36-
sigs.k8s.io/controller-runtime v0.22.4
37+
sigs.k8s.io/controller-runtime v0.23.1
3738
sigs.k8s.io/gateway-api v1.4.1
3839
sigs.k8s.io/randfill v1.0.0
39-
sigs.k8s.io/structured-merge-diff/v6 v6.3.0
40+
sigs.k8s.io/structured-merge-diff/v6 v6.3.2-0.20260122202528-d9cc6641c482
4041
sigs.k8s.io/yaml v1.6.0
4142
)
4243

4344
require (
4445
cel.dev/expr v0.25.1 // indirect
46+
github.com/Masterminds/semver/v3 v3.4.0 // indirect
4547
github.com/NYTimes/gziphandler v1.1.1 // indirect
4648
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
4749
github.com/beorn7/perks v1.0.1 // indirect
@@ -55,7 +57,6 @@ require (
5557
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
5658
github.com/felixge/httpsnoop v1.0.4 // indirect
5759
github.com/fluxcd/pkg/apis/acl v0.9.0 // indirect
58-
github.com/fluxcd/pkg/apis/kustomize v1.13.0 // indirect
5960
github.com/fsnotify/fsnotify v1.9.0 // indirect
6061
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
6162
github.com/go-logr/stdr v1.2.2 // indirect
@@ -68,7 +69,7 @@ require (
6869
github.com/google/cel-go v0.26.0 // indirect
6970
github.com/google/gnostic-models v0.7.0 // indirect
7071
github.com/google/go-cmp v0.7.0 // indirect
71-
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
72+
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
7273
github.com/google/uuid v1.6.0 // indirect
7374
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
7475
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
@@ -85,14 +86,14 @@ require (
8586
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
8687
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
8788
github.com/prometheus/client_model v0.6.2 // indirect
88-
github.com/prometheus/common v0.65.0 // indirect
89+
github.com/prometheus/common v0.66.1 // indirect
8990
github.com/prometheus/procfs v0.17.0 // indirect
90-
github.com/spf13/pflag v1.0.7 // indirect
91+
github.com/spf13/pflag v1.0.9 // indirect
9192
github.com/stoewer/go-strcase v1.3.0 // indirect
9293
github.com/x448/float16 v0.8.4 // indirect
93-
go.etcd.io/etcd/api/v3 v3.6.4 // indirect
94-
go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect
95-
go.etcd.io/etcd/client/v3 v3.6.4 // indirect
94+
go.etcd.io/etcd/api/v3 v3.6.5 // indirect
95+
go.etcd.io/etcd/client/pkg/v3 v3.6.5 // indirect
96+
go.etcd.io/etcd/client/v3 v3.6.5 // indirect
9697
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
9798
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 // indirect
9899
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect
@@ -104,10 +105,11 @@ require (
104105
go.opentelemetry.io/otel/trace v1.43.0 // indirect
105106
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
106107
go.uber.org/multierr v1.11.0 // indirect
107-
go.yaml.in/yaml/v2 v2.4.2 // indirect
108+
go.yaml.in/yaml/v2 v2.4.3 // indirect
108109
go.yaml.in/yaml/v3 v3.0.4 // indirect
109110
golang.org/x/crypto v0.52.0 // indirect
110111
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect
112+
golang.org/x/mod v0.35.0 // indirect
111113
golang.org/x/net v0.55.0 // indirect
112114
golang.org/x/oauth2 v0.35.0 // indirect
113115
golang.org/x/sync v0.20.0 // indirect
@@ -124,10 +126,10 @@ require (
124126
gopkg.in/inf.v0 v0.9.1 // indirect
125127
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
126128
gopkg.in/yaml.v3 v3.0.1 // indirect
127-
k8s.io/kms v0.34.1 // indirect
129+
k8s.io/kms v0.35.0 // indirect
128130
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect
129131
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect
130132
)
131133

132134
// See: issues.k8s.io/135537
133-
replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20251219010959-1f91eabae46c
135+
replace k8s.io/apimachinery => github.com/cozystack/apimachinery v0.0.0-20260710062224-763e1451713b

0 commit comments

Comments
 (0)