Skip to content

Commit d35cedd

Browse files
xds/resolver: pass route's auto_host_rewrite to LB picker (gRFC A81) (#8740)
This PR implements the ConfigSelector changes required for [gRFC A81](https://github.com/grpc/proposal/blob/master/A81-xds-authority-rewriting.md). It ensures that the `auto_host_rewrite` field from the xDS Route Configuration is correctly propagated through the resolver and made available to the Load Balancer picker via the RPC context. ### Key Changes: * Pass the `AutoHostRewrite` field value from `Route` struct via RPC context. * Add helper functions for `AutoHostRewrite` in `internal/xds/balancer/cluserimpl/picker.go`. * Update `ConfigSelector.SelectConfig` to pass the `AutoHostRewrite` boolean in RPC context. RELEASE NOTES: None
1 parent d931fdc commit d35cedd

File tree

4 files changed

+179
-0
lines changed

4 files changed

+179
-0
lines changed

internal/xds/balancer/clusterimpl/picker.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,25 @@ func (d *picker) Pick(info balancer.PickInfo) (balancer.PickResult, error) {
194194

195195
return pr, err
196196
}
197+
198+
// autoHostRewriteKey is the context key used to store the value of
199+
// route's autoHostRewrite in the RPC context.
200+
type autoHostRewriteKey struct{}
201+
202+
// autoHostRewrite retrieves the autoHostRewrite value from the provided context.
203+
func autoHostRewrite(ctx context.Context) bool {
204+
v, _ := ctx.Value(autoHostRewriteKey{}).(bool)
205+
return v
206+
}
207+
208+
// AutoHostRewriteForTesting returns the value of autoHostRewrite field;
209+
// to be used for testing only.
210+
func AutoHostRewriteForTesting(ctx context.Context) bool {
211+
return autoHostRewrite(ctx)
212+
}
213+
214+
// SetAutoHostRewrite adds the autoHostRewrite value to the context for
215+
// the xds_cluster_impl LB policy to pick.
216+
func SetAutoHostRewrite(ctx context.Context, autohostRewrite bool) context.Context {
217+
return context.WithValue(ctx, autoHostRewriteKey{}, autohostRewrite)
218+
}

internal/xds/resolver/serviceconfig.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
iringhash "google.golang.org/grpc/internal/ringhash"
3636
"google.golang.org/grpc/internal/serviceconfig"
3737
"google.golang.org/grpc/internal/wrr"
38+
"google.golang.org/grpc/internal/xds/balancer/clusterimpl"
3839
"google.golang.org/grpc/internal/xds/balancer/clustermanager"
3940
"google.golang.org/grpc/internal/xds/httpfilter"
4041
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource"
@@ -114,6 +115,7 @@ type route struct {
114115
maxStreamDuration time.Duration
115116
retryConfig *xdsresource.RetryConfig
116117
hashPolicies []*xdsresource.HashPolicy
118+
autoHostRewrite bool
117119
}
118120

119121
func (r route) String() string {
@@ -197,6 +199,7 @@ func (cs *configSelector) SelectConfig(rpcInfo iresolver.RPCInfo) (*iresolver.RP
197199

198200
lbCtx := clustermanager.SetPickedCluster(rpcInfo.Context, cluster.name)
199201
lbCtx = iringhash.SetXDSRequestHash(lbCtx, cs.generateHash(rpcInfo, rt.hashPolicies))
202+
lbCtx = clusterimpl.SetAutoHostRewrite(lbCtx, rt.autoHostRewrite)
200203

201204
config := &iresolver.RPCConfig{
202205
// Communicate to the LB policy the chosen cluster and request hash, if Ring Hash LB policy.

internal/xds/resolver/xds_resolver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ func (r *xdsResolver) newConfigSelector() (*configSelector, error) {
392392

393393
cs.routes[i].retryConfig = rt.RetryConfig
394394
cs.routes[i].hashPolicies = rt.HashPolicies
395+
cs.routes[i].autoHostRewrite = rt.AutoHostRewrite
395396
}
396397

397398
// Account for this config selector's clusters. Do this after no further

internal/xds/resolver/xds_resolver_test.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@ import (
3535
"google.golang.org/grpc/codes"
3636
estats "google.golang.org/grpc/experimental/stats"
3737
"google.golang.org/grpc/internal"
38+
"google.golang.org/grpc/internal/envconfig"
3839
iresolver "google.golang.org/grpc/internal/resolver"
3940
iringhash "google.golang.org/grpc/internal/ringhash"
4041
"google.golang.org/grpc/internal/testutils"
4142
"google.golang.org/grpc/internal/testutils/xds/e2e"
43+
"google.golang.org/grpc/internal/xds/balancer/clusterimpl"
4244
"google.golang.org/grpc/internal/xds/balancer/clustermanager"
4345
"google.golang.org/grpc/internal/xds/bootstrap"
46+
serverFeature "google.golang.org/grpc/internal/xds/clients/xdsclient"
4447
rinternal "google.golang.org/grpc/internal/xds/resolver/internal"
4548
"google.golang.org/grpc/internal/xds/xdsclient"
4649
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version"
@@ -1297,3 +1300,153 @@ func (s) TestConfigSelector_FailureCases(t *testing.T) {
12971300
func newDurationP(d time.Duration) *time.Duration {
12981301
return &d
12991302
}
1303+
1304+
// TestResolver_AutoHostRewrite verifies the propagation of the AutoHostRewrite
1305+
// field from the xDS resolver.
1306+
//
1307+
// Per gRFC A81, this feature should only be active if two conditions met:
1308+
// 1. The environment variable (XDSAuthorityRewrite) is enabled.
1309+
// 2. The xDS server is marked as "trusted_xds_server" in the bootstrap config.
1310+
func (s) TestResolver_AutoHostRewrite(t *testing.T) {
1311+
for _, tt := range []struct {
1312+
name string
1313+
autoHostRewrite bool
1314+
envconfig bool
1315+
serverfeature serverFeature.ServerFeature
1316+
wantAutoHostRewrite bool
1317+
}{
1318+
{
1319+
name: "EnvVarDisabled_NonTrustedServer_AutoHostRewriteOff",
1320+
autoHostRewrite: false,
1321+
envconfig: false,
1322+
wantAutoHostRewrite: false,
1323+
},
1324+
{
1325+
name: "EnvVarDisabled_NonTrustedServer_AutoHostRewriteOn",
1326+
autoHostRewrite: true,
1327+
envconfig: false,
1328+
wantAutoHostRewrite: false,
1329+
},
1330+
{
1331+
name: "EnvVarDisabled_TrustedServer_AutoHostRewriteOff",
1332+
autoHostRewrite: false,
1333+
envconfig: false,
1334+
serverfeature: serverFeature.ServerFeatureTrustedXDSServer,
1335+
wantAutoHostRewrite: false,
1336+
},
1337+
{
1338+
name: "EnvVarDisabled_TrustedServer_AutoHostRewriteOn",
1339+
autoHostRewrite: true,
1340+
envconfig: false,
1341+
serverfeature: serverFeature.ServerFeatureTrustedXDSServer,
1342+
wantAutoHostRewrite: false,
1343+
},
1344+
{
1345+
name: "EnvVarEnabled_NonTrustedServer_AutoHostRewriteOff",
1346+
autoHostRewrite: false,
1347+
envconfig: true,
1348+
wantAutoHostRewrite: false,
1349+
},
1350+
{
1351+
name: "EnvVarEnabled_NonTrustedServer_AutoHostRewriteOn",
1352+
autoHostRewrite: true,
1353+
envconfig: true,
1354+
wantAutoHostRewrite: false,
1355+
},
1356+
{
1357+
name: "EnvVarEnabled_TrustedServer_AutoHostRewriteOff",
1358+
autoHostRewrite: false,
1359+
envconfig: true,
1360+
serverfeature: serverFeature.ServerFeatureTrustedXDSServer,
1361+
wantAutoHostRewrite: false,
1362+
},
1363+
{
1364+
name: "EnvVarEnabled_TrustedServer_AutoHostRewriteOn",
1365+
autoHostRewrite: true,
1366+
envconfig: true,
1367+
serverfeature: serverFeature.ServerFeatureTrustedXDSServer,
1368+
wantAutoHostRewrite: true,
1369+
},
1370+
} {
1371+
t.Run(tt.name, func(t *testing.T) {
1372+
testutils.SetEnvConfig(t, &envconfig.XDSAuthorityRewrite, tt.envconfig)
1373+
1374+
// Spin up an xDS management server for the test.
1375+
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
1376+
defer cancel()
1377+
nodeID := uuid.New().String()
1378+
mgmtServer := e2e.StartManagementServer(t, e2e.ManagementServerOptions{AllowResourceSubset: true})
1379+
defer mgmtServer.Stop()
1380+
1381+
// Configure the management server with a good listener resource and a
1382+
// route configuration resource, as specified by the test case.
1383+
resources := e2e.UpdateOptions{
1384+
NodeID: nodeID,
1385+
Listeners: []*v3listenerpb.Listener{e2e.DefaultClientListener(defaultTestServiceName, defaultTestRouteConfigName)},
1386+
Routes: []*v3routepb.RouteConfiguration{{
1387+
Name: defaultTestRouteConfigName,
1388+
VirtualHosts: []*v3routepb.VirtualHost{{
1389+
Domains: []string{defaultTestServiceName},
1390+
Routes: []*v3routepb.Route{{
1391+
Match: &v3routepb.RouteMatch{PathSpecifier: &v3routepb.RouteMatch_Prefix{Prefix: "/"}},
1392+
Action: &v3routepb.Route_Route{Route: &v3routepb.RouteAction{
1393+
ClusterSpecifier: &v3routepb.RouteAction_WeightedClusters{WeightedClusters: &v3routepb.WeightedCluster{
1394+
Clusters: []*v3routepb.WeightedCluster_ClusterWeight{
1395+
{
1396+
Name: defaultTestClusterName,
1397+
Weight: &wrapperspb.UInt32Value{Value: 100},
1398+
},
1399+
},
1400+
}},
1401+
HostRewriteSpecifier: &v3routepb.RouteAction_AutoHostRewrite{
1402+
AutoHostRewrite: &wrapperspb.BoolValue{Value: tt.autoHostRewrite},
1403+
},
1404+
}},
1405+
}},
1406+
}},
1407+
}},
1408+
SkipValidation: true,
1409+
}
1410+
1411+
if err := mgmtServer.Update(ctx, resources); err != nil {
1412+
t.Fatal(err)
1413+
}
1414+
1415+
trustedXdsServer := "[]"
1416+
if tt.serverfeature == serverFeature.ServerFeatureTrustedXDSServer {
1417+
trustedXdsServer = `["trusted_xds_server"]`
1418+
}
1419+
1420+
opts := bootstrap.ConfigOptionsForTesting{
1421+
Servers: []byte(fmt.Sprintf(`[{
1422+
"server_uri": %q,
1423+
"channel_creds": [{"type": "insecure"}],
1424+
"server_features": %s
1425+
}]`, mgmtServer.Address, trustedXdsServer)),
1426+
Node: []byte(fmt.Sprintf(`{"id": "%s"}`, nodeID)),
1427+
}
1428+
1429+
contents, err := bootstrap.NewContentsForTesting(opts)
1430+
if err != nil {
1431+
t.Fatalf("Failed to create bootstrap configuration: %v", err)
1432+
}
1433+
1434+
// Build the resolver and read the config selector out of it.
1435+
stateCh, _, _ := buildResolverForTarget(t, resolver.Target{URL: *testutils.MustParseURL("xds:///" + defaultTestServiceName)}, contents)
1436+
cs := verifyUpdateFromResolver(ctx, t, stateCh, "")
1437+
1438+
res, err := cs.SelectConfig(iresolver.RPCInfo{
1439+
Context: ctx,
1440+
Method: "/service/method",
1441+
})
1442+
if err != nil {
1443+
t.Fatalf("cs.SelectConfig(): %v", err)
1444+
}
1445+
1446+
gotAutoHostRewrite := clusterimpl.AutoHostRewriteForTesting(res.Context)
1447+
if gotAutoHostRewrite != tt.wantAutoHostRewrite {
1448+
t.Fatalf("Got autoHostRewrite: %v, want: %v", gotAutoHostRewrite, tt.wantAutoHostRewrite)
1449+
}
1450+
})
1451+
}
1452+
}

0 commit comments

Comments
 (0)