xdsclient: add Cluster Specifier Name to Route (#4972)

* xdsclient: add Cluster Specifier Name to Route
This commit is contained in:
Zach Reyes 2021-11-12 15:50:27 -05:00 committed by GitHub
parent 82d8af8bf0
commit 6e79bc8afe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 54 deletions

View File

@ -111,14 +111,14 @@ func (s) TestRDSHandleResponseWithRouting(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*xdsresource.Route{{Prefix: newStringP(""),
WeightedClusters: map[string]xdsresource.WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: xdsresource.RouteActionRoute}},
ActionType: xdsresource.RouteActionRoute}},
},
{
Domains: []string{goodLDSTarget1},
Routes: []*xdsresource.Route{{
Prefix: newStringP(""),
WeightedClusters: map[string]xdsresource.WeightedCluster{goodClusterName2: {Weight: 1}},
RouteAction: xdsresource.RouteActionRoute}},
ActionType: xdsresource.RouteActionRoute}},
},
},
Raw: marshaledGoodRouteConfig2,
@ -142,13 +142,13 @@ func (s) TestRDSHandleResponseWithRouting(t *testing.T) {
Routes: []*xdsresource.Route{{
Prefix: newStringP(""),
WeightedClusters: map[string]xdsresource.WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: xdsresource.RouteActionRoute}},
ActionType: xdsresource.RouteActionRoute}},
},
{
Domains: []string{goodLDSTarget1},
Routes: []*xdsresource.Route{{Prefix: newStringP(""),
WeightedClusters: map[string]xdsresource.WeightedCluster{goodClusterName1: {Weight: 1}},
RouteAction: xdsresource.RouteActionRoute}},
ActionType: xdsresource.RouteActionRoute}},
},
},
Raw: marshaledGoodRouteConfig1,

View File

@ -86,8 +86,8 @@ type VirtualHostWithInterceptors struct {
type RouteWithInterceptors struct {
// M is the matcher used to match to this route.
M *CompositeMatcher
// RouteAction is the type of routing action to initiate once matched to.
RouteAction RouteAction
// ActionType is the type of routing action to initiate once matched to.
ActionType RouteActionType
// Interceptors are interceptors instantiated for this route. These will be
// constructed from a combination of the top level configuration and any
// HTTP Filter overrides present in Virtual Host or Route.
@ -112,7 +112,7 @@ func (f *FilterChain) convertVirtualHost(virtualHost *VirtualHost) (VirtualHostW
rs := make([]RouteWithInterceptors, len(virtualHost.Routes))
for i, r := range virtualHost.Routes {
var err error
rs[i].RouteAction = r.RouteAction
rs[i].ActionType = r.ActionType
rs[i].M, err = RouteToMatcher(r)
if err != nil {
return VirtualHostWithInterceptors{}, fmt.Errorf("matcher construction: %v", err)

View File

@ -66,7 +66,7 @@ var (
inlineRouteConfig = &RouteConfigUpdate{
VirtualHosts: []*VirtualHost{{
Domains: []string{"lds.target.good:3333"},
Routes: []*Route{{Prefix: newStringP("/"), RouteAction: RouteActionNonForwardingAction}},
Routes: []*Route{{Prefix: newStringP("/"), ActionType: RouteActionNonForwardingAction}},
}}}
emptyValidNetworkFilters = []*v3listenerpb.Filter{
{

View File

@ -95,14 +95,14 @@ type HashPolicy struct {
RegexSubstitution string
}
// RouteAction is the action of the route from a received RDS response.
type RouteAction int
// RouteActionType is the action of the route from a received RDS response.
type RouteActionType int
const (
// RouteActionUnsupported are routing types currently unsupported by grpc.
// According to A36, "A Route with an inappropriate action causes RPCs
// matching that route to fail."
RouteActionUnsupported RouteAction = iota
RouteActionUnsupported RouteActionType = iota
// RouteActionRoute is the expected route type on the client side. Route
// represents routing a request to some upstream cluster. On the client
// side, if an RPC matches to a route that is not RouteActionRoute, the RPC
@ -129,7 +129,6 @@ type Route struct {
HashPolicies []*HashPolicy
// If the matchers above indicate a match, the below configuration is used.
WeightedClusters map[string]WeightedCluster
// If MaxStreamDuration is nil, it indicates neither of the route action's
// max_stream_duration fields (grpc_timeout_header_max nor
// max_stream_duration) were set. In this case, the ListenerUpdate's
@ -143,10 +142,17 @@ type Route struct {
HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
RetryConfig *RetryConfig
RouteAction RouteAction
ActionType RouteActionType
// Only one of the following fields (WeightedClusters or
// ClusterSpecifierPlugin) will be set for a route.
WeightedClusters map[string]WeightedCluster
// ClusterSpecifierPlugin is the name of the Cluster Specifier Plugin that
// this Route is linked to, if specified by xDS.
ClusterSpecifierPlugin string
}
// WeightedCluster contains settings for an xds RouteAction.WeightedCluster.
// WeightedCluster contains settings for an xds ActionType.WeightedCluster.
type WeightedCluster struct {
// Weight is the relative weight of the cluster. It will never be zero.
Weight uint32

View File

@ -633,7 +633,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) {
InlineRouteConfig: &RouteConfigUpdate{
VirtualHosts: []*VirtualHost{{
Domains: []string{v3LDSTarget},
Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}, RouteAction: RouteActionRoute}},
Routes: []*Route{{Prefix: newStringP("/"), WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}}, ActionType: RouteActionRoute}},
}}},
MaxStreamDuration: time.Second,
Raw: v3LisWithInlineRoute,
@ -730,7 +730,7 @@ func (s) TestUnmarshalListener_ServerSide(t *testing.T) {
inlineRouteConfig = &RouteConfigUpdate{
VirtualHosts: []*VirtualHost{{
Domains: []string{"lds.target.good:3333"},
Routes: []*Route{{Prefix: newStringP("/"), RouteAction: RouteActionNonForwardingAction}},
Routes: []*Route{{Prefix: newStringP("/"), ActionType: RouteActionNonForwardingAction}},
}}}
emptyValidNetworkFilters = []*v3listenerpb.Filter{
{

View File

@ -119,7 +119,7 @@ func generateRDSUpdateFromRouteConfiguration(rc *v3routepb.RouteConfiguration, l
}
// "For any entry in the RouteConfiguration.cluster_specifier_plugins not
// referenced by an enclosed RouteAction's cluster_specifier_plugin, the xDS
// referenced by an enclosed ActionType's cluster_specifier_plugin, the xDS
// client should not provide it to its consumers." - RLS in xDS Design
for name := range csps {
if !cspNames[name] {
@ -356,6 +356,7 @@ func routesProtoToSlice(routes []*v3routepb.Route, csps map[string]clusterspecif
return nil, nil, fmt.Errorf("route %+v, action %+v, specifies a cluster specifier plugin %+v that is not in Route Configuration", r, a, a.ClusterSpecifierPlugin)
}
cspNames[a.ClusterSpecifierPlugin] = true
route.ClusterSpecifierPlugin = a.ClusterSpecifierPlugin
default:
return nil, nil, fmt.Errorf("route %+v, has an unknown ClusterSpecifier: %+v", r, a)
}
@ -377,13 +378,13 @@ func routesProtoToSlice(routes []*v3routepb.Route, csps map[string]clusterspecif
return nil, nil, fmt.Errorf("route %+v, action %+v: %v", r, action, err)
}
route.RouteAction = RouteActionRoute
route.ActionType = RouteActionRoute
case *v3routepb.Route_NonForwardingAction:
// Expected to be used on server side.
route.RouteAction = RouteActionNonForwardingAction
route.ActionType = RouteActionNonForwardingAction
default:
route.RouteAction = RouteActionUnsupported
route.ActionType = RouteActionUnsupported
}
if !v2 {

View File

@ -104,7 +104,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Routes: []*Route{{
Prefix: newStringP("/"),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
HTTPFilterConfigOverride: cfgs,
}},
@ -114,8 +114,9 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
VirtualHosts: []*VirtualHost{{
Domains: []string{ldsTarget},
Routes: []*Route{{
Prefix: newStringP("1"),
RouteAction: RouteActionRoute,
Prefix: newStringP("1"),
ActionType: RouteActionRoute,
ClusterSpecifierPlugin: "cspA",
}},
}},
ClusterSpecifierPlugins: map[string]clusterspecifier.BalancerConfig{
@ -155,7 +156,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Routes: []*Route{{
Prefix: newStringP("/"),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
RetryConfig: rrc,
}},
RetryConfig: vhrc,
@ -263,7 +264,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Routes: []*Route{{Prefix: newStringP("/"),
CaseInsensitive: true,
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
},
@ -307,13 +308,13 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
},
@ -345,7 +346,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP("/"),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
},
@ -422,7 +423,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
"b": {Weight: 3},
"c": {Weight: 5},
},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
},
},
@ -457,7 +458,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Prefix: newStringP("/"),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
MaxStreamDuration: newDurationP(time.Second),
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
},
},
@ -492,7 +493,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Prefix: newStringP("/"),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
MaxStreamDuration: newDurationP(time.Second),
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
},
},
@ -527,7 +528,7 @@ func (s) TestRDSGenerateRDSUpdateFromRouteConfiguration(t *testing.T) {
Prefix: newStringP("/"),
WeightedClusters: map[string]WeightedCluster{clusterName: {Weight: 1}},
MaxStreamDuration: newDurationP(0),
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
},
},
@ -860,13 +861,13 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
Raw: v2RouteConfig,
@ -887,13 +888,13 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
Raw: v3RouteConfig,
@ -914,13 +915,13 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
Raw: v3RouteConfig,
@ -931,13 +932,13 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
Raw: v2RouteConfig,
@ -969,13 +970,13 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
Raw: v3RouteConfig,
@ -986,13 +987,13 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) {
Domains: []string{uninterestingDomain},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
{
Domains: []string{ldsTarget},
Routes: []*Route{{Prefix: newStringP(""),
WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}},
RouteAction: RouteActionRoute}},
ActionType: RouteActionRoute}},
},
},
Raw: v2RouteConfig,
@ -1059,7 +1060,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
CaseInsensitive: true,
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60, HTTPFilterConfigOverride: cfgs}},
HTTPFilterConfigOverride: cfgs,
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}}
}
)
@ -1099,7 +1100,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
Prefix: newStringP("/"),
CaseInsensitive: true,
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
},
{
@ -1147,7 +1148,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
},
Fraction: newUInt32P(10000),
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},
@ -1193,7 +1194,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
},
Fraction: newUInt32P(10000),
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},
@ -1228,7 +1229,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
wantRoutes: []*Route{{
Prefix: newStringP("/a/"),
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},
@ -1410,7 +1411,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
wantRoutes: []*Route{{
Prefix: newStringP("/a/"),
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 40}, "B": {Weight: 60}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},
@ -1436,7 +1437,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
wantRoutes: []*Route{{
Prefix: newStringP("/a/"),
WeightedClusters: map[string]WeightedCluster{"A": {Weight: 20}, "B": {Weight: 30}},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},
@ -1492,7 +1493,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
HashPolicies: []*HashPolicy{
{HashPolicyType: HashPolicyTypeChannelID},
},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},
@ -1551,7 +1552,7 @@ func (s) TestRoutesProtoToSlice(t *testing.T) {
{HashPolicyType: HashPolicyTypeHeader,
HeaderName: ":path"},
},
RouteAction: RouteActionRoute,
ActionType: RouteActionRoute,
}},
wantErr: false,
},

View File

@ -359,7 +359,7 @@ func routeAndProcess(ctx context.Context) error {
if r.M.Match(rpcInfo) {
// "NonForwardingAction is expected for all Routes used on server-side; a route with an inappropriate action causes
// RPCs matching that route to fail with UNAVAILABLE." - A36
if r.RouteAction != xdsresource.RouteActionNonForwardingAction {
if r.ActionType != xdsresource.RouteActionNonForwardingAction {
return status.Error(codes.Unavailable, "the incoming RPC matched to a route that was not of action type non forwarding")
}
rwi = &r