From a3880bbbc3361b3e9ec46aede66e0db60ac2d1b0 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sun, 12 Jul 2026 21:53:15 +0200 Subject: [PATCH 1/4] feat(cilium): stage bandwidth manager with BBR --- .github/workflows/ci.yaml | 8 ++ .../bandwidth-manager-bbr/kustomization.yaml | 38 ++++++++ .../controllers/kustomization.yaml | 4 + ...test_cilium_bandwidth_manager_component.py | 95 +++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml create mode 100644 scripts/tests/test_cilium_bandwidth_manager_component.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2f85ec12c..c72e389e3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,6 +41,7 @@ jobs: - 'talos/**' - 'scripts/validate-naming.py' - 'scripts/validate-embedded-json.py' + - 'scripts/tests/test_cilium_bandwidth_manager_component.py' - '.github/workflows/ci.yaml' talos: - 'talos/**' @@ -75,6 +76,13 @@ jobs: # scripts/validate-embedded-json.py (#2480). run: python3 scripts/validate-embedded-json.py + - name: 🚦 Validate default-off Cilium bandwidth manager + # Render the committed and temporary opt-in states so the staged + # bandwidth-manager + BBR component cannot silently become active or + # regress the Hetzner WireGuard settings. Pure stdlib plus the kubectl + # bundled on the GitHub-hosted runner; no cluster or secrets required. + run: python3 -m unittest scripts/tests/test_cilium_bandwidth_manager_component.py -v + - name: ⚙️ Setup KSail # Renovate-managed (datasource github-releases; grouped 'ksail' with the # deploy-prod / dr-rebuild pins). The validate step below renders diff --git a/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml b/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml new file mode 100644 index 000000000..83bf4ebcd --- /dev/null +++ b/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml @@ -0,0 +1,38 @@ +--- +# Default-off staging component for platform#2029 / platform#2607. +# +# Cilium's bandwidth manager installs fq qdiscs and EDT pacing, while BBR +# selects BBR congestion control for eligible egress traffic. The Talos 6.x +# kernel is newer than Cilium's Linux 5.18 minimum for BBR. This component is +# Hetzner-only because that is the production path where egress traverses the +# node datapath and where WireGuard is enabled. +# +# SAFETY: do not reference this component until the activation/soak follow-up. +# `rollOutCiliumPods: true` means enabling it rolls every Cilium agent one node +# at a time and replaces the node qdisc. Activate only in a low-traffic window; +# verify `cilium status --verbose` and unexpected Hubble drops after the roll. +# Roll back by removing the component reference, which restores the chart +# defaults in the next one-node-at-a-time roll. +# +# bpf.masquerade and netkit are deliberately out of scope and require their own +# independently validated slices. +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +patches: + - target: + group: helm.toolkit.fluxcd.io + version: v2 + kind: HelmRelease + name: cilium + namespace: kube-system + patch: | + apiVersion: helm.toolkit.fluxcd.io/v2 + kind: HelmRelease + metadata: + name: cilium + namespace: kube-system + spec: + values: + bandwidthManager: + enabled: true + bbr: true diff --git a/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml b/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml index 7e9d48c4e..a49113995 100644 --- a/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml +++ b/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml @@ -66,6 +66,10 @@ components: # silently-broken keda external-scaler and homepage Deployments. - ../../../../bases/components/helmrelease-drift-detection - ../../../../bases/components/helmrelease-flux-defaults + # Default-off Cilium bandwidth-manager + BBR staging component (#2607). + # Enabling it replaces the node qdisc and rolls every Cilium agent; uncomment + # only in the separate low-traffic activation/soak PR. Rollback = re-comment. + # - cilium/components/bandwidth-manager-bbr/ patches: - path: openbao/patches/store-data-on-hcloud.yaml # Prod-only fail-closed WireGuard encryption (egress strict mode) — see file. diff --git a/scripts/tests/test_cilium_bandwidth_manager_component.py b/scripts/tests/test_cilium_bandwidth_manager_component.py new file mode 100644 index 000000000..0d7a584a8 --- /dev/null +++ b/scripts/tests/test_cilium_bandwidth_manager_component.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python3 +"""Render-level regression tests for the default-off Cilium BBR component.""" + +import os +import pathlib +import subprocess +import tempfile +import textwrap +import unittest + + +ROOT = pathlib.Path(__file__).resolve().parents[2] +COMPONENT = ( + ROOT + / "k8s/providers/hetzner/infrastructure/controllers/cilium/components" + / "bandwidth-manager-bbr" +) +BASE_CILIUM = ROOT / "k8s/bases/infrastructure/controllers/cilium" +PROD_CONTROLLERS = ROOT / "k8s/providers/hetzner/infrastructure/controllers" +PROD_CILIUM = PROD_CONTROLLERS / "cilium" +STRICT_MODE_PATCH = PROD_CILIUM / "patches/enforce-wireguard-strict-mode.yaml" + + +def render(path, unrestricted=False): + """Render a Kustomize root with kubectl and return its YAML stream.""" + command = ["kubectl", "kustomize", str(path)] + if unrestricted: + command.extend(["--load-restrictor", "LoadRestrictionsNone"]) + result = subprocess.run( + command, + check=False, + capture_output=True, + text=True, + ) + if result.returncode != 0: + raise AssertionError(result.stderr.strip()) + return result.stdout + + +def cilium_release(rendered): + """Return the Cilium HelmRelease document from a rendered YAML stream.""" + for document in rendered.split("\n---\n"): + if "kind: HelmRelease" in document and "name: cilium" in document: + return document + raise AssertionError("render did not contain the Cilium HelmRelease") + + +class CiliumBandwidthManagerComponentTests(unittest.TestCase): + """Pin both the default-off and explicit opt-in render states.""" + + def test_committed_prod_overlay_keeps_bandwidth_manager_off(self): + parent = (PROD_CONTROLLERS / "kustomization.yaml").read_text(encoding="utf-8") + self.assertIn( + "# - cilium/components/bandwidth-manager-bbr/", + parent, + ) + self.assertNotIn( + "\n - cilium/components/bandwidth-manager-bbr/", + parent, + ) + self.assertNotIn("bandwidthManager:", cilium_release(render(BASE_CILIUM))) + + def test_opt_in_render_enables_bbr_and_preserves_wireguard(self): + self.assertTrue(COMPONENT.is_dir(), f"missing component: {COMPONENT}") + with tempfile.TemporaryDirectory(prefix=".platform-cilium-bbr-", dir=ROOT) as tmp: + base = os.path.relpath(BASE_CILIUM, tmp) + provider = os.path.relpath(PROD_CILIUM, tmp) + component = os.path.relpath(COMPONENT, tmp) + strict_mode_patch = os.path.relpath(STRICT_MODE_PATCH, tmp) + pathlib.Path(tmp, "kustomization.yaml").write_text( + textwrap.dedent( + f"""\ + --- + apiVersion: kustomize.config.k8s.io/v1beta1 + kind: Kustomization + resources: + - {base} + - {provider} + components: + - {component} + patches: + - path: {strict_mode_patch} + """ + ), + encoding="utf-8", + ) + release = cilium_release(render(tmp, unrestricted=True)) + + self.assertIn("bandwidthManager:\n bbr: true\n enabled: true", release) + self.assertIn("encryption:\n enabled: true\n nodeEncryption: false", release) + self.assertIn("type: wireguard", release) + + +if __name__ == "__main__": + unittest.main() From d8c9c59ea362ca5b48185482db31ef4cc1b068c6 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Sun, 12 Jul 2026 23:01:41 +0200 Subject: [PATCH 2/4] fix(cilium): guard bandwidth manager activation --- .../bandwidth-manager-bbr/kustomization.yaml | 15 ++++++++++++- .../controllers/kustomization.yaml | 8 ++++--- ...test_cilium_bandwidth_manager_component.py | 21 +++++++++---------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml b/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml index 83bf4ebcd..cccd20dad 100644 --- a/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml +++ b/k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/kustomization.yaml @@ -7,7 +7,19 @@ # Hetzner-only because that is the production path where egress traverses the # node datapath and where WireGuard is enabled. # -# SAFETY: do not reference this component until the activation/soak follow-up. +# HOST-NAMESPACE GUARD: pod BBR also requires eBPF host routing. The current +# tunnel-mode datapath intentionally keeps bpf.masquerade off, so +# bbrHostNamespaceOnly stays true and limits BBR to hostNetwork workloads. +# Do not remove that guard until #2609 has merged and completed its own soak. +# +# DEVICE GUARD: production currently pins two heterogeneous private-NIC names +# (`enp7s0` on workers, `eth1` on control planes). Cilium requires every +# manually listed bandwidth-manager device name on every managed node. Do not +# activate this component until #2610 provides a homogeneous selection while +# preserving the private-NIC WireGuard and mutual-auth path. +# +# SAFETY: this component is staged, not activation-ready. Keep it unreferenced +# until both #2609 and #2610 are complete, then use a separate activation/soak. # `rollOutCiliumPods: true` means enabling it rolls every Cilium agent one node # at a time and replaces the node qdisc. Activate only in a low-traffic window; # verify `cilium status --verbose` and unexpected Hubble drops after the roll. @@ -36,3 +48,4 @@ patches: bandwidthManager: enabled: true bbr: true + bbrHostNamespaceOnly: true diff --git a/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml b/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml index a49113995..751b10956 100644 --- a/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml +++ b/k8s/providers/hetzner/infrastructure/controllers/kustomization.yaml @@ -66,9 +66,11 @@ components: # silently-broken keda external-scaler and homepage Deployments. - ../../../../bases/components/helmrelease-drift-detection - ../../../../bases/components/helmrelease-flux-defaults - # Default-off Cilium bandwidth-manager + BBR staging component (#2607). - # Enabling it replaces the node qdisc and rolls every Cilium agent; uncomment - # only in the separate low-traffic activation/soak PR. Rollback = re-comment. + # Default-off Cilium bandwidth-manager + host-only BBR staging component + # (#2607). It is not activation-ready: #2609 must prove pod-BBR datapath + # prerequisites and #2610 must make device selection homogeneous first. + # Enabling replaces the node qdisc and rolls every Cilium agent; after both + # guards close, use a separate low-traffic activation. Rollback = re-comment. # - cilium/components/bandwidth-manager-bbr/ patches: - path: openbao/patches/store-data-on-hcloud.yaml diff --git a/scripts/tests/test_cilium_bandwidth_manager_component.py b/scripts/tests/test_cilium_bandwidth_manager_component.py index 0d7a584a8..ea13cf967 100644 --- a/scripts/tests/test_cilium_bandwidth_manager_component.py +++ b/scripts/tests/test_cilium_bandwidth_manager_component.py @@ -15,10 +15,7 @@ / "k8s/providers/hetzner/infrastructure/controllers/cilium/components" / "bandwidth-manager-bbr" ) -BASE_CILIUM = ROOT / "k8s/bases/infrastructure/controllers/cilium" PROD_CONTROLLERS = ROOT / "k8s/providers/hetzner/infrastructure/controllers" -PROD_CILIUM = PROD_CONTROLLERS / "cilium" -STRICT_MODE_PATCH = PROD_CILIUM / "patches/enforce-wireguard-strict-mode.yaml" def render(path, unrestricted=False): @@ -58,15 +55,13 @@ def test_committed_prod_overlay_keeps_bandwidth_manager_off(self): "\n - cilium/components/bandwidth-manager-bbr/", parent, ) - self.assertNotIn("bandwidthManager:", cilium_release(render(BASE_CILIUM))) + self.assertNotIn("bandwidthManager:", cilium_release(render(PROD_CONTROLLERS))) def test_opt_in_render_enables_bbr_and_preserves_wireguard(self): self.assertTrue(COMPONENT.is_dir(), f"missing component: {COMPONENT}") with tempfile.TemporaryDirectory(prefix=".platform-cilium-bbr-", dir=ROOT) as tmp: - base = os.path.relpath(BASE_CILIUM, tmp) - provider = os.path.relpath(PROD_CILIUM, tmp) + base = os.path.relpath(PROD_CONTROLLERS, tmp) component = os.path.relpath(COMPONENT, tmp) - strict_mode_patch = os.path.relpath(STRICT_MODE_PATCH, tmp) pathlib.Path(tmp, "kustomization.yaml").write_text( textwrap.dedent( f"""\ @@ -75,18 +70,22 @@ def test_opt_in_render_enables_bbr_and_preserves_wireguard(self): kind: Kustomization resources: - {base} - - {provider} components: - {component} - patches: - - path: {strict_mode_patch} """ ), encoding="utf-8", ) release = cilium_release(render(tmp, unrestricted=True)) - self.assertIn("bandwidthManager:\n bbr: true\n enabled: true", release) + self.assertIn( + "bandwidthManager:\n" + " bbr: true\n" + " bbrHostNamespaceOnly: true\n" + " enabled: true", + release, + ) + self.assertNotIn("bpf:\n masquerade: true", release) self.assertIn("encryption:\n enabled: true\n nodeEncryption: false", release) self.assertIn("type: wireguard", release) From 0a1f81201713a9f3ec9e517a9f45912e30e99751 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Mon, 13 Jul 2026 09:24:28 +0200 Subject: [PATCH 3/4] test(cilium): replace Python BBR test harness --- .github/workflows/ci.yaml | 9 +- ...test-cilium-bandwidth-manager-component.sh | 109 ++++++++++++++++++ ...test_cilium_bandwidth_manager_component.py | 94 --------------- .../kustomization.yaml | 7 ++ 4 files changed, 121 insertions(+), 98 deletions(-) create mode 100755 scripts/tests/test-cilium-bandwidth-manager-component.sh delete mode 100644 scripts/tests/test_cilium_bandwidth_manager_component.py create mode 100644 tests/cilium-bandwidth-manager-bbr/kustomization.yaml diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index c72e389e3..7e5374e16 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,7 +41,8 @@ jobs: - 'talos/**' - 'scripts/validate-naming.py' - 'scripts/validate-embedded-json.py' - - 'scripts/tests/test_cilium_bandwidth_manager_component.py' + - 'scripts/tests/test-cilium-bandwidth-manager-component.sh' + - 'tests/cilium-bandwidth-manager-bbr/**' - '.github/workflows/ci.yaml' talos: - 'talos/**' @@ -79,9 +80,9 @@ jobs: - name: 🚦 Validate default-off Cilium bandwidth manager # Render the committed and temporary opt-in states so the staged # bandwidth-manager + BBR component cannot silently become active or - # regress the Hetzner WireGuard settings. Pure stdlib plus the kubectl - # bundled on the GitHub-hosted runner; no cluster or secrets required. - run: python3 -m unittest scripts/tests/test_cilium_bandwidth_manager_component.py -v + # regress the Hetzner WireGuard settings. Bash plus the kubectl bundled + # on the GitHub-hosted runner; no cluster or secrets required. + run: bash scripts/tests/test-cilium-bandwidth-manager-component.sh - name: ⚙️ Setup KSail # Renovate-managed (datasource github-releases; grouped 'ksail' with the diff --git a/scripts/tests/test-cilium-bandwidth-manager-component.sh b/scripts/tests/test-cilium-bandwidth-manager-component.sh new file mode 100755 index 000000000..6285b57e9 --- /dev/null +++ b/scripts/tests/test-cilium-bandwidth-manager-component.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash + +set -euo pipefail + +root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +readonly root_dir +readonly controllers_dir="${root_dir}/k8s/providers/hetzner/infrastructure/controllers" +readonly opt_in_fixture="${root_dir}/tests/cilium-bandwidth-manager-bbr" + +fail() { + printf 'FAIL: %s\n' "$1" >&2 + exit 1 +} + +extract_cilium_release() { + awk ' + function reset_document() { + document = "" + is_helm_release = 0 + is_cilium = 0 + } + + function emit_if_cilium() { + if (is_helm_release && is_cilium) { + printf "%s", document + found = 1 + exit + } + reset_document() + } + + BEGIN { reset_document() } + /^---[[:space:]]*$/ { emit_if_cilium(); next } + { + document = document $0 ORS + if ($0 ~ /^kind:[[:space:]]*HelmRelease[[:space:]]*$/) { + is_helm_release = 1 + } + if ($0 ~ /^ name:[[:space:]]*cilium[[:space:]]*$/) { + is_cilium = 1 + } + } + END { + if (!found && is_helm_release && is_cilium) { + printf "%s", document + found = 1 + } + if (!found) { + exit 1 + } + } + ' +} + +require_text() { + local haystack="$1" + local needle="$2" + local description="$3" + + grep -Fq -- "$needle" <<<"${haystack}" || fail "${description}" +} + +reject_text() { + local haystack="$1" + local needle="$2" + local description="$3" + + if grep -Fq -- "$needle" <<<"${haystack}"; then + fail "${description}" + fi +} + +readonly controllers_kustomization="${controllers_dir}/kustomization.yaml" +grep -Fxq ' # - cilium/components/bandwidth-manager-bbr/' "${controllers_kustomization}" || + fail 'the production controllers overlay must retain the documented opt-in reference' +if grep -Fxq ' - cilium/components/bandwidth-manager-bbr/' "${controllers_kustomization}"; then + fail 'the production controllers overlay must keep the BBR component disabled by default' +fi + +default_release="$(kubectl kustomize "${controllers_dir}" | extract_cilium_release)" || + fail 'the default production controllers render has no Cilium HelmRelease' +reject_text \ + "${default_release}" \ + 'bandwidthManager:' \ + 'the default production render unexpectedly enables the bandwidth manager' + +opt_in_release="$( + kubectl kustomize "${opt_in_fixture}" --load-restrictor LoadRestrictionsNone | + extract_cilium_release +)" || fail 'the opt-in fixture render has no Cilium HelmRelease' + +require_text \ + "${opt_in_release}" \ + $'bandwidthManager:\n bbr: true\n bbrHostNamespaceOnly: true\n enabled: true' \ + 'the opt-in render must enable host-namespace-only BBR' +reject_text \ + "${opt_in_release}" \ + $'bpf:\n masquerade: true' \ + 'the opt-in render must not enable BPF masquerading' +require_text \ + "${opt_in_release}" \ + $'encryption:\n enabled: true\n nodeEncryption: false' \ + 'the opt-in render must preserve the production encryption settings' +require_text \ + "${opt_in_release}" \ + 'type: wireguard' \ + 'the opt-in render must preserve WireGuard encryption' + +printf 'PASS: Cilium bandwidth manager is default-off and the opt-in render preserves production guards\n' diff --git a/scripts/tests/test_cilium_bandwidth_manager_component.py b/scripts/tests/test_cilium_bandwidth_manager_component.py deleted file mode 100644 index ea13cf967..000000000 --- a/scripts/tests/test_cilium_bandwidth_manager_component.py +++ /dev/null @@ -1,94 +0,0 @@ -#!/usr/bin/env python3 -"""Render-level regression tests for the default-off Cilium BBR component.""" - -import os -import pathlib -import subprocess -import tempfile -import textwrap -import unittest - - -ROOT = pathlib.Path(__file__).resolve().parents[2] -COMPONENT = ( - ROOT - / "k8s/providers/hetzner/infrastructure/controllers/cilium/components" - / "bandwidth-manager-bbr" -) -PROD_CONTROLLERS = ROOT / "k8s/providers/hetzner/infrastructure/controllers" - - -def render(path, unrestricted=False): - """Render a Kustomize root with kubectl and return its YAML stream.""" - command = ["kubectl", "kustomize", str(path)] - if unrestricted: - command.extend(["--load-restrictor", "LoadRestrictionsNone"]) - result = subprocess.run( - command, - check=False, - capture_output=True, - text=True, - ) - if result.returncode != 0: - raise AssertionError(result.stderr.strip()) - return result.stdout - - -def cilium_release(rendered): - """Return the Cilium HelmRelease document from a rendered YAML stream.""" - for document in rendered.split("\n---\n"): - if "kind: HelmRelease" in document and "name: cilium" in document: - return document - raise AssertionError("render did not contain the Cilium HelmRelease") - - -class CiliumBandwidthManagerComponentTests(unittest.TestCase): - """Pin both the default-off and explicit opt-in render states.""" - - def test_committed_prod_overlay_keeps_bandwidth_manager_off(self): - parent = (PROD_CONTROLLERS / "kustomization.yaml").read_text(encoding="utf-8") - self.assertIn( - "# - cilium/components/bandwidth-manager-bbr/", - parent, - ) - self.assertNotIn( - "\n - cilium/components/bandwidth-manager-bbr/", - parent, - ) - self.assertNotIn("bandwidthManager:", cilium_release(render(PROD_CONTROLLERS))) - - def test_opt_in_render_enables_bbr_and_preserves_wireguard(self): - self.assertTrue(COMPONENT.is_dir(), f"missing component: {COMPONENT}") - with tempfile.TemporaryDirectory(prefix=".platform-cilium-bbr-", dir=ROOT) as tmp: - base = os.path.relpath(PROD_CONTROLLERS, tmp) - component = os.path.relpath(COMPONENT, tmp) - pathlib.Path(tmp, "kustomization.yaml").write_text( - textwrap.dedent( - f"""\ - --- - apiVersion: kustomize.config.k8s.io/v1beta1 - kind: Kustomization - resources: - - {base} - components: - - {component} - """ - ), - encoding="utf-8", - ) - release = cilium_release(render(tmp, unrestricted=True)) - - self.assertIn( - "bandwidthManager:\n" - " bbr: true\n" - " bbrHostNamespaceOnly: true\n" - " enabled: true", - release, - ) - self.assertNotIn("bpf:\n masquerade: true", release) - self.assertIn("encryption:\n enabled: true\n nodeEncryption: false", release) - self.assertIn("type: wireguard", release) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/cilium-bandwidth-manager-bbr/kustomization.yaml b/tests/cilium-bandwidth-manager-bbr/kustomization.yaml new file mode 100644 index 000000000..1248c925e --- /dev/null +++ b/tests/cilium-bandwidth-manager-bbr/kustomization.yaml @@ -0,0 +1,7 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ../../k8s/providers/hetzner/infrastructure/controllers/ +components: + - ../../k8s/providers/hetzner/infrastructure/controllers/cilium/components/bandwidth-manager-bbr/ From 5719b847093b247cb7333628b673369ec9e1815e Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Mon, 13 Jul 2026 09:46:19 +0200 Subject: [PATCH 4/4] test(cilium): drain render stream in extractor --- ...test-cilium-bandwidth-manager-component.sh | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/scripts/tests/test-cilium-bandwidth-manager-component.sh b/scripts/tests/test-cilium-bandwidth-manager-component.sh index 6285b57e9..50a106b8f 100755 --- a/scripts/tests/test-cilium-bandwidth-manager-component.sh +++ b/scripts/tests/test-cilium-bandwidth-manager-component.sh @@ -21,10 +21,9 @@ extract_cilium_release() { } function emit_if_cilium() { - if (is_helm_release && is_cilium) { + if (!found && is_helm_release && is_cilium) { printf "%s", document found = 1 - exit } reset_document() } @@ -32,18 +31,19 @@ extract_cilium_release() { BEGIN { reset_document() } /^---[[:space:]]*$/ { emit_if_cilium(); next } { - document = document $0 ORS - if ($0 ~ /^kind:[[:space:]]*HelmRelease[[:space:]]*$/) { - is_helm_release = 1 - } - if ($0 ~ /^ name:[[:space:]]*cilium[[:space:]]*$/) { - is_cilium = 1 + if (!found) { + document = document $0 ORS + if ($0 ~ /^kind:[[:space:]]*HelmRelease[[:space:]]*$/) { + is_helm_release = 1 + } + if ($0 ~ /^ name:[[:space:]]*cilium[[:space:]]*$/) { + is_cilium = 1 + } } } END { - if (!found && is_helm_release && is_cilium) { - printf "%s", document - found = 1 + if (!found) { + emit_if_cilium() } if (!found) { exit 1 @@ -70,6 +70,24 @@ reject_text() { fi } +extractor_probe="$( + { + printf '%s\n' \ + 'apiVersion: helm.toolkit.fluxcd.io/v2' \ + 'kind: HelmRelease' \ + 'metadata:' \ + ' name: cilium' \ + '---' + for ((line = 0; line < 10000; line++)); do + printf '# trailing render content %05d\n' "${line}" + done + } | extract_cilium_release +)" || fail 'the Cilium release extractor must consume the complete render stream' +require_text \ + "${extractor_probe}" \ + 'kind: HelmRelease' \ + 'the Cilium release extractor must return the matching document' + readonly controllers_kustomization="${controllers_dir}/kustomization.yaml" grep -Fxq ' # - cilium/components/bandwidth-manager-bbr/' "${controllers_kustomization}" || fail 'the production controllers overlay must retain the documented opt-in reference'