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` |