Skip to content

feat: support default mergeType for BackendTrafficPolicy via EnvoyProxy#9374

Open
H34rtUnd3rB14d3 wants to merge 3 commits into
envoyproxy:mainfrom
H34rtUnd3rB14d3:feat/btp-mergetype-envoyproxy
Open

feat: support default mergeType for BackendTrafficPolicy via EnvoyProxy#9374
H34rtUnd3rB14d3 wants to merge 3 commits into
envoyproxy:mainfrom
H34rtUnd3rB14d3:feat/btp-mergetype-envoyproxy

Conversation

@H34rtUnd3rB14d3

@H34rtUnd3rB14d3 H34rtUnd3rB14d3 commented Jun 29, 2026

Copy link
Copy Markdown

What this PR does / why we need it:

Right now, if a route-level BackendTrafficPolicy doesn't set mergeType, it replaces the
gateway- or listener-level policy instead of merging into it. So if you keep a baseline policy on
the Gateway and add route-level policies on top, you have to remember to put mergeType on every
single one of them, or the baseline silently gets dropped for that route.

This PR lets you set that default once on the EnvoyProxy instead:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
spec:
  backendTrafficPolicy:
    defaultMergeType: StrategicMerge   # or JSONMerge
    excludeLabel: gateway.envoyproxy.io/skip-merge-default   # optional

With that in place, a route-level policy that doesn't set its own mergeType picks up the default
and merges into its parent. A few rules that keep it predictable:

  • An explicit mergeType on the policy always wins.
  • A policy that carries the excludeLabel key opts out and replaces its parent as before.
  • Policies in the control-plane namespace are never defaulted.
  • defaultMergeType only accepts StrategicMerge or JSONMerge - the field's enum rejects Replace, since defaulting to a replace wouldn't do anything.

The default rides the existing EnvoyProxy precedence (GatewayClass-level, per-Gateway, and the
EnvoyGateway default spec), so you can set it broadly and override it on a specific Gateway. When no
default is configured, behavior is exactly the same as today, so this is fully backward compatible.

On the approach: an earlier draft did this with a mutating webhook, but the maintainers preferred
putting it on EnvoyProxy since there's already a default EnvoyProxy concept in EnvoyGateway. This
PR follows that. Everything is resolved at translation time (effectiveMergeType /
anyGatewayMergeDefault in internal/gatewayapi/backendtrafficpolicy.go); no new webhook or CRD.

Tests: unit tests for the two new helpers, golden translator fixtures covering the merge,
exclude-label, control-plane-namespace, and multi-parent cases, and CEL validation for the new
fields. Docs are updated in the BackendTrafficPolicy concept page and the generated API reference.

Which issue(s) this PR fixes:

Fixes #9334


PR Checklist

  • Authorship & ownership: Coding agents / AI assistants are welcome, but I have reviewed every change, understand how and why it works, can explain and maintain it, and take full responsibility for this PR. I have not submitted generated output I do not understand.
  • DCO: All commits are signed off (git commit -s). See DCO: Sign your work.
  • API agreed first: If this PR contains API changes (changes under /api), the API was discussed and agreed before the implementation. The API change can be in a separate PR, or in the same PR, but the API must be agreed before implementation. N/A if this PR does not contain API changes.
  • Required checks pass: make generate gen-check, make lint, and the unit-test/coverage build pass. (Flaky e2e failures are not considered breakages, but gen-check, lint, and coverage MUST pass.)
  • Tests added/updated: New/changed code is covered by appropriate tests. N/A if this PR does not contain code changes.
  • Docs: User-facing changes update the docs, either in this PR or a follow-up PR. N/A if this PR does not contain user-facing changes.
  • Release notes: For any non-trivial change, added a release-note fragment under release-notes/current/<section>/<pr-number>-<slug>.md (see release-notes/current/README.md for sections and naming). N/A if this PR does not contain non-trivial changes.
  • Generated files committed: Ran make gen-check and committed the result if API/helm charts/modules changed.
  • Scope & compatibility: The PR is reasonably scoped (no unrelated changes) and preserves backward compatibility, or any breaking change is called out above and documented in release-notes/current/breaking_changes/.
  • Codex review: Requested a Codex review and addressed all of its comments.
  • Copilot review: Requested a Copilot review and addressed all of its comments.

A route-level BackendTrafficPolicy that leaves mergeType unset currently replaces its parent policy rather than merging into it. That means anyone who wants merging has to remember to set mergeType on every policy.

This adds a backendTrafficPolicy section to the EnvoyProxy API with a defaultMergeType field. When a route-level policy doesn't set its own mergeType, it picks up this default and merges into the parent instead of replacing it. An explicit mergeType still wins, an optional excludeLabel lets a policy opt out, and policies in the control-plane namespace are left untouched. defaultMergeType only accepts StrategicMerge or JSONMerge.

Fixes envoyproxy#9334

Signed-off-by: Maksim Kuchkovskiy <K.Maksim.E@yandex.ru>
@H34rtUnd3rB14d3 H34rtUnd3rB14d3 requested a review from a team as a code owner June 29, 2026 12:30
@netlify

netlify Bot commented Jun 29, 2026

Copy link
Copy Markdown

Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit e942762
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6a439c8b8f11930009c721d6
😎 Deploy Preview https://deploy-preview-9374--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e22e13f6f6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

}

if policy.Spec.MergeType == nil {
if policy.Spec.MergeType == nil && !t.anyGatewayMergeDefault(policy, parentRefCtxs) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep defaulted merges scoped to the Gateway

When defaultMergeType sends an otherwise-unset policy into the per-listener merge path, MergeGateways mode makes t.IRKey(gwNN) the same for every Gateway and the later route application filters only by listener sectionName. For a route attached to two Gateways that both have a listener named http but different parent BackendTrafficPolicies, the first merged parent policy is applied to both listeners and the second is skipped because the route traffic is already set. Include the Gateway identity when applying defaulted merged route policies in merged-Gateway IR.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed

Comment on lines +230 to +232
// +kubebuilder:validation:Enum=StrategicMerge;JSONMerge
// +optional
DefaultMergeType *MergeType `json:"defaultMergeType,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate defaultMergeType outside the CRD path

The enum marker protects EnvoyProxy CRs, but this same EnvoyProxySpec is also used as the EnvoyGateway default spec, which is loaded through ValidateEnvoyGateway rather than CRD validation. A config such as envoyProxy.backendTrafficPolicy.defaultMergeType: Replace is therefore accepted and effectiveMergeType will use Replace, causing the child policy to replace the parent while statuses record it as merged. Add runtime validation for the EnvoyGateway/default-spec path as well.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed

Comment thread api/v1alpha1/envoyproxy_types.go Outdated
// BackendTrafficPolicy defines defaults applied to BackendTrafficPolicy resources
// attached to Gateways that use this EnvoyProxy.
// +optional
BackendTrafficPolicy *BackendTrafficPolicyDefaults `json:"backendTrafficPolicy,omitempty"`

@zirain zirain Jun 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

we may need this for other policy, so this might became a common settings for all the xPolicies(at least for EnvoyExtensionPolicy).

cc @envoyproxy/gateway-maintainers

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

+1, I prefer common setting.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

fixed, pls check that I understood you correctly

Rename the EnvoyProxy policy-defaults type from BackendTrafficPolicyDefaults
to a reusable PolicyDefaults, so other xPolicies can adopt the same shape.
The backendTrafficPolicy field is unchanged; only the type name changes.

Also fixes two review findings:

- Validate defaultMergeType on the EnvoyGateway default EnvoyProxySpec.
  That spec is loaded via config (ValidateEnvoyGateway), not CRD admission,
  so the enum does not apply and a value like Replace could slip through.
  effectiveMergeType also defensively ignores a non-merge value, so a stray
  default can never report a "merged" status while actually replacing.

- Scope a defaulted merged route policy to its own Gateway's listeners. In
  MergeGateways mode all Gateways share one IR keyed by section name, so a
  route attached to two Gateways with different parent policies received the
  first Gateway's merge on both. applyTrafficFeatureToRoute now filters
  listeners by the target Gateway. Adds a merged-gateways golden fixture.

Signed-off-by: Maksim Kuchkovskiy <K.Maksim.E@yandex.ru>
@H34rtUnd3rB14d3 H34rtUnd3rB14d3 requested a review from zirain June 30, 2026 09:10
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.15686% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.20%. Comparing base (01e38bb) to head (64a4275).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
internal/gatewayapi/backendtrafficpolicy.go 90.00% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9374      +/-   ##
==========================================
- Coverage   75.20%   75.20%   -0.01%     
==========================================
  Files         252      252              
  Lines       41049    41095      +46     
==========================================
+ Hits        30871    30905      +34     
- Misses       8084     8090       +6     
- Partials     2094     2100       +6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Add a unit test for applyTrafficFeatureToRoute exercising the TCP and UDP listener skip branches when a route policy targets a different Gateway under the shared MergeGateways IR. The HTTP path is already covered by the merged-gateways golden fixture; this brings the new scoping code to full patch coverage.

Signed-off-by: Maksim Kuchkovskiy <K.Maksim.E@yandex.ru>
// BackendTrafficPolicy defines defaults applied to BackendTrafficPolicy resources
// attached to Gateways that use this EnvoyProxy.
// +optional
BackendTrafficPolicy *PolicyDefaults `json:"backendTrafficPolicy,omitempty"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we add some things like following for better extension?

policyMergeType:
  backendTrafficPolicy:
  securitryPolicy: #we could implament this in the future.

cc @envoyproxy/gateway-maintainers WDYT?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

IMHO, if we decide to do that, I'd name the parent policyDefaults rather than policyMergeType, since each entry also carries excludeLabel and may grow beyond merge settings later.

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.

feat: optional cluster-wide default for BackendTrafficPolicy mergeType

3 participants