Skip to content

Bug: setWeight incorrectly modifies header-based routing rules, breaking canary traffic routing #158

@guoliangmiao

Description

@guoliangmiao

Description

I've discovered a bug in the rollouts-plugin-trafficrouter-gatewayapi plugin where the setWeight operation incorrectly modifies ALL routing rules, including header-based routes, causing canary traffic routing to fail.

Problem

The plugin's setWeight logic is too aggressive - it doesn't distinguish between regular routing rules and header-based routing rules. When setting weights, it modifies the weight of all backend references pointing to the canary service, including those in header-match rules that should remain unaffected.

Root Cause

In the plugin source code at pkg/plugin/httproute.go, the setHTTPRouteWeight function implements the following logic:

// 1. Get all rules from the HTTPRoute
routeRuleList := HTTPRouteRuleList(httpRoute.Spec.Rules)

// 2. Find all BackendRefs pointing to the Canary service across ALL rules
canaryBackendRefs, err := getBackendRefs(canaryServiceName, routeRuleList)

// 3. Set the weight for ALL found references to desiredWeight
for _, ref := range canaryBackendRefs {
    ref.Weight = &desiredWeight
}

Reproduction Steps

When a Rollout progresses through its first step with both header routing and weight configuration:

setHeaderRoute executes first: The plugin adds a new rule (e.g., Rule #2) to the HTTPRoute that matches the X-Canary-start header and routes to the Canary service with default weight (effectively 100%).

setWeight: 0 executes: The plugin runs the logic described above:

  • It iterates through ALL rules in the HTTPRoute
  • It finds the Canary service in Rule [BE]:Add Gateway API plugin #1 (main route) and sets weight to 0 ✓
  • It also finds the Canary service in Rule Update readme #2 (header route) and sets its weight to 0 ✗

Result

The generated HTTPRoute YAML looks like this:

spec:
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: my-app-stable
          port: 80
          weight: 100
        - name: my-app-canary
          port: 80
          weight: 0 
    - matches:
        - headers:
            - name: X-Canary-start
              value: "true"
          path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: my-app-canary
          port: 80
          weight: 100 

Impact:

The header-based routing rule exists but doesn't receive any traffic (or produces undefined behavior) because weight: 0 effectively disables it.

Expected Behavior

setWeight should only control the traffic distribution in the main routing rule and should NOT modify weights in header-based routing rules created by setHeaderRoute.Proposed FixWhen updating weights, the plugin should skip rules that were created by setHeaderRoute.

This could be achieved by:

  1. Adding metadata/annotations to identify header-based rules
  2. Checking for the presence of header matches before modifying weights
  3. Only applying weight changes to the primary/default route rule

Would appreciate any guidance on this issue or if there's a workaround available. Happy to provide more details or help with a PR if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions