Skip to content

test(kubernetes): stop TEST 3 failing on the expected apiserver connect error#13701

Open
nic-6443 wants to merge 1 commit into
apache:masterfrom
nic-6443:fix/k8s-discovery-test3-flake
Open

test(kubernetes): stop TEST 3 failing on the expected apiserver connect error#13701
nic-6443 wants to merge 1 commit into
apache:masterfrom
nic-6443:fix/k8s-discovery-test3-flake

Conversation

@nic-6443

@nic-6443 nic-6443 commented Jul 16, 2026

Copy link
Copy Markdown
Member

Description

t/kubernetes/discovery/kubernetes.t TEST 3 fails intermittently on master, for example in this run:

Failed test 't/kubernetes/discovery/kubernetes.t TEST 3: mixing set custom and default values -
pattern "[error]" should not match any line in error.log but matches line
"[error] ... [lua] informer_factory.lua:302: connect apiserver failed,
apiserver.host: sample.com, apiserver.port: 6443, message : connection refused,
context: ngx.timer"

TEST 3 is the only block in the file whose service.host is not the apiserver the job exposes on 127.0.0.1:6443, so its informer can never connect. Configuring discovery.kubernetes starts the informer regardless, it fails to connect in an ngx.timer, and it logs an [error]. The block sets neither error_log nor no_error_log, so t/APISIX.pm gives it the default no_error_log: [error] and the block fails — but only when the connect fails early enough to land inside the block's own window. Each block here has its own yaml_config, so nginx restarts between blocks and a slow-enough resolve means the timer is killed before it ever logs. That is what makes it intermittent rather than a hard failure.

The block only compares the resolved configuration through /compare and never intends to reach an apiserver, so the connect error is expected noise rather than a defect. This overrides no_error_log for that block alone, using the same idiom already used elsewhere in t/.

Why not map the host in /etc/hosts instead?

That was my first instinct too, since ci/common.sh's set_coredns() already pins test.com and admin.apisix.dev that way. It does work for TEST 3 — the tests resolve through /etc/resolv.conf (t::APISIX::local_dns_resolver), which on the runners is systemd-resolved, and that does serve /etc/hosts entries over DNS. Pointing sample.com at 127.0.0.1 makes the informer connect to the real apiserver (ssl_verify defaults to false, so the certificate name does not matter) and the block then passes with its [error] guard intact.

I did not take that route because it does not generalise, and the reason is instructive. TEST 5 is the same kind of block — config comparison only, no no_error_log override — but its hosts cannot be mapped:

  • 1.cluster.com:6445 is https, while the kubectl proxy on 6445 speaks plain HTTP;
  • 2.cluster.com:6443 is http, while 6443 is the HTTPS apiserver.

Mapping all three hostnames to 127.0.0.1 on a local replica of the CI cluster fails TEST 5 deterministically (2 failures on every run), with connect apiserver failed for the first and list failed ... Client sent an HTTP request to an HTTPS server for the second. So sample.com only works by coincidence — it happens to be https on the one port that hosts a real apiserver.

That asymmetry is the point: these hostnames are deliberately fictitious and the blocks only compare configuration, which is why suppressing the expected error is the fix that matches the file rather than a special case that works for one block out of three and quietly breaks another.

How this was verified

On a local replica of the CI cluster (kind with t/kubernetes/configs/kind.yaml, the fixtures from the workflow and the service account token in place), pointing sample.com at an address that refuses 6443 reproduces the CI failure deterministically:

master, sample.com unreachable:   TEST 3 failed 4/4
with this change, same setup:     TEST 3 passed 3/3

The neighbouring blocks are deliberately left alone: they point at 127.0.0.1, which the job actually serves.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible

…ct error

TEST 3 is the only block in the file whose `service.host` is not the
apiserver the CI port-forwards to 127.0.0.1, so its informer can never
connect. The connect failure logs an `[error]`, and whether it lands inside
the block's window depends on how long resolving the host takes, so the
default `no_error_log: [error]` fails the block intermittently:

    TEST 3: mixing set custom and default values - pattern "[error]" should
    not match any line in error.log but matches line "... informer_factory.lua:302:
    connect apiserver failed, apiserver.host: sample.com, apiserver.port: 6443,
    message : connection refused, context: ngx.timer"

The block only compares the resolved configuration and never intends to
reach an apiserver, so the connect error is expected noise. Override
`no_error_log` for this block alone.

The neighbouring blocks are unaffected: they point at 127.0.0.1, which the
job actually serves. (Run the file without an apiserver on 127.0.0.1:6443
and the failure moves to them, with the same signature, while TEST 3 passes.)
@dosubot dosubot Bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Jul 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS This PR changes 0-9 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant