From f88efb505d04e8788caf3fa4b3ea4dab8978c73e Mon Sep 17 00:00:00 2001 From: Said Boudjelda Date: Sun, 18 Oct 2026 15:36:25 +0200 Subject: [PATCH] fix(deploy): kates deploy --with-chaos=false puts the Kates API on the noop chaos provider, through a new chaos.provider chart value `kates deploy --with-chaos=false` installed no Litmus but left the Kates API on its litmus-crd default: the kates chart had no chaos value, only extraEnv, and deploy set nothing. The ChaosCoordinator then found Litmus unavailable, logged at ERROR that fault injection is DISABLED, and fell back to noop, so a stack deployed without chaos read as a broken one. The kates chart gets chaos.provider, empty by default. When set, the configmap renders KATES_CHAOS_PROVIDER, and the configmap checksum rolls the pod when the value flips. values.schema.json allows litmus-crd, kubernetes, hybrid, noop or empty. Deploy passes --set chaos.provider=noop when --with-chaos=false and no chaos release is installed; with Litmus there, or --with-chaos, it sets nothing and the chart default applies. The chart moves to 0.11.2, with README.md and the book's version matrix to match. The chart README documents the value and selects the direct backend with it instead of extraEnv. The helm-lint job renders the configmap with the value empty, set and unknown. --- .github/workflows/ci.yml | 17 ++++++++++++++ README.md | 2 +- charts/kates/Chart.yaml | 11 ++++----- charts/kates/README.md | 8 +++---- charts/kates/templates/configmap.yaml | 3 +++ charts/kates/values.schema.json | 9 ++++++++ charts/kates/values.yaml | 9 ++++++++ cli/cmd/deploy_components.go | 12 ++++++++++ cli/cmd/deploy_test.go | 32 +++++++++++++++++++++++++++ docs/book/appendix-d-versions.md | 2 +- 10 files changed, 94 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a451fba..d31a0c26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,6 +236,23 @@ jobs: || fail "8889 must be open once, to the Kafka namespace (got: ${trogdor:-none})" echo "OK: the egress follows networkPolicy.kafka.namespace" + # kates deploy --with-chaos=false sets chaos.provider=noop; empty must + # leave the backend on its own default, litmus-crd. + - name: Assert chaos.provider renders KATES_CHAOS_PROVIDER only when set + run: | + fail() { echo "::error::kates configmap: $1"; exit 1; } + cm=$(helm template kates charts/kates/ --show-only templates/configmap.yaml) + if grep -q 'KATES_CHAOS_PROVIDER' <<<"${cm}"; then + fail "KATES_CHAOS_PROVIDER rendered with chaos.provider empty" + fi + cm=$(helm template kates charts/kates/ --show-only templates/configmap.yaml \ + --set chaos.provider=noop) + grep -q 'KATES_CHAOS_PROVIDER: "noop"' <<<"${cm}" || fail "chaos.provider=noop not rendered" + if helm template kates charts/kates/ --set chaos.provider=litmus > /dev/null 2>&1; then + fail "values.schema.json accepted chaos.provider=litmus" + fi + echo "OK: chaos.provider renders KATES_CHAOS_PROVIDER only when set" + # The Strimzi version is declared in five places. If values.yaml's # strimziVersion drifts from the Chart.yaml dependency version, the CRD # hook applies CRDs for a different operator than the one installed — diff --git a/README.md b/README.md index 68e60ded..2b7e4343 100644 --- a/README.md +++ b/README.md @@ -213,7 +213,7 @@ When you install charts with Helm directly: | [`kafka-ui`](charts/kafka-ui/) | 0.3.0 | v1.5.0 | A Helm chart for deploying Kafka UI (Kafbat) with Strimzi SCRAM-SHA-512 authentication | | [`kates-chaos`](charts/kates-chaos/) | 2.2.1 | 3.28.0 | Kates Chaos Engineering — wraps the LitmusChaos execution plane (operator, exporter, CRDs) with Kafka-specific RBAC, experiment/engine templating, and monitoring | | [`kates-platform`](charts/kates-platform/) | 0.7.0 | 1.0.0 | Umbrella chart for the full Kates platform — Kafka, Kates, and supporting infrastructure | -| [`kates`](charts/kates/) | 0.11.1 | 1.25.1 | Kates — Kafka Advanced Testing & Engineering Suite | +| [`kates`](charts/kates/) | 0.11.2 | 1.25.1 | Kates — Kafka Advanced Testing & Engineering Suite | | [`legacy-kafka`](charts/legacy-kafka/) | 0.2.0 | 3.9.1 | A deliberately old Kafka (2.x on ZooKeeper, or 3.x on KRaft) to migrate FROM — the replication source that the pinned Strimzi release cannot deploy | | [`mirror-maker2`](charts/mirror-maker2/) | 0.11.4 | 4.3.1 | Strimzi KafkaMirrorMaker2 — cross-cluster replication, DR, and cross-version migration (2.x/3.x → 4.x) | | [`monitoring`](charts/monitoring/) | 1.6.0 | 82.4.3 | Kates Monitoring — wraps kube-prometheus-stack with Kates-specific dashboards and configuration | diff --git a/charts/kates/Chart.yaml b/charts/kates/Chart.yaml index c939b235..b26e1ed2 100644 --- a/charts/kates/Chart.yaml +++ b/charts/kates/Chart.yaml @@ -2,11 +2,10 @@ apiVersion: v2 name: kates description: Kates — Kafka Advanced Testing & Engineering Suite type: application -# Patch: the NetworkPolicy's Kafka egress follows networkPolicy.kafka.namespace -# instead of always `kafka`, opens Trogdor's 8889 there instead of in -# `monitoring`, and a new rule opens TCP 443/6443 for the Kubernetes API. -# appVersion is unchanged. -version: 0.11.1 +# Patch: a new chaos.provider value renders KATES_CHAOS_PROVIDER in the +# configmap; empty by default, so a release that leaves it out renders as +# before. appVersion is unchanged. +version: 0.11.2 # The non-blocking health endpoints this chart's probes now point at come from # a BUILD-TIME property (quarkus.messaging.health.enabled=false), so they only # exist in the image built from this branch. Keep appVersion and @@ -30,6 +29,8 @@ annotations: artifacthub.io/category: integration-delivery artifacthub.io/license: Apache-2.0 artifacthub.io/changes: | + - kind: added + description: "chaos.provider (KATES_CHAOS_PROVIDER, default empty: the backend's litmus-crd) picks the chaos provider every fault goes through: litmus-crd, kubernetes, hybrid or noop. It used to be set only through extraEnv. `kates deploy --with-chaos=false` sets noop when no chaos release is installed, so a stack without Litmus skips its faults by design instead of logging an ERROR and falling back to noop. values.schema.json refuses any other name" - kind: fixed description: "On a CNI that enforces NetworkPolicy, the chart's NetworkPolicy cut the backend off from the Kubernetes API, so every chaos fault, pod listing, KafkaTopic CR and orphan recovery failed; its Kafka egress always named namespace kafka, whatever networkPolicy.kafka.namespace said; and it allowed Trogdor's 8889 only to namespace monitoring, where no coordinator runs. The Kafka egress now follows networkPolicy.kafka.namespace (default kafka), 8889 moves from monitoring to that namespace, and a new ports-only rule opens TCP 443 and 6443 to any address for the Kubernetes API. Upgrading: a release that set networkPolicy.kafka.namespace to anything but the namespace Kafka runs in loses Kafka, as the value now takes effect; a Trogdor coordinator outside that namespace needs a networkPolicy.egressRules entry" - kind: changed diff --git a/charts/kates/README.md b/charts/kates/README.md index 649b6354..47e5ed97 100644 --- a/charts/kates/README.md +++ b/charts/kates/README.md @@ -42,6 +42,7 @@ All configuration is in [values.yaml](values.yaml). Key sections: | `engine.maxDurationMs` | `7200000` | Maximum planned duration accepted for one run | | `engine.reaperGraceMs` | `300000` | Grace after a `RUNNING` or `STOPPING` run's planned duration before the reaper fails it | | `engine.submissionTimeoutMs` | `120000` | Maximum time a run may stay `PENDING` before submission is considered stranded | +| `chaos.provider` | `""` | Chaos provider every fault goes through: `litmus-crd`, `kubernetes`, `hybrid` or `noop`. Empty keeps the backend's default, `litmus-crd`. `kates deploy --with-chaos=false` sets `noop` when no chaos release is installed. See [Chaos permissions](#chaos-permissions) | | `prometheus.url` | `http://monitoring-kube-prometheus-prometheus.monitoring.svc:9090` | Prometheus the backend queries for a disruption's Kafka metrics: kube-prometheus-stack's Service for `charts/monitoring` installed as release `monitoring` in namespace `monitoring`, as `kates deploy` does. After `make monitoring`, which uses namespace `kafka`, set `http://monitoring-kube-prometheus-prometheus.kafka.svc:9090` and `networkPolicy.prometheus.namespace=kafka` | ### Networking @@ -120,12 +121,11 @@ With the default chaos provider, `litmus-crd`, Kates only creates and watches `C `ROLLING_RESTART` needs none of these, on either backend, and neither does `SCALE_DOWN` on a Strimzi cluster. On a Strimzi cluster `ROLLING_RESTART` annotates the Kafka pods for the Strimzi Cluster Operator to roll, and on a plain StatefulSet, such as `charts/legacy-kafka`, it restarts the StatefulSet. `SCALE_DOWN` lowers `spec.replicas` of a KafkaNodePool. Both run on either backend, so the default role grants `patch` on pods, on StatefulSets and on `kafkanodepools`. On a Kafka that Strimzi does not manage, `SCALE_DOWN` also patches the StatefulSet, to record its original replica count. -These rules are cluster-wide, like the rest of the role, and `pods/ephemeralcontainers` lets Kates start a container in any pod. Leave them off unless you use the direct backend. It is selected with an environment variable: +These rules are cluster-wide, like the rest of the role, and `pods/ephemeralcontainers` lets Kates start a container in any pod. Leave them off unless you use the direct backend. It is selected with `chaos.provider`: ```yaml -extraEnv: - - name: KATES_CHAOS_PROVIDER - value: kubernetes +chaos: + provider: kubernetes rbac: directChaos: true ``` diff --git a/charts/kates/templates/configmap.yaml b/charts/kates/templates/configmap.yaml index aae27a78..a5fb2c77 100644 --- a/charts/kates/templates/configmap.yaml +++ b/charts/kates/templates/configmap.yaml @@ -176,6 +176,9 @@ data: KATES_TESTS_ROUNDTRIP_DURATION_MS: {{ .Values.tests.roundtrip.durationMs | default .Values.defaults.durationMs | quote }} KATES_TESTS_ROUNDTRIP_NUM_PRODUCERS: {{ .Values.tests.roundtrip.numProducers | default .Values.defaults.numProducers | quote }} KATES_TESTS_ROUNDTRIP_NUM_CONSUMERS: {{ .Values.tests.roundtrip.numConsumers | default .Values.defaults.numConsumers | quote }} + {{- with .Values.chaos.provider }} + KATES_CHAOS_PROVIDER: {{ . | quote }} + {{- end }} {{- with .Values.faultTolerance }} COM_BMSCOMP_KATES_SERVICE_TOPICSERVICE_CREATETOPIC_TIMEOUT_VALUE: {{ .topicService.timeoutMs | default "35000" | quote }} diff --git a/charts/kates/values.schema.json b/charts/kates/values.schema.json index 65d1ef1a..2e5d2282 100644 --- a/charts/kates/values.schema.json +++ b/charts/kates/values.schema.json @@ -439,6 +439,15 @@ } } }, + "chaos": { + "type": "object", + "properties": { + "provider": { + "type": "string", + "enum": [ "", "litmus-crd", "kubernetes", "hybrid", "noop" ] + } + } + }, "faultTolerance": { "type": "object", "properties": { diff --git a/charts/kates/values.yaml b/charts/kates/values.yaml index 85b72a70..ab2d8eee 100644 --- a/charts/kates/values.yaml +++ b/charts/kates/values.yaml @@ -672,6 +672,15 @@ tests: numRecords: "500000" throughput: "10000" +# -- Chaos provider +chaos: + # -- The chaos provider every fault goes through (KATES_CHAOS_PROVIDER): + # litmus-crd, kubernetes, hybrid or noop. Empty keeps the backend's default, + # litmus-crd. kubernetes, and hybrid without Litmus, need rbac.directChaos. + # `kates deploy --with-chaos=false` sets noop when no Litmus release is + # installed. + provider: "" + # -- PostgreSQL backup CronJob backup: # -- Enable backup CronJob. It dumps the bundled PostgreSQL only, so diff --git a/cli/cmd/deploy_components.go b/cli/cmd/deploy_components.go index 2460f3b9..9e9f7f72 100644 --- a/cli/cmd/deploy_components.go +++ b/cli/cmd/deploy_components.go @@ -1573,6 +1573,17 @@ spec: return nil } +// katesChaosArgs puts the Kates API on the noop chaos provider when this +// deploy installs no Litmus and no chaos release is there. Left on its +// litmus-crd default, the API finds no Litmus, logs an ERROR and falls back to +// noop anyway; set to noop, every fault is skipped by design. +func katesChaosArgs(ctx context.Context, chaosNS string) []string { + if deployWithChaos || isHelmReleaseDeployedFn(ctx, "chaos", chaosNS) { + return nil + } + return []string{"--set", "chaos.provider=noop"} +} + // deployGroupC deploys Group C components (Apps / Sequential): // Apicurio Schema Registry, Kates Backend, Kafka UI, and Litmus Chaos. func deployGroupC(dc *deployContext) error { @@ -1686,6 +1697,7 @@ data: katesArgs = append(katesArgs, dc.scrapeArgs("charts/kates")...) katesArgs = append(katesArgs, dc.prometheusArgs()...) katesArgs = append(katesArgs, dc.cdcDatabaseAccessArgs()...) + katesArgs = append(katesArgs, katesChaosArgs(ctx, chaosNS)...) katesArgs = append(katesArgs, "--timeout", "8m") dl.Println(" - Waiting for Kates backend pods to become ready (this may take 2-3 minutes)...") diff --git a/cli/cmd/deploy_test.go b/cli/cmd/deploy_test.go index 3436ff43..4a536084 100644 --- a/cli/cmd/deploy_test.go +++ b/cli/cmd/deploy_test.go @@ -204,6 +204,9 @@ func TestDeployCommand_SingleTopology(t *testing.T) { if !strings.Contains(cmd, "--set networkPolicy.kafka.namespace=kates-test") { t.Errorf("Expected the Kates NetworkPolicy to allow Kafka in kates-test, got: %s", cmd) } + if !strings.Contains(cmd, "--set chaos.provider=noop") { + t.Errorf("Expected Kates on the noop chaos provider without Litmus, got: %s", cmd) + } } } @@ -282,6 +285,9 @@ func TestDeployCommand_IsolatedTopology(t *testing.T) { if !strings.Contains(cmd, "--set networkPolicy.kafka.namespace=kafka-sys") { t.Errorf("Expected the Kates NetworkPolicy to allow Kafka in kafka-sys, got: %s", cmd) } + if strings.Contains(cmd, "chaos.provider") { + t.Errorf("Expected Kates on the chart's chaos provider with Litmus, got: %s", cmd) + } } if strings.Contains(cmd, "helm upgrade --install chaos") { foundChaos = true @@ -308,6 +314,32 @@ func TestDeployCommand_IsolatedTopology(t *testing.T) { } } +func TestKatesChaosArgs(t *testing.T) { + origChaos, origDeployed := deployWithChaos, isHelmReleaseDeployedFn + t.Cleanup(func() { deployWithChaos, isHelmReleaseDeployedFn = origChaos, origDeployed }) + + for _, tc := range []struct { + name string + withChaos bool + chaosReleased bool + want string + }{ + {"with chaos", true, false, ""}, + {"without chaos, none installed", false, false, "--set chaos.provider=noop"}, + {"without chaos, an earlier release installed", false, true, ""}, + } { + t.Run(tc.name, func(t *testing.T) { + deployWithChaos = tc.withChaos + isHelmReleaseDeployedFn = func(_ context.Context, release, namespace string) bool { + return tc.chaosReleased && release == "chaos" && namespace == "chaos-sys" + } + if got := strings.Join(katesChaosArgs(context.Background(), "chaos-sys"), " "); got != tc.want { + t.Errorf("katesChaosArgs = %q, want %q", got, tc.want) + } + }) + } +} + func TestDeployCommand_Idempotency(t *testing.T) { deployTopology = "single" deployNamespace = "test-ns" diff --git a/docs/book/appendix-d-versions.md b/docs/book/appendix-d-versions.md index 5012b7cd..c8425f74 100644 --- a/docs/book/appendix-d-versions.md +++ b/docs/book/appendix-d-versions.md @@ -22,7 +22,7 @@ Every version the platform pins, in one place. This table is generated from the | `kafka-ui` chart | 0.3.0 (app v1.5.0) | `charts/kafka-ui/Chart.yaml` | | `kates-chaos` chart | 2.2.1 (app 3.28.0) | `charts/kates-chaos/Chart.yaml` | | `kates-platform` chart | 0.7.0 (app 1.0.0) | `charts/kates-platform/Chart.yaml` | -| `kates` chart | 0.11.1 (app 1.25.1) | `charts/kates/Chart.yaml` | +| `kates` chart | 0.11.2 (app 1.25.1) | `charts/kates/Chart.yaml` | | `legacy-kafka` chart | 0.2.0 (app 3.9.1) | `charts/legacy-kafka/Chart.yaml` | | `mirror-maker2` chart | 0.11.4 (app 4.3.1) | `charts/mirror-maker2/Chart.yaml` | | `monitoring` chart | 1.6.0 (app 82.4.3) | `charts/monitoring/Chart.yaml` |