diff --git a/scripts/read-cilium-api-limiter.sh b/scripts/read-cilium-api-limiter.sh index 2d901eebc2..767e69a5ca 100755 --- a/scripts/read-cilium-api-limiter.sh +++ b/scripts/read-cilium-api-limiter.sh @@ -21,6 +21,7 @@ inconclusive() { printf 'INCONCLUSIVE: %s\n' "$1"; exit 3; } # Bound JSON responses and requests. Neither failed kubectl output nor parser diagnostics are public. read_json() { local destination="$1" + local json_shape local -a read_status shift read_failure=COMMAND_FAILED @@ -52,10 +53,25 @@ read_json() { fi return 1 fi - if ! jq -e -s 'length==1 and .[0]!=null' "${destination}" >/dev/null 2>&1; then + # Slurping distinguishes valid JSON null and an empty stream from parse errors. + # None is a measurement; only the fixed classification leaves the private file. + if ! json_shape="$(jq -r -s ' + if length==0 then "EMPTY_OUTPUT" + elif length>1 then "MULTIPLE_JSON_VALUES" + elif .[0]==null then "JSON_NULL" + else "OK" end + ' "${destination}" 2>/dev/null)"; then read_failure=INVALID_JSON return 1 fi + case "${json_shape}" in + OK) ;; + EMPTY_OUTPUT | MULTIPLE_JSON_VALUES | JSON_NULL) + read_failure="${json_shape}" + return 1 + ;; + *) read_failure=INVALID_JSON; return 1 ;; + esac } roster() { local prefix="$1" diff --git a/scripts/tests/test-read-cilium-api-limiter.sh b/scripts/tests/test-read-cilium-api-limiter.sh index b9404499d7..730c22b387 100755 --- a/scripts/tests/test-read-cilium-api-limiter.sh +++ b/scripts/tests/test-read-cilium-api-limiter.sh @@ -126,6 +126,25 @@ require_inconclusive [[ "${output}" == 'INCONCLUSIVE: an agent metric read failed (INVALID_JSON).' ]] || { printf 'FAIL: malformed JSON was not classified: %s\n' "${output}" >&2; exit 1; } +# Successful CLI exits can still carry no measurement. Keep those distinct from +# malformed JSON, but refuse all of them before publishing any samples. +while IFS='|' read -r expected response; do + reset_fixture + printf '%b' "${response}" >"${fixture}/metrics.json" + require_inconclusive + [[ "${output}" == "INCONCLUSIVE: an agent metric read failed (${expected})." ]] || { + printf 'FAIL: expected %s response classification: %s\n' "${expected}" "${output}" >&2; exit 1; + } +done <<'RESPONSES' +EMPTY_OUTPUT| +EMPTY_OUTPUT|\n \t\n +JSON_NULL|null +JSON_NULL| \n null \t\n +MULTIPLE_JSON_VALUES|[]\n[] +MULTIPLE_JSON_VALUES|null\n[] +MULTIPLE_JSON_VALUES|[]\nnull +INVALID_JSON|[]\nPRIVATE_MALFORMED +RESPONSES while IFS='|' read -r expected exit_code message; do reset_fixture printf 'PRIVATE_ERROR https://198.51.100.9:6443 %s\n' "${message}" >"${fixture}/stderr"