mirror of https://github.com/grpc/grpc-go.git
				
				
				
			xds/client: accept resources wrapped in discoverypb.Resource message (#5242)
This commit is contained in:
		
							parent
							
								
									6c3ccbe89a
								
							
						
					
					
						commit
						97c3143418
					
				|  | @ -53,6 +53,7 @@ const ( | |||
| 
 | ||||
| 	gRPCUserAgentName               = "gRPC Go" | ||||
| 	clientFeatureNoOverprovisioning = "envoy.lb.does_not_support_overprovisioning" | ||||
| 	clientFeatureResourceWrapper    = "xds.config.resource-in-sotw" | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
|  | @ -499,7 +500,7 @@ func (c *Config) updateNodeProto(node *v3corepb.Node) error { | |||
| 	} | ||||
| 	v3.UserAgentName = gRPCUserAgentName | ||||
| 	v3.UserAgentVersionType = &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version} | ||||
| 	v3.ClientFeatures = append(v3.ClientFeatures, clientFeatureNoOverprovisioning) | ||||
| 	v3.ClientFeatures = append(v3.ClientFeatures, clientFeatureNoOverprovisioning, clientFeatureResourceWrapper) | ||||
| 
 | ||||
| 	v3bytes, err := proto.Marshal(v3) | ||||
| 	if err != nil { | ||||
|  |  | |||
|  | @ -200,14 +200,14 @@ var ( | |||
| 		BuildVersion:         gRPCVersion, | ||||
| 		UserAgentName:        gRPCUserAgentName, | ||||
| 		UserAgentVersionType: &v2corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, | ||||
| 		ClientFeatures:       []string{clientFeatureNoOverprovisioning}, | ||||
| 		ClientFeatures:       []string{clientFeatureNoOverprovisioning, clientFeatureResourceWrapper}, | ||||
| 	} | ||||
| 	v3NodeProto = &v3corepb.Node{ | ||||
| 		Id:                   "ENVOY_NODE_ID", | ||||
| 		Metadata:             metadata, | ||||
| 		UserAgentName:        gRPCUserAgentName, | ||||
| 		UserAgentVersionType: &v3corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, | ||||
| 		ClientFeatures:       []string{clientFeatureNoOverprovisioning}, | ||||
| 		ClientFeatures:       []string{clientFeatureNoOverprovisioning, clientFeatureResourceWrapper}, | ||||
| 	} | ||||
| 	nilCredsConfigV2 = &Config{ | ||||
| 		XDSServer: &ServerConfig{ | ||||
|  | @ -401,7 +401,7 @@ func TestNewConfigV2ProtoSuccess(t *testing.T) { | |||
| 						BuildVersion:         gRPCVersion, | ||||
| 						UserAgentName:        gRPCUserAgentName, | ||||
| 						UserAgentVersionType: &v2corepb.Node_UserAgentVersion{UserAgentVersion: grpc.Version}, | ||||
| 						ClientFeatures:       []string{clientFeatureNoOverprovisioning}, | ||||
| 						ClientFeatures:       []string{clientFeatureNoOverprovisioning, clientFeatureResourceWrapper}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				ClientDefaultListenerResourceNameTemplate: "%s", | ||||
|  |  | |||
|  | @ -20,6 +20,8 @@ package xdsresource | |||
| import ( | ||||
| 	"time" | ||||
| 
 | ||||
| 	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version" | ||||
| 	"google.golang.org/protobuf/types/known/anypb" | ||||
| ) | ||||
|  | @ -76,6 +78,21 @@ func IsEndpointsResource(url string) bool { | |||
| 	return url == version.V2EndpointsURL || url == version.V3EndpointsURL | ||||
| } | ||||
| 
 | ||||
| // unwrapResource unwraps and returns the inner resource if it's in a resource
 | ||||
| // wrapper. The original resource is returned if it's not wrapped.
 | ||||
| func unwrapResource(r *anypb.Any) (*anypb.Any, error) { | ||||
| 	url := r.GetTypeUrl() | ||||
| 	if url != version.V2ResourceWrapperURL && url != version.V3ResourceWrapperURL { | ||||
| 		// Not wrapped.
 | ||||
| 		return r, nil | ||||
| 	} | ||||
| 	inner := &v3discoverypb.Resource{} | ||||
| 	if err := proto.Unmarshal(r.GetValue(), inner); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return inner.Resource, nil | ||||
| } | ||||
| 
 | ||||
| // ServiceStatus is the status of the update.
 | ||||
| type ServiceStatus int | ||||
| 
 | ||||
|  |  | |||
|  | @ -51,6 +51,11 @@ func UnmarshalCluster(opts *UnmarshalOptions) (map[string]ClusterUpdateErrTuple, | |||
| } | ||||
| 
 | ||||
| func unmarshalClusterResource(r *anypb.Any, f UpdateValidatorFunc, logger *grpclog.PrefixLogger) (string, ClusterUpdate, error) { | ||||
| 	r, err := unwrapResource(r) | ||||
| 	if err != nil { | ||||
| 		return "", ClusterUpdate{}, fmt.Errorf("failed to unwrap resource: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !IsClusterResource(r.GetTypeUrl()) { | ||||
| 		return "", ClusterUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl()) | ||||
| 	} | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import ( | |||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" | ||||
| 	"github.com/google/go-cmp/cmp" | ||||
| 	"github.com/google/go-cmp/cmp/cmpopts" | ||||
| 	"google.golang.org/grpc/internal/envconfig" | ||||
|  | @ -1517,6 +1518,21 @@ func (s) TestUnmarshalCluster(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v2 cluster wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v2xdspb.Resource{Resource: v2ClusterAny})}, | ||||
| 			wantUpdate: map[string]ClusterUpdateErrTuple{ | ||||
| 				v2ClusterName: {Update: ClusterUpdate{ | ||||
| 					ClusterName:    v2ClusterName, | ||||
| 					EDSServiceName: v2Service, LRSServerConfig: ClusterLRSServerSelf, | ||||
| 					Raw: v2ClusterAny, | ||||
| 				}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 cluster", | ||||
| 			resources: []*anypb.Any{v3ClusterAny}, | ||||
|  | @ -1532,6 +1548,21 @@ func (s) TestUnmarshalCluster(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 cluster wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v3discoverypb.Resource{Resource: v3ClusterAny})}, | ||||
| 			wantUpdate: map[string]ClusterUpdateErrTuple{ | ||||
| 				v3ClusterName: {Update: ClusterUpdate{ | ||||
| 					ClusterName:    v3ClusterName, | ||||
| 					EDSServiceName: v3Service, LRSServerConfig: ClusterLRSServerSelf, | ||||
| 					Raw: v3ClusterAny, | ||||
| 				}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 cluster with EDS config source self", | ||||
| 			resources: []*anypb.Any{v3ClusterAnyWithEDSConfigSourceSelf}, | ||||
|  |  | |||
|  | @ -42,6 +42,11 @@ func UnmarshalEndpoints(opts *UnmarshalOptions) (map[string]EndpointsUpdateErrTu | |||
| } | ||||
| 
 | ||||
| func unmarshalEndpointsResource(r *anypb.Any, logger *grpclog.PrefixLogger) (string, EndpointsUpdate, error) { | ||||
| 	r, err := unwrapResource(r) | ||||
| 	if err != nil { | ||||
| 		return "", EndpointsUpdate{}, fmt.Errorf("failed to unwrap resource: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !IsEndpointsResource(r.GetTypeUrl()) { | ||||
| 		return "", EndpointsUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl()) | ||||
| 	} | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ import ( | |||
| 
 | ||||
| 	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" | ||||
| 	v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" | ||||
| 	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" | ||||
| 	v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3" | ||||
| 	anypb "github.com/golang/protobuf/ptypes/any" | ||||
| 	wrapperspb "github.com/golang/protobuf/ptypes/wrappers" | ||||
|  | @ -227,6 +228,42 @@ func (s) TestUnmarshalEndpoints(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 endpoints wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v3discoverypb.Resource{Resource: v3EndpointsAny})}, | ||||
| 			wantUpdate: map[string]EndpointsUpdateErrTuple{ | ||||
| 				"test": {Update: EndpointsUpdate{ | ||||
| 					Drops: nil, | ||||
| 					Localities: []Locality{ | ||||
| 						{ | ||||
| 							Endpoints: []Endpoint{{ | ||||
| 								Address:      "addr1:314", | ||||
| 								HealthStatus: EndpointHealthStatusUnhealthy, | ||||
| 								Weight:       271, | ||||
| 							}}, | ||||
| 							ID:       internal.LocalityID{SubZone: "locality-1"}, | ||||
| 							Priority: 1, | ||||
| 							Weight:   1, | ||||
| 						}, | ||||
| 						{ | ||||
| 							Endpoints: []Endpoint{{ | ||||
| 								Address:      "addr2:159", | ||||
| 								HealthStatus: EndpointHealthStatusDraining, | ||||
| 								Weight:       828, | ||||
| 							}}, | ||||
| 							ID:       internal.LocalityID{SubZone: "locality-2"}, | ||||
| 							Priority: 0, | ||||
| 							Weight:   1, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Raw: v3EndpointsAny, | ||||
| 				}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// To test that unmarshal keeps processing on errors.
 | ||||
| 			name: "good and bad endpoints", | ||||
|  |  | |||
|  | @ -46,6 +46,11 @@ func UnmarshalListener(opts *UnmarshalOptions) (map[string]ListenerUpdateErrTupl | |||
| } | ||||
| 
 | ||||
| func unmarshalListenerResource(r *anypb.Any, f UpdateValidatorFunc, logger *grpclog.PrefixLogger) (string, ListenerUpdate, error) { | ||||
| 	r, err := unwrapResource(r) | ||||
| 	if err != nil { | ||||
| 		return "", ListenerUpdate{}, fmt.Errorf("failed to unwrap resource: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !IsListenerResource(r.GetTypeUrl()) { | ||||
| 		return "", ListenerUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl()) | ||||
| 	} | ||||
|  |  | |||
|  | @ -23,6 +23,7 @@ import ( | |||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/google/go-cmp/cmp" | ||||
| 	"github.com/google/go-cmp/cmp/cmpopts" | ||||
|  | @ -605,6 +606,17 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v2 listener resource wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v2xdspb.Resource{Resource: v2Lis})}, | ||||
| 			wantUpdate: map[string]ListenerUpdateErrTuple{ | ||||
| 				v2LDSTarget: {Update: ListenerUpdate{RouteConfigName: v2RouteConfigName, Raw: v2Lis}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 listener resource", | ||||
| 			resources: []*anypb.Any{v3LisWithFilters()}, | ||||
|  | @ -616,6 +628,17 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 listener resource wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v3discoverypb.Resource{Resource: v3LisWithFilters()})}, | ||||
| 			wantUpdate: map[string]ListenerUpdateErrTuple{ | ||||
| 				v3LDSTarget: {Update: ListenerUpdate{RouteConfigName: v3RouteConfigName, MaxStreamDuration: time.Second, HTTPFilters: routerFilterList, Raw: v3LisWithFilters()}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		// "To allow equating RBAC's direct_remote_ip and
 | ||||
| 		// remote_ip...HttpConnectionManager.xff_num_trusted_hops must be unset
 | ||||
| 		// or zero and HttpConnectionManager.original_ip_detection_extensions
 | ||||
|  |  | |||
|  | @ -46,6 +46,11 @@ func UnmarshalRouteConfig(opts *UnmarshalOptions) (map[string]RouteConfigUpdateE | |||
| } | ||||
| 
 | ||||
| func unmarshalRouteConfigResource(r *anypb.Any, logger *grpclog.PrefixLogger) (string, RouteConfigUpdate, error) { | ||||
| 	r, err := unwrapResource(r) | ||||
| 	if err != nil { | ||||
| 		return "", RouteConfigUpdate{}, fmt.Errorf("failed to unwrap resource: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if !IsRouteConfigResource(r.GetTypeUrl()) { | ||||
| 		return "", RouteConfigUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl()) | ||||
| 	} | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ import ( | |||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
| 	v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/google/go-cmp/cmp" | ||||
| 	"github.com/google/go-cmp/cmp/cmpopts" | ||||
|  | @ -910,6 +911,33 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v2 routeConfig resource wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v2xdspb.Resource{Resource: v2RouteConfig})}, | ||||
| 			wantUpdate: map[string]RouteConfigUpdateErrTuple{ | ||||
| 				v2RouteConfigName: {Update: RouteConfigUpdate{ | ||||
| 					VirtualHosts: []*VirtualHost{ | ||||
| 						{ | ||||
| 							Domains: []string{uninterestingDomain}, | ||||
| 							Routes: []*Route{{Prefix: newStringP(""), | ||||
| 								WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}, | ||||
| 								ActionType:       RouteActionRoute}}, | ||||
| 						}, | ||||
| 						{ | ||||
| 							Domains: []string{ldsTarget}, | ||||
| 							Routes: []*Route{{Prefix: newStringP(""), | ||||
| 								WeightedClusters: map[string]WeightedCluster{v2ClusterName: {Weight: 1}}, | ||||
| 								ActionType:       RouteActionRoute}}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Raw: v2RouteConfig, | ||||
| 				}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 routeConfig resource", | ||||
| 			resources: []*anypb.Any{v3RouteConfig}, | ||||
|  | @ -937,6 +965,33 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) { | |||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "v3 routeConfig resource wrapped", | ||||
| 			resources: []*anypb.Any{testutils.MarshalAny(&v3discoverypb.Resource{Resource: v3RouteConfig})}, | ||||
| 			wantUpdate: map[string]RouteConfigUpdateErrTuple{ | ||||
| 				v3RouteConfigName: {Update: RouteConfigUpdate{ | ||||
| 					VirtualHosts: []*VirtualHost{ | ||||
| 						{ | ||||
| 							Domains: []string{uninterestingDomain}, | ||||
| 							Routes: []*Route{{Prefix: newStringP(""), | ||||
| 								WeightedClusters: map[string]WeightedCluster{uninterestingClusterName: {Weight: 1}}, | ||||
| 								ActionType:       RouteActionRoute}}, | ||||
| 						}, | ||||
| 						{ | ||||
| 							Domains: []string{ldsTarget}, | ||||
| 							Routes: []*Route{{Prefix: newStringP(""), | ||||
| 								WeightedClusters: map[string]WeightedCluster{v3ClusterName: {Weight: 1}}, | ||||
| 								ActionType:       RouteActionRoute}}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					Raw: v3RouteConfig, | ||||
| 				}}, | ||||
| 			}, | ||||
| 			wantMD: UpdateMetadata{ | ||||
| 				Status:  ServiceStatusACKed, | ||||
| 				Version: testVersion, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:      "multiple routeConfig resources", | ||||
| 			resources: []*anypb.Any{v2RouteConfig, v3RouteConfig}, | ||||
|  |  | |||
|  | @ -42,6 +42,7 @@ const ( | |||
| 	V2ClusterType     = "envoy.api.v2.Cluster" | ||||
| 	V2EndpointsType   = "envoy.api.v2.ClusterLoadAssignment" | ||||
| 
 | ||||
| 	V2ResourceWrapperURL = googleapiPrefix + "envoy.api.v2.Resource" | ||||
| 	V2ListenerURL        = googleapiPrefix + V2ListenerType | ||||
| 	V2RouteConfigURL     = googleapiPrefix + V2RouteConfigType | ||||
| 	V2ClusterURL         = googleapiPrefix + V2ClusterType | ||||
|  | @ -53,6 +54,7 @@ const ( | |||
| 	V3ClusterType     = "envoy.config.cluster.v3.Cluster" | ||||
| 	V3EndpointsType   = "envoy.config.endpoint.v3.ClusterLoadAssignment" | ||||
| 
 | ||||
| 	V3ResourceWrapperURL      = googleapiPrefix + "envoy.service.discovery.v3.Resource" | ||||
| 	V3ListenerURL             = googleapiPrefix + V3ListenerType | ||||
| 	V3RouteConfigURL          = googleapiPrefix + V3RouteConfigType | ||||
| 	V3ClusterURL              = googleapiPrefix + V3ClusterType | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue