diff --git a/.changelog/16531.txt b/.changelog/16531.txt new file mode 100644 index 0000000000..71f83ad2ac --- /dev/null +++ b/.changelog/16531.txt @@ -0,0 +1,3 @@ +```release-note:bug +gateways: fix HTTPRoute bug where services with a weight not divisible by 10000 are never registered properly +``` \ No newline at end of file diff --git a/agent/xds/routes.go b/agent/xds/routes.go index 6eae88854d..4588f39d61 100644 --- a/agent/xds/routes.go +++ b/agent/xds/routes.go @@ -863,6 +863,7 @@ func (s *ResourceGenerator) makeRouteActionForSplitter( forMeshGateway bool, ) (*envoy_route_v3.Route_Route, error) { clusters := make([]*envoy_route_v3.WeightedCluster_ClusterWeight, 0, len(splits)) + totalWeight := 0 for _, split := range splits { nextNode := chain.Nodes[split.NextNode] @@ -878,8 +879,10 @@ func (s *ResourceGenerator) makeRouteActionForSplitter( // The smallest representable weight is 1/10000 or .01% but envoy // deals with integers so scale everything up by 100x. + weight := int(split.Weight * 100) + totalWeight += weight cw := &envoy_route_v3.WeightedCluster_ClusterWeight{ - Weight: makeUint32Value(int(split.Weight * 100)), + Weight: makeUint32Value(weight), Name: clusterName, } if err := injectHeaderManipToWeightedCluster(split.Definition, cw); err != nil { @@ -893,12 +896,19 @@ func (s *ResourceGenerator) makeRouteActionForSplitter( return nil, fmt.Errorf("number of clusters in splitter must be > 0; got %d", len(clusters)) } + envoyWeightScale := 10000 + if envoyWeightScale < totalWeight { + clusters[0].Weight.Value += uint32(totalWeight - envoyWeightScale) + } else { + clusters[0].Weight.Value += uint32(envoyWeightScale - totalWeight) + } + return &envoy_route_v3.Route_Route{ Route: &envoy_route_v3.RouteAction{ ClusterSpecifier: &envoy_route_v3.RouteAction_WeightedClusters{ WeightedClusters: &envoy_route_v3.WeightedCluster{ Clusters: clusters, - TotalWeight: makeUint32Value(10000), // scaled up 100% + TotalWeight: makeUint32Value(envoyWeightScale), // scaled up 100% }, }, }, diff --git a/test/integration/connect/envoy/case-api-gateway-http-simple/setup.sh b/test/integration/connect/envoy/case-api-gateway-http-simple/setup.sh index 8d0513553d..6dab478e20 100644 --- a/test/integration/connect/envoy/case-api-gateway-http-simple/setup.sh +++ b/test/integration/connect/envoy/case-api-gateway-http-simple/setup.sh @@ -35,6 +35,10 @@ rules = [ services = [ { name = "s1" + }, + { + name = "s2" + weight = 2 } ] } diff --git a/test/integration/connect/envoy/case-api-gateway-http-simple/verify.bats b/test/integration/connect/envoy/case-api-gateway-http-simple/verify.bats index c7378e55bf..72686b3c4f 100644 --- a/test/integration/connect/envoy/case-api-gateway-http-simple/verify.bats +++ b/test/integration/connect/envoy/case-api-gateway-http-simple/verify.bats @@ -22,9 +22,9 @@ load helpers } @test "api gateway should be able to connect to s1 via configured port" { - run retry_long curl -s -f -d hello localhost:9999 + run retry_long curl -s -d hello localhost:9999 [ "$status" -eq 0 ] - [[ "$output" == *"hello"* ]] + [[ ! -z "$output" ]] } @test "api gateway should get an intentions error connecting to s2 via configured port" {