Skip to content

(apigw/httproute) Add support to disable traffic with weight 0 in services#23216

Merged
sujay-hashicorp merged 1 commit into
mainfrom
sujay/fix/route-weight-0
Mar 11, 2026
Merged

(apigw/httproute) Add support to disable traffic with weight 0 in services#23216
sujay-hashicorp merged 1 commit into
mainfrom
sujay/fix/route-weight-0

Conversation

@sujay-hashicorp
Copy link
Copy Markdown
Contributor

@sujay-hashicorp sujay-hashicorp commented Feb 16, 2026

Description

This PR fixes Consul API Gateway behavior for Kubernetes HTTPRoute backends with weight: 0.

Previously, HTTPRoute normalization converted all weight <= 0 values to 1, which caused explicit weight: 0 backends to still receive traffic. This conflicted with Gateway API expectations and customer-observed behavior.

This change updates normalization logic to:

  • Preserve explicit weight: 0 (so zero-weight backends can be excluded from traffic).
  • Continue normalizing negative weights to 1.

Links

Tests

  • With this fix, the routes support definition of 0 weight services.
  • The instance with weight: 0 does not receive any traffic.
HTTPRoute config output

$ consul config read -kind http-route -name quill-route

{
    "Kind": "http-route",
    "Name": "quill-route",
    "Parents": [
        {
            "Kind": "api-gateway",
            "Name": "api-gateway",
            "SectionName": "http-listener"
        }
    ],
    "Rules": [
        {
            "Filters": {
                "Headers": null,
                "URLRewrite": null,
                "RetryFilter": null,
                "TimeoutFilter": null,
                "JWT": null
            },
            "ResponseFilters": {
                "Headers": null
            },
            "Matches": [
                {
                    "Headers": null,
                    "Method": "",
                    "Path": {
                        "Match": "prefix",
                        "Value": "/"
                    },
                    "Query": null
                }
            ],
            "Services": [
                {
                    "Name": "quill-v1",
                    "Weight": 0,
                    "Filters": {
                        "Headers": null,
                        "URLRewrite": null,
                        "RetryFilter": null,
                        "TimeoutFilter": null,
                        "JWT": null
                    },
                    "ResponseFilters": {
                        "Headers": null
                    }
                },
                {
                    "Name": "quill-v2",
                    "Weight": 100,
                    "Filters": {
                        "Headers": null,
                        "URLRewrite": null,
                        "RetryFilter": null,
                        "TimeoutFilter": null,
                        "JWT": null
                    },
                    "ResponseFilters": {
                        "Headers": null
                    }
                }
            ]
        }
    ],
    "Hostnames": null,
    "CreateIndex": 43,
    "ModifyIndex": 80,
    "Status": {
        "Conditions": [
            {
                "Type": "Accepted",
                "Status": "True",
                "Reason": "Accepted",
                "Message": "route is valid",
                "Resource": {
                    "Kind": "",
                    "Name": "",
                    "SectionName": ""
                },
                "LastTransitionTime": "2026-02-16T08:17:57.943208Z"
            },
            {
                "Type": "Bound",
                "Status": "True",
                "Reason": "Bound",
                "Message": "successfully bound route",
                "Resource": {
                    "Kind": "api-gateway",
                    "Name": "api-gateway",
                    "SectionName": "http-listener"
                },
                "LastTransitionTime": "2026-02-16T08:17:57.943215Z"
            }
        ]
    }
}

Traffic Distribution

case 1:
Services = [
  {
    Name = "quill-v1"
    Weight = 100
  },
  {
    Name = "quill-v2"
    Weight = 100
  }
]
Screenshot 2026-02-16 at 14 29 59
case 2:
Services = [
  {
    Name = "quill-v1"
    Weight = 0
  },
  {
    Name = "quill-v2"
    Weight = 100
  }
]
Screenshot 2026-02-16 at 14 32 55

PR Checklist

  • updated test coverage
  • external facing docs updated
  • appropriate backport labels added
  • not a security concern

PCI review checklist

  • I have documented a clear reason for, and description of, the change I am making.

  • If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.

  • If applicable, I've documented the impact of any changes to security controls.

    Examples of changes to security controls include using new access control methods, adding or removing logging pipelines, etc.

@sujay-hashicorp sujay-hashicorp added pr/no-changelog PR does not need a corresponding .changelog entry pr/no-backport labels Feb 16, 2026
@sujay-hashicorp sujay-hashicorp changed the title (discoverychain) Add support to disable routes with weight 0 instead of setting it 1 explicitly (apigw/httproute) Add support to disable routes with weight 0 instead of setting it 1 explicitly Feb 16, 2026
@sujay-hashicorp sujay-hashicorp force-pushed the sujay/fix/route-weight-0 branch from 08b2d33 to 1472d47 Compare February 16, 2026 09:09
@sujay-hashicorp sujay-hashicorp added backport/all Apply backports for all active releases per .release/versions.hcl and removed pr/no-changelog PR does not need a corresponding .changelog entry pr/no-backport labels Feb 16, 2026
@sujay-hashicorp sujay-hashicorp marked this pull request as ready for review February 16, 2026 09:10
@sujay-hashicorp sujay-hashicorp requested review from a team as code owners February 16, 2026 09:10
@sujay-hashicorp sujay-hashicorp changed the title (apigw/httproute) Add support to disable routes with weight 0 instead of setting it 1 explicitly (apigw/httproute) Add support to disable traffic with weight 0 in services Feb 16, 2026
@sujay-hashicorp sujay-hashicorp added the pr/do-not-merge PR cannot be merged in its current form. label Feb 16, 2026
Comment thread agent/structs/config_entry_routes.go Outdated
@@ -105,8 +105,19 @@ func (e *HTTPRouteConfigEntry) Normalize() error {
rule.Matches[j] = normalizeHTTPMatch(match)
}

allServicesHaveZeroWeight := len(rule.Services) > 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

this is misleading, why can't we simply have
allServicesHaveZeroWeight := true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Sure, I have updated it to true. It was set like this so to skip extra processing in cases where there are no services. But I think HTTPRoute must have at least 1 service.

@sujay-hashicorp sujay-hashicorp force-pushed the sujay/fix/route-weight-0 branch from 1472d47 to 67d104e Compare February 19, 2026 10:57
@sujay-hashicorp sujay-hashicorp force-pushed the sujay/fix/route-weight-0 branch 2 times, most recently from 73e47ae to 9e8325a Compare February 19, 2026 14:21
@sujay-hashicorp sujay-hashicorp force-pushed the sujay/fix/route-weight-0 branch from 9e8325a to 6c84033 Compare February 25, 2026 08:36
service.Merge(e.GetEnterpriseMeta())
service.Normalize()
if service.Weight <= 0 {
if service.Weight < 0 {
Copy link
Copy Markdown
Member

@krutibaraiya krutibaraiya Feb 27, 2026

Choose a reason for hiding this comment

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

Wouldn't this reintroduce the same issue again? This normalisation layer looks fine, but down the discovery chain, the 0-weight services would get skipped here and at the end of the loop no spiltter would be created.
Will this handled by Envoy now? If yes, can we add some test coverage to ensure that we return 503?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The above issue was addressed by normalizing 0 weight to 1 by default. Because envoy had not added a support for 0 weight by then. Now after testing I see envoy supports 0 weight so it should not reintroduce the issue.

Copy link
Copy Markdown
Member

@krutibaraiya krutibaraiya left a comment

Choose a reason for hiding this comment

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

LGTM - all relevant cases have been tested by Sujay.

@sujay-hashicorp sujay-hashicorp merged commit 31e303c into main Mar 11, 2026
153 of 155 checks passed
@hc-github-team-consul-core hc-github-team-consul-core added backport/1.22 Changes are backported to 1.22 backport/ent/1.18 Changes are backported to 1.18 ent backport/ent/1.21 changes are backported to 1.21 ent labels Mar 11, 2026
@sujay-hashicorp sujay-hashicorp removed the pr/do-not-merge PR cannot be merged in its current form. label Mar 11, 2026
@hc-github-team-consul-core
Copy link
Copy Markdown
Collaborator

📣 Hi @sujay-hashicorp! a backport is missing for this PR [23216] for versions [1.18,1.21] please perform the backport manually and add the following snippet to your backport PR description:

<details>
	<summary> Overview of commits </summary>
		- <<backport commit 1>>
		- <<backport commit 2>>
		...
</details>

1 similar comment
@hc-github-team-consul-core
Copy link
Copy Markdown
Collaborator

📣 Hi @sujay-hashicorp! a backport is missing for this PR [23216] for versions [1.18,1.21] please perform the backport manually and add the following snippet to your backport PR description:

<details>
	<summary> Overview of commits </summary>
		- <<backport commit 1>>
		- <<backport commit 2>>
		...
</details>

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

Labels

backport/all Apply backports for all active releases per .release/versions.hcl backport/ent/1.18 Changes are backported to 1.18 ent backport/ent/1.21 changes are backported to 1.21 ent backport/1.22 Changes are backported to 1.22

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants