Skip to content

fix: remove redundant route.Hosts to prevent false diffs in ADC sync#392

Open
jarvis9443 wants to merge 2 commits intomasterfrom
fix/remove-redundant-route-hosts
Open

fix: remove redundant route.Hosts to prevent false diffs in ADC sync#392
jarvis9443 wants to merge 2 commits intomasterfrom
fix/remove-redundant-route-hosts

Conversation

@jarvis9443
Copy link
Copy Markdown

@jarvis9443 jarvis9443 commented Apr 10, 2026

Problem

The translator sets hosts on both Route and Service when translating ApisixRoute resources. For backends that don't support route-level hosts (where hosts is a service-level concept), this causes a false diff every sync cycle: the local state has route.hosts but the remote state never does, triggering unnecessary PUT requests.

In production, this leads to massive audit log growth — one customer accumulated 8 GB / 4.2M records of redundant UpdateService entries.

Root Cause

In buildRoute() (internal/adc/translator/apisixroute.go), route.Hosts was set to rule.Match.Hosts. However, buildService() already sets service.Hosts to the same value. Since routes inherit hosts from their parent service, the route-level hosts is redundant and can cause false diffs during config sync.

Fix

Remove route.Hosts = rule.Match.Hosts from buildRoute(). service.Hosts remains as the canonical location for host matching.

CI Fix

Also fixes ADC binary extraction in CI workflows: the ghcr.io/api7/adc:dev Docker image now bundles main.cjs instead of main.js at the container root. Updated e2e-test.yml, e2e-test-k8s.yml, and apisix-e2e-test.yml.

Testing

Added unit tests:

  • TestBuildRoute_HostsNotSet: verifies route.Hosts is not set after buildRoute
  • TestBuildService_HostsSet: verifies service.Hosts is correctly set

Summary by CodeRabbit

  • Bug Fixes

    • Route translation no longer assigns host matching to individual routes; hosts are now applied at the service level.
  • Tests

    • Added unit tests to validate host-vs-service host matching behavior during translation.

The translator was setting hosts on both Route and Service for ApisixRoute
resources. Since both APISIX and API7 EE backends support service-level
hosts for route matching (APISIX routes inherit hosts from their parent
service), the route-level hosts is redundant.

For backends that don't support route-level hosts (e.g., API7 EE where
hosts is a service-level concept), this causes a false diff every sync
cycle: the local state has route.hosts but the remote state never will,
triggering unnecessary PUT requests and audit log bloat.

Remove route.Hosts assignment; service.Hosts remains as the canonical
location for host matching.

Ref: api7/rfcs#2
Ref: api7/adc#427
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6d8ae3d0-9db0-4b03-bb6b-645360837efb

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9597c and b1af3da.

📒 Files selected for processing (3)
  • .github/workflows/apisix-e2e-test.yml
  • .github/workflows/e2e-test-k8s.yml
  • .github/workflows/e2e-test.yml

📝 Walkthrough

Walkthrough

Removed per-route host assignment from the APISIXRoute translator, added unit tests verifying hosts are set at the service level (not per-route), and updated CI workflows to copy main.cjs (instead of main.js) from the ADC dev image.

Changes

Cohort / File(s) Summary
Translator change
internal/adc/translator/apisixroute.go
Removed assignment of route.Hosts from rule.Match.Hosts in buildRoute; other route fields unchanged.
Unit tests
internal/adc/translator/apisixroute_test.go
Added tests: TestBuildRoute_HostsNotSet (route.Hosts is nil) and TestBuildService_HostsSet (service.Hosts populated from HTTP match).
CI workflows
.github/workflows/.../apisix-e2e-test.yml, .github/workflows/.../e2e-test-k8s.yml, .github/workflows/.../e2e-test.yml
Changed ADC dev artifact path copied from main.js to main.cjs (still written to adc.js and executed the same way).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • ronething
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
E2e Test Quality Review ⚠️ Warning PR adds only unit tests to internal/adc/translator/apisixroute_test.go with mocked objects, but lacks E2E tests covering the complete ApisixRoute-to-ADC translation flow and critical scenarios like empty/nil hosts, multiple routes per service, and sync cycle validation. Add E2E tests in test/e2e/ using Ginkgo framework to verify complete translation pipeline, deploy ApisixRoute with hosts verification, and confirm fix prevents false diffs during sync cycles.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary change: removing redundant route.Hosts assignment to prevent false diffs in ADC sync cycles.
Security Check ✅ Passed PR removes redundant host assignment and updates workflow binary path; no security vulnerabilities introduced, no sensitive data exposed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/remove-redundant-route-hosts

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/adc/translator/apisixroute_test.go (1)

53-54: Use a fatal length check before indexing service.Routes[0].

assert.Len is non-fatal, so a failed length assertion can still panic on the next line. Prefer require.Len here.

Suggested diff
 import (
 	"testing"
 
 	"github.com/go-logr/logr"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@
-	assert.Len(t, service.Routes, 1)
+	require.Len(t, service.Routes, 1)
 	route := service.Routes[0]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/adc/translator/apisixroute_test.go` around lines 53 - 54, The test
uses assert.Len(t, service.Routes, 1) which is non-fatal and may let the
subsequent indexing of service.Routes[0] panic; change this to a fatal check by
using require.Len(t, service.Routes, 1) in the apisixroute_test.go test before
accessing route := service.Routes[0], and add or ensure the testify/require
import is present so the test fails immediately if the length is wrong.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/adc/translator/apisixroute_test.go`:
- Around line 53-54: The test uses assert.Len(t, service.Routes, 1) which is
non-fatal and may let the subsequent indexing of service.Routes[0] panic; change
this to a fatal check by using require.Len(t, service.Routes, 1) in the
apisixroute_test.go test before accessing route := service.Routes[0], and add or
ensure the testify/require import is present so the test fails immediately if
the length is wrong.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 64bb35aa-caf4-4fe6-b379-157b6ca0c8a1

📥 Commits

Reviewing files that changed from the base of the PR and between 21f983b and 8a9597c.

📒 Files selected for processing (2)
  • internal/adc/translator/apisixroute.go
  • internal/adc/translator/apisixroute_test.go
💤 Files with no reviewable changes (1)
  • internal/adc/translator/apisixroute.go

@jarvis9443
Copy link
Copy Markdown
Author

CI Status: lint ✅, unit tests ✅, misspell ✅, CRD docs ✅

The e2e test failures are a pre-existing infrastructure issue — the ADC dev Docker image (ghcr.io/api7/adc:dev) no longer has main.js at the container root, causing the "Extract adc binary" step to fail with Could not find the file main.js in container adc-temp. This is unrelated to the route.Hosts removal in this PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

conformance test report - apisix-standalone mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-04-10T05:50:51Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    failedTests:
    - HTTPRouteInvalidBackendRefUnknownKind
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

conformance test report - apisix mode

apiVersion: gateway.networking.k8s.io/v1
date: "2026-04-10T05:51:00Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    result: success
    statistics:
      Failed: 0
      Passed: 12
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests succeeded.
- core:
    failedTests:
    - HTTPRouteInvalidBackendRefUnknownKind
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    result: partial
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 0
      Passed: 11
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests partially succeeded
    with 1 test skips.
- core:
    result: partial
    skippedTests:
    - TLSRouteSimpleSameNamespace
    statistics:
      Failed: 0
      Passed: 10
      Skipped: 1
  name: GATEWAY-TLS
  summary: Core tests partially succeeded with 1 test skips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 10, 2026

conformance test report

apiVersion: gateway.networking.k8s.io/v1
date: "2026-04-10T06:12:22Z"
gatewayAPIChannel: experimental
gatewayAPIVersion: v1.3.0
implementation:
  contact: null
  organization: APISIX
  project: apisix-ingress-controller
  url: https://github.com/apache/apisix-ingress-controller.git
  version: v2.0.0
kind: ConformanceReport
mode: default
profiles:
- core:
    failedTests:
    - GatewayModifyListeners
    result: failure
    skippedTests:
    - HTTPRouteHTTPSListener
    statistics:
      Failed: 1
      Passed: 31
      Skipped: 1
  extended:
    failedTests:
    - HTTPRouteBackendProtocolWebSocket
    result: failure
    skippedTests:
    - HTTPRouteRedirectPortAndScheme
    statistics:
      Failed: 1
      Passed: 10
      Skipped: 1
    supportedFeatures:
    - GatewayAddressEmpty
    - GatewayPort8080
    - HTTPRouteBackendProtocolWebSocket
    - HTTPRouteDestinationPortMatching
    - HTTPRouteHostRewrite
    - HTTPRouteMethodMatching
    - HTTPRoutePathRewrite
    - HTTPRoutePortRedirect
    - HTTPRouteQueryParamMatching
    - HTTPRouteRequestMirror
    - HTTPRouteResponseHeaderModification
    - HTTPRouteSchemeRedirect
    unsupportedFeatures:
    - GatewayHTTPListenerIsolation
    - GatewayInfrastructurePropagation
    - GatewayStaticAddresses
    - HTTPRouteBackendProtocolH2C
    - HTTPRouteBackendRequestHeaderModification
    - HTTPRouteBackendTimeout
    - HTTPRouteParentRefPort
    - HTTPRoutePathRedirect
    - HTTPRouteRequestMultipleMirrors
    - HTTPRouteRequestPercentageMirror
    - HTTPRouteRequestTimeout
  name: GATEWAY-HTTP
  summary: Core tests failed with 1 test failures. Extended tests failed with 1 test
    failures.
- core:
    failedTests:
    - GatewayModifyListeners
    - TLSRouteSimpleSameNamespace
    result: failure
    statistics:
      Failed: 2
      Passed: 9
      Skipped: 0
  name: GATEWAY-TLS
  summary: Core tests failed with 2 test failures.
- core:
    failedTests:
    - GRPCExactMethodMatching
    - GRPCRouteHeaderMatching
    - GRPCRouteListenerHostnameMatching
    - GatewayModifyListeners
    result: failure
    statistics:
      Failed: 4
      Passed: 8
      Skipped: 0
  name: GATEWAY-GRPC
  summary: Core tests failed with 4 test failures.

The ghcr.io/api7/adc:dev Docker image now bundles main.cjs instead
of main.js at the container root. Update all workflow files that
extract the ADC binary via docker cp.
@jarvis9443
Copy link
Copy Markdown
Author

Pushed CI fix: updated main.jsmain.cjs in all 3 workflow files (e2e-test.yml, e2e-test-k8s.yml, apisix-e2e-test.yml) to match the updated ghcr.io/api7/adc:dev Docker image layout. The e2e tests should now pass the ADC binary extraction step.

@jarvis9443
Copy link
Copy Markdown
Author

CI Status update: 17/19 checks ✅ passed.

  • e2e-test (apisix-standalone, apisix.apache.org): Infrastructure failure — endpoint readiness timeout, pre-existing issue unrelated to this PR.
  • e2e-test (v2): Stuck in QUEUED state for over 1 hour — appears to be a runner availability issue, not a code issue. All other APISIX E2E tests (including the other apisix.apache.org and networking.k8s.io matrix jobs) passed successfully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant