xds: change the DumpResources API to return proto message containing the resource dump (#7240)

This commit is contained in:
Easwar Swaminathan 2024-05-22 11:04:29 -07:00 committed by GitHub
parent 48b6b11b38
commit a75dfa68c6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 426 additions and 304 deletions

View File

@ -34,10 +34,7 @@ import (
internalgrpclog "google.golang.org/grpc/internal/grpclog"
"google.golang.org/grpc/status"
"google.golang.org/grpc/xds/internal/xdsclient"
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
"google.golang.org/protobuf/types/known/timestamppb"
v3adminpb "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
v3statusgrpc "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
)
@ -77,7 +74,7 @@ func NewClientStatusDiscoveryServer() (*ClientStatusDiscoveryServer, error) {
return s, nil
}
// StreamClientStatus implementations interface ClientStatusDiscoveryServiceServer.
// StreamClientStatus implements interface ClientStatusDiscoveryServiceServer.
func (s *ClientStatusDiscoveryServer) StreamClientStatus(stream v3statusgrpc.ClientStatusDiscoveryService_StreamClientStatusServer) error {
for {
req, err := stream.Recv()
@ -97,13 +94,13 @@ func (s *ClientStatusDiscoveryServer) StreamClientStatus(stream v3statusgrpc.Cli
}
}
// FetchClientStatus implementations interface ClientStatusDiscoveryServiceServer.
// FetchClientStatus implements interface ClientStatusDiscoveryServiceServer.
func (s *ClientStatusDiscoveryServer) FetchClientStatus(_ context.Context, req *v3statuspb.ClientStatusRequest) (*v3statuspb.ClientStatusResponse, error) {
return s.buildClientStatusRespForReq(req)
}
// buildClientStatusRespForReq fetches the status from the client, and returns
// the response to be sent back to xdsclient.
// buildClientStatusRespForReq fetches the status of xDS resources from the
// xdsclient, and returns the response to be sent back to the csds client.
//
// If it returns an error, the error is a status error.
func (s *ClientStatusDiscoveryServer) buildClientStatusRespForReq(req *v3statuspb.ClientStatusRequest) (*v3statuspb.ClientStatusResponse, error) {
@ -119,16 +116,7 @@ func (s *ClientStatusDiscoveryServer) buildClientStatusRespForReq(req *v3statusp
return nil, status.Errorf(codes.InvalidArgument, "node_matchers are not supported, request contains node_matchers: %v", req.NodeMatchers)
}
dump := s.xdsClient.DumpResources()
ret := &v3statuspb.ClientStatusResponse{
Config: []*v3statuspb.ClientConfig{
{
Node: s.xdsClient.BootstrapConfig().NodeProto,
GenericXdsConfigs: dumpToGenericXdsConfig(dump),
},
},
}
return ret, nil
return s.xdsClient.DumpResources()
}
// Close cleans up the resources.
@ -137,45 +125,3 @@ func (s *ClientStatusDiscoveryServer) Close() {
s.xdsClientClose()
}
}
func dumpToGenericXdsConfig(dump map[string]map[string]xdsresource.UpdateWithMD) []*v3statuspb.ClientConfig_GenericXdsConfig {
var ret []*v3statuspb.ClientConfig_GenericXdsConfig
for typeURL, updates := range dump {
for name, update := range updates {
config := &v3statuspb.ClientConfig_GenericXdsConfig{
TypeUrl: typeURL,
Name: name,
VersionInfo: update.MD.Version,
XdsConfig: update.Raw,
LastUpdated: timestamppb.New(update.MD.Timestamp),
ClientStatus: serviceStatusToProto(update.MD.Status),
}
if errState := update.MD.ErrState; errState != nil {
config.ErrorState = &v3adminpb.UpdateFailureState{
LastUpdateAttempt: timestamppb.New(errState.Timestamp),
Details: errState.Err.Error(),
VersionInfo: errState.Version,
}
}
ret = append(ret, config)
}
}
return ret
}
func serviceStatusToProto(serviceStatus xdsresource.ServiceStatus) v3adminpb.ClientResourceStatus {
switch serviceStatus {
case xdsresource.ServiceStatusUnknown:
return v3adminpb.ClientResourceStatus_UNKNOWN
case xdsresource.ServiceStatusRequested:
return v3adminpb.ClientResourceStatus_REQUESTED
case xdsresource.ServiceStatusNotExist:
return v3adminpb.ClientResourceStatus_DOES_NOT_EXIST
case xdsresource.ServiceStatusACKed:
return v3adminpb.ClientResourceStatus_ACKED
case xdsresource.ServiceStatusNACKed:
return v3adminpb.ClientResourceStatus_NACKED
default:
return v3adminpb.ClientResourceStatus_UNKNOWN
}
}

View File

@ -32,6 +32,10 @@ import (
"google.golang.org/grpc/xds/internal/xdsclient/transport"
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/timestamppb"
v3adminpb "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
)
type watchState int
@ -586,26 +590,54 @@ func (a *authority) reportLoad() (*load.Store, func()) {
return a.transport.ReportLoad()
}
func (a *authority) dumpResources() map[string]map[string]xdsresource.UpdateWithMD {
func (a *authority) dumpResources() ([]*v3statuspb.ClientConfig_GenericXdsConfig, error) {
a.resourcesMu.Lock()
defer a.resourcesMu.Unlock()
dump := make(map[string]map[string]xdsresource.UpdateWithMD)
var ret []*v3statuspb.ClientConfig_GenericXdsConfig
for rType, resourceStates := range a.resources {
states := make(map[string]xdsresource.UpdateWithMD)
typeURL := rType.TypeURL()
for name, state := range resourceStates {
var raw *anypb.Any
if state.cache != nil {
raw = state.cache.Raw()
}
states[name] = xdsresource.UpdateWithMD{
MD: state.md,
Raw: raw,
config := &v3statuspb.ClientConfig_GenericXdsConfig{
TypeUrl: typeURL,
Name: name,
VersionInfo: state.md.Version,
XdsConfig: raw,
LastUpdated: timestamppb.New(state.md.Timestamp),
ClientStatus: serviceStatusToProto(state.md.Status),
}
if errState := state.md.ErrState; errState != nil {
config.ErrorState = &v3adminpb.UpdateFailureState{
LastUpdateAttempt: timestamppb.New(errState.Timestamp),
Details: errState.Err.Error(),
VersionInfo: errState.Version,
}
}
ret = append(ret, config)
}
dump[rType.TypeURL()] = states
}
return dump
return ret, nil
}
func serviceStatusToProto(serviceStatus xdsresource.ServiceStatus) v3adminpb.ClientResourceStatus {
switch serviceStatus {
case xdsresource.ServiceStatusUnknown:
return v3adminpb.ClientResourceStatus_UNKNOWN
case xdsresource.ServiceStatusRequested:
return v3adminpb.ClientResourceStatus_REQUESTED
case xdsresource.ServiceStatusNotExist:
return v3adminpb.ClientResourceStatus_DOES_NOT_EXIST
case xdsresource.ServiceStatusACKed:
return v3adminpb.ClientResourceStatus_ACKED
case xdsresource.ServiceStatusNACKed:
return v3adminpb.ClientResourceStatus_NACKED
default:
return v3adminpb.ClientResourceStatus_UNKNOWN
}
}
func combineErrors(rType string, topLevelErrors []error, perResourceErrors map[string]error) error {

View File

@ -24,6 +24,8 @@ import (
"google.golang.org/grpc/internal/xds/bootstrap"
"google.golang.org/grpc/xds/internal/xdsclient/load"
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
)
// XDSClient is a full fledged gRPC client which queries a set of discovery APIs
@ -48,7 +50,7 @@ type XDSClient interface {
// DumpResources returns the status of the xDS resources. Returns a map of
// resource type URLs to a map of resource names to resource state.
DumpResources() map[string]map[string]xdsresource.UpdateWithMD
DumpResources() (*v3statuspb.ClientStatusResponse, error)
ReportLoad(*bootstrap.ServerConfig) (*load.Store, func())

View File

@ -19,35 +19,30 @@
package xdsclient
import (
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
)
func appendMaps(dst, src map[string]map[string]xdsresource.UpdateWithMD) {
// Iterate through the resource types.
for rType, srcResources := range src {
// Lookup/create the resource type specific map in the destination.
dstResources := dst[rType]
if dstResources == nil {
dstResources = make(map[string]xdsresource.UpdateWithMD)
dst[rType] = dstResources
}
// Iterate through the resources within the resource type in the source,
// and copy them over to the destination.
for name, update := range srcResources {
dstResources[name] = update
}
}
}
// DumpResources returns the status and contents of all xDS resources.
func (c *clientImpl) DumpResources() map[string]map[string]xdsresource.UpdateWithMD {
func (c *clientImpl) DumpResources() (*v3statuspb.ClientStatusResponse, error) {
c.authorityMu.Lock()
defer c.authorityMu.Unlock()
dumps := make(map[string]map[string]xdsresource.UpdateWithMD)
var retCfg []*v3statuspb.ClientConfig_GenericXdsConfig
for _, a := range c.authorities {
dump := a.dumpResources()
appendMaps(dumps, dump)
cfg, err := a.dumpResources()
if err != nil {
return nil, err
}
retCfg = append(retCfg, cfg...)
}
return dumps
return &v3statuspb.ClientStatusResponse{
Config: []*v3statuspb.ClientConfig{
{
// TODO: Populate ClientScope. Need to update go-control-plane dependency.
Node: c.config.NodeProto,
GenericXdsConfigs: retCfg,
},
},
}, nil
}

View File

@ -20,46 +20,22 @@ package xdsclient_test
import (
"context"
"fmt"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"google.golang.org/grpc/internal/testutils"
"google.golang.org/grpc/internal/testutils/xds/e2e"
"google.golang.org/grpc/xds/internal/xdsclient"
"google.golang.org/grpc/xds/internal/xdsclient/xdsresource"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/anypb"
v3adminpb "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
v3listenerpb "github.com/envoyproxy/go-control-plane/envoy/config/listener/v3"
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
)
func compareDump(ctx context.Context, client xdsclient.XDSClient, want map[string]map[string]xdsresource.UpdateWithMD) error {
var lastErr error
for {
if err := ctx.Err(); err != nil {
return fmt.Errorf("Timeout when waiting for expected dump: %v", lastErr)
}
cmpOpts := cmp.Options{
cmpopts.EquateEmpty(),
cmp.Comparer(func(a, b time.Time) bool { return true }),
cmpopts.EquateErrors(),
protocmp.Transform(),
}
diff := cmp.Diff(want, client.DumpResources(), cmpOpts)
if diff == "" {
return nil
}
lastErr = fmt.Errorf("DumpResources() returned unexpected dump, diff (-want +got):\n%s", diff)
time.Sleep(100 * time.Millisecond)
}
}
func (s) TestDumpResources(t *testing.T) {
// Initialize the xDS resources to be used in this test.
ldsTargets := []string{"lds.target.good:0000", "lds.target.good:1111"}
@ -107,7 +83,7 @@ func (s) TestDumpResources(t *testing.T) {
// Dump resources and expect empty configs.
ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout)
defer cancel()
if err := compareDump(ctx, client, nil); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, nil); err != nil {
t.Fatal(err)
}
@ -124,25 +100,49 @@ func (s) TestDumpResources(t *testing.T) {
for _, target := range edsTargets {
xdsresource.WatchEndpoints(client, target, noopEndpointsWatcher{})
}
want := map[string]map[string]xdsresource.UpdateWithMD{
"type.googleapis.com/envoy.config.listener.v3.Listener": {
ldsTargets[0]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
ldsTargets[1]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
want := []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: ldsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
"type.googleapis.com/envoy.config.route.v3.RouteConfiguration": {
rdsTargets[0]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
rdsTargets[1]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: ldsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
"type.googleapis.com/envoy.config.cluster.v3.Cluster": {
cdsTargets[0]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
cdsTargets[1]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: rdsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
"type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment": {
edsTargets[0]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
edsTargets[1]: {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusRequested}},
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: rdsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: cdsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: cdsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: edsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: edsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED,
},
}
if err := compareDump(ctx, client, want); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, want); err != nil {
t.Fatal(err)
}
@ -158,25 +158,65 @@ func (s) TestDumpResources(t *testing.T) {
}
// Dump resources and expect ACK configs.
want = map[string]map[string]xdsresource.UpdateWithMD{
"type.googleapis.com/envoy.config.listener.v3.Listener": {
ldsTargets[0]: {Raw: listenerAnys[0], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
ldsTargets[1]: {Raw: listenerAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
want = []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: ldsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: listenerAnys[0],
},
"type.googleapis.com/envoy.config.route.v3.RouteConfiguration": {
rdsTargets[0]: {Raw: routeAnys[0], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
rdsTargets[1]: {Raw: routeAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: ldsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: listenerAnys[1],
},
"type.googleapis.com/envoy.config.cluster.v3.Cluster": {
cdsTargets[0]: {Raw: clusterAnys[0], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
cdsTargets[1]: {Raw: clusterAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: rdsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: routeAnys[0],
},
"type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment": {
edsTargets[0]: {Raw: endpointAnys[0], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
edsTargets[1]: {Raw: endpointAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"}},
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: rdsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: routeAnys[1],
},
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: cdsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: clusterAnys[0],
},
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: cdsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: clusterAnys[1],
},
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: edsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: endpointAnys[0],
},
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: edsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: endpointAnys[1],
},
}
if err := compareDump(ctx, client, want); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, want); err != nil {
t.Fatal(err)
}
@ -198,58 +238,77 @@ func (s) TestDumpResources(t *testing.T) {
t.Fatal(err)
}
// Verify that the xDS client reports the first resource of each type as
// being in "NACKed" state, and the second resource of each type to be in
// "ACKed" state. The version for the ACKed resource would be "2", while
// that for the NACKed resource would be "1". In the NACKed resource, the
// version which is NACKed is stored in the ErrorState field.
want = map[string]map[string]xdsresource.UpdateWithMD{
"type.googleapis.com/envoy.config.listener.v3.Listener": {
ldsTargets[0]: {
Raw: listenerAnys[0],
MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
Version: "1",
ErrState: &xdsresource.UpdateErrorMetadata{Version: "2", Err: cmpopts.AnyError},
},
want = []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: ldsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
VersionInfo: "1",
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "2",
},
ldsTargets[1]: {Raw: listenerAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "2"}},
XdsConfig: listenerAnys[0],
},
"type.googleapis.com/envoy.config.route.v3.RouteConfiguration": {
rdsTargets[0]: {
Raw: routeAnys[0],
MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
Version: "1",
ErrState: &xdsresource.UpdateErrorMetadata{Version: "2", Err: cmpopts.AnyError},
},
},
rdsTargets[1]: {Raw: routeAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "2"}},
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: ldsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "2",
XdsConfig: listenerAnys[1],
},
"type.googleapis.com/envoy.config.cluster.v3.Cluster": {
cdsTargets[0]: {
Raw: clusterAnys[0],
MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
Version: "1",
ErrState: &xdsresource.UpdateErrorMetadata{Version: "2", Err: cmpopts.AnyError},
},
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: rdsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
VersionInfo: "1",
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "2",
},
cdsTargets[1]: {Raw: clusterAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "2"}},
XdsConfig: routeAnys[0],
},
"type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment": {
edsTargets[0]: {
Raw: endpointAnys[0],
MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
Version: "1",
ErrState: &xdsresource.UpdateErrorMetadata{Version: "2", Err: cmpopts.AnyError},
},
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: rdsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "2",
XdsConfig: routeAnys[1],
},
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: cdsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
VersionInfo: "1",
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "2",
},
edsTargets[1]: {Raw: endpointAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "2"}},
XdsConfig: clusterAnys[0],
},
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: cdsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "2",
XdsConfig: clusterAnys[1],
},
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: edsTargets[0],
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
VersionInfo: "1",
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "2",
},
XdsConfig: endpointAnys[0],
},
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: edsTargets[1],
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "2",
XdsConfig: endpointAnys[1],
},
}
if err := compareDump(ctx, client, want); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, want); err != nil {
t.Fatal(err)
}
}

View File

@ -21,6 +21,7 @@ package xdsclient_test
import (
"context"
"fmt"
"sort"
"strings"
"testing"
"time"
@ -41,6 +42,7 @@ import (
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/wrapperspb"
v3adminpb "github.com/envoyproxy/go-control-plane/envoy/admin/v3"
v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
@ -48,6 +50,7 @@ import (
v3routepb "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
v3httppb "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/network/http_connection_manager/v3"
v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
v3statuspb "github.com/envoyproxy/go-control-plane/envoy/service/status/v3"
_ "google.golang.org/grpc/xds/internal/httpfilter/router" // Register the router filter.
)
@ -63,21 +66,42 @@ func startFakeManagementServer(t *testing.T) (*fakeserver.Server, func()) {
return fs, sCleanup
}
func compareUpdateMetadata(ctx context.Context, dumpFunc func() map[string]xdsresource.UpdateWithMD, want map[string]xdsresource.UpdateWithMD) error {
func compareUpdateMetadata(ctx context.Context, dumpFunc func() (*v3statuspb.ClientStatusResponse, error), want []*v3statuspb.ClientConfig_GenericXdsConfig) error {
var cmpOpts = cmp.Options{
cmp.Transformer("sort", func(in []*v3statuspb.ClientConfig_GenericXdsConfig) []*v3statuspb.ClientConfig_GenericXdsConfig {
out := append([]*v3statuspb.ClientConfig_GenericXdsConfig(nil), in...)
sort.Slice(out, func(i, j int) bool {
a, b := out[i], out[j]
if a == nil {
return true
}
if b == nil {
return false
}
if strings.Compare(a.TypeUrl, b.TypeUrl) == 0 {
return strings.Compare(a.Name, b.Name) < 0
}
return strings.Compare(a.TypeUrl, b.TypeUrl) < 0
})
return out
}),
protocmp.Transform(),
protocmp.IgnoreFields((*v3statuspb.ClientConfig_GenericXdsConfig)(nil), "last_updated"),
protocmp.IgnoreFields((*v3adminpb.UpdateFailureState)(nil), "last_update_attempt", "details"),
}
var lastErr error
for ; ctx.Err() == nil; <-time.After(100 * time.Millisecond) {
cmpOpts := cmp.Options{
cmpopts.EquateEmpty(),
cmp.Comparer(func(a, b time.Time) bool { return true }),
cmpopts.EquateErrors(),
protocmp.Transform(),
resp, err := dumpFunc()
if err != nil {
return err
}
gotUpdateMetadata := dumpFunc()
diff := cmp.Diff(want, gotUpdateMetadata, cmpOpts)
got := resp.GetConfig()[0].GetGenericXdsConfigs()
diff := cmp.Diff(want, got, cmpOpts)
if diff == "" {
return nil
}
lastErr = fmt.Errorf("unexpected diff in metadata, diff (-want +got):\n%s\n want: %+v\n got: %+v", diff, want, gotUpdateMetadata)
lastErr = fmt.Errorf("unexpected diff in metadata, diff (-want +got):\n%s\n want: %+v\n got: %+v", diff, want, got)
}
return fmt.Errorf("timeout when waiting for expected update metadata: %v", lastErr)
}
@ -124,7 +148,7 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
managementServerResponse *v3discoverypb.DiscoveryResponse
wantUpdate xdsresource.ListenerUpdate
wantErr string
wantUpdateMetadata map[string]xdsresource.UpdateWithMD
wantGenericXDSConfig []*v3statuspb.ClientConfig_GenericXdsConfig
}{
{
desc: "badly-marshaled-response",
@ -138,8 +162,12 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
}},
},
wantErr: "Listener not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -150,8 +178,12 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
VersionInfo: "1",
},
wantErr: "Listener not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -163,8 +195,12 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
Resources: []*anypb.Any{testutils.MarshalAny(t, &v3routepb.RouteConfiguration{})},
},
wantErr: "Listener not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -181,14 +217,15 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
},
},
wantErr: "no RouteSpecifier",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
ErrState: &xdsresource.UpdateErrorMetadata{
Version: "1",
Err: cmpopts.AnyError,
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "1",
},
}},
},
},
},
{
@ -203,10 +240,13 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
RouteConfigName: "route-configuration-name",
HTTPFilters: []xdsresource.HTTPFilter{{Name: "router"}},
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -222,10 +262,13 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
RouteConfigName: "route-configuration-name",
HTTPFilters: []xdsresource.HTTPFilter{{Name: "router"}},
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -300,10 +343,7 @@ func (s) TestHandleListenerResponseFromManagementServer(t *testing.T) {
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
}
if err := compareUpdateMetadata(ctx, func() map[string]xdsresource.UpdateWithMD {
dump := client.DumpResources()
return dump["type.googleapis.com/envoy.config.listener.v3.Listener"]
}, test.wantUpdateMetadata); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, test.wantGenericXDSConfig); err != nil {
t.Fatal(err)
}
})
@ -351,7 +391,7 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
managementServerResponse *v3discoverypb.DiscoveryResponse
wantUpdate xdsresource.RouteConfigUpdate
wantErr string
wantUpdateMetadata map[string]xdsresource.UpdateWithMD
wantGenericXDSConfig []*v3statuspb.ClientConfig_GenericXdsConfig
}{
// The first three tests involve scenarios where the response fails
// protobuf deserialization (because it contains an invalid data or type
@ -373,8 +413,12 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
}},
},
wantErr: "RouteConfiguration not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -385,8 +429,12 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
VersionInfo: "1",
},
wantErr: "RouteConfiguration not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -398,8 +446,12 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
Resources: []*anypb.Any{testutils.MarshalAny(t, &v3clusterpb.Cluster{})},
},
wantErr: "RouteConfiguration not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -424,14 +476,15 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
})},
},
wantErr: "received route is invalid: retry_policy.num_retries = 0; must be >= 1",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
ErrState: &xdsresource.UpdateErrorMetadata{
Version: "1",
Err: cmpopts.AnyError,
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "1",
},
}},
},
},
},
{
@ -452,10 +505,13 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
},
},
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -477,10 +533,13 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
},
},
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -553,10 +612,7 @@ func (s) TestHandleRouteConfigResponseFromManagementServer(t *testing.T) {
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
}
if err := compareUpdateMetadata(ctx, func() map[string]xdsresource.UpdateWithMD {
dump := client.DumpResources()
return dump["type.googleapis.com/envoy.config.route.v3.RouteConfiguration"]
}, test.wantUpdateMetadata); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, test.wantGenericXDSConfig); err != nil {
t.Fatal(err)
}
})
@ -586,7 +642,7 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
managementServerResponse *v3discoverypb.DiscoveryResponse
wantUpdate xdsresource.ClusterUpdate
wantErr string
wantUpdateMetadata map[string]xdsresource.UpdateWithMD
wantGenericXDSConfig []*v3statuspb.ClientConfig_GenericXdsConfig
}{
{
desc: "badly-marshaled-response",
@ -600,8 +656,12 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
}},
},
wantErr: "Cluster not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -612,8 +672,12 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
VersionInfo: "1",
},
wantErr: "Cluster not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -625,8 +689,12 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
Resources: []*anypb.Any{testutils.MarshalAny(t, &v3endpointpb.ClusterLoadAssignment{})},
},
wantErr: "Cluster not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -650,14 +718,15 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
})},
},
wantErr: "unexpected lbPolicy MAGLEV",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
ErrState: &xdsresource.UpdateErrorMetadata{
Version: "1",
Err: cmpopts.AnyError,
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "1",
},
}},
},
},
},
{
@ -672,10 +741,13 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
ClusterName: "resource-name-1",
EDSServiceName: "eds-service-name",
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -691,10 +763,13 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
ClusterName: "resource-name-1",
EDSServiceName: "eds-service-name",
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.cluster.v3.Cluster",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -778,10 +853,7 @@ func (s) TestHandleClusterResponseFromManagementServer(t *testing.T) {
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
}
if err := compareUpdateMetadata(ctx, func() map[string]xdsresource.UpdateWithMD {
dump := client.DumpResources()
return dump["type.googleapis.com/envoy.config.cluster.v3.Cluster"]
}, test.wantUpdateMetadata); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, test.wantGenericXDSConfig); err != nil {
t.Fatal(err)
}
})
@ -859,7 +931,7 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
managementServerResponse *v3discoverypb.DiscoveryResponse
wantUpdate xdsresource.EndpointsUpdate
wantErr string
wantUpdateMetadata map[string]xdsresource.UpdateWithMD
wantGenericXDSConfig []*v3statuspb.ClientConfig_GenericXdsConfig
}{
// The first three tests involve scenarios where the response fails
// protobuf deserialization (because it contains an invalid data or type
@ -881,8 +953,12 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
}},
},
wantErr: "Endpoints not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -893,8 +969,12 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
VersionInfo: "1",
},
wantErr: "Endpoints not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -906,8 +986,12 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
Resources: []*anypb.Any{testutils.MarshalAny(t, &v3listenerpb.Listener{})},
},
wantErr: "Endpoints not found in received response",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusNotExist}},
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_DOES_NOT_EXIST,
},
},
},
{
@ -949,14 +1033,15 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
},
},
wantErr: "EDS response contains an endpoint with zero weight",
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {MD: xdsresource.UpdateMetadata{
Status: xdsresource.ServiceStatusNACKed,
ErrState: &xdsresource.UpdateErrorMetadata{
Version: "1",
Err: cmpopts.AnyError,
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_NACKED,
ErrorState: &v3adminpb.UpdateFailureState{
VersionInfo: "1",
},
}},
},
},
},
{
@ -983,10 +1068,13 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
},
},
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -1014,10 +1102,13 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
},
},
},
wantUpdateMetadata: map[string]xdsresource.UpdateWithMD{
"resource-name-1": {
MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "1"},
Raw: testutils.MarshalAny(t, resource1),
wantGenericXDSConfig: []*v3statuspb.ClientConfig_GenericXdsConfig{
{
TypeUrl: "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
Name: resourceName1,
ClientStatus: v3adminpb.ClientResourceStatus_ACKED,
VersionInfo: "1",
XdsConfig: testutils.MarshalAny(t, resource1),
},
},
},
@ -1091,10 +1182,7 @@ func (s) TestHandleEndpointsResponseFromManagementServer(t *testing.T) {
if diff := cmp.Diff(test.wantUpdate, gotUpdate, cmpOpts...); diff != "" {
t.Fatalf("Unexpected diff in metadata, diff (-want +got):\n%s", diff)
}
if err := compareUpdateMetadata(ctx, func() map[string]xdsresource.UpdateWithMD {
dump := client.DumpResources()
return dump["type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment"]
}, test.wantUpdateMetadata); err != nil {
if err := compareUpdateMetadata(ctx, client.DumpResources, test.wantGenericXDSConfig); err != nil {
t.Fatal(err)
}
})