diff --git a/xds/csds/csds.go b/xds/csds/csds.go index 8d03124811a4..6266f60e86d9 100644 --- a/xds/csds/csds.go +++ b/xds/csds/csds.go @@ -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 - } -} diff --git a/xds/internal/xdsclient/authority.go b/xds/internal/xdsclient/authority.go index 62d7a1756e41..c855234bb511 100644 --- a/xds/internal/xdsclient/authority.go +++ b/xds/internal/xdsclient/authority.go @@ -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 { diff --git a/xds/internal/xdsclient/client.go b/xds/internal/xdsclient/client.go index 8f211238f521..468c5fb31b9b 100644 --- a/xds/internal/xdsclient/client.go +++ b/xds/internal/xdsclient/client.go @@ -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()) diff --git a/xds/internal/xdsclient/clientimpl_dump.go b/xds/internal/xdsclient/clientimpl_dump.go index b9d0499301a2..8fbc010f743d 100644 --- a/xds/internal/xdsclient/clientimpl_dump.go +++ b/xds/internal/xdsclient/clientimpl_dump.go @@ -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 } diff --git a/xds/internal/xdsclient/tests/dump_test.go b/xds/internal/xdsclient/tests/dump_test.go index 577973f63c16..91e88c8ae5e8 100644 --- a/xds/internal/xdsclient/tests/dump_test.go +++ b/xds/internal/xdsclient/tests/dump_test.go @@ -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, + }, + { + TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener", + Name: ldsTargets[1], + ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, + }, + { + TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + Name: rdsTargets[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.route.v3.RouteConfiguration", + Name: rdsTargets[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.cluster.v3.Cluster", + Name: cdsTargets[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.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], + }, + { + TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener", + Name: ldsTargets[1], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + VersionInfo: "1", + XdsConfig: listenerAnys[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.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.route.v3.RouteConfiguration", + Name: rdsTargets[1], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + VersionInfo: "1", + XdsConfig: routeAnys[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.cluster.v3.Cluster", + Name: cdsTargets[0], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + VersionInfo: "1", + XdsConfig: clusterAnys[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.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"}}, - }, - "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}, - }, + XdsConfig: listenerAnys[0], + }, + { + TypeUrl: "type.googleapis.com/envoy.config.listener.v3.Listener", + Name: ldsTargets[1], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + VersionInfo: "2", + XdsConfig: listenerAnys[1], + }, + { + TypeUrl: "type.googleapis.com/envoy.config.route.v3.RouteConfiguration", + Name: rdsTargets[0], + ClientStatus: v3adminpb.ClientResourceStatus_NACKED, + VersionInfo: "1", + ErrorState: &v3adminpb.UpdateFailureState{ + VersionInfo: "2", }, - rdsTargets[1]: {Raw: routeAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "2"}}, - }, - "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}, - }, + XdsConfig: routeAnys[0], + }, + { + 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", }, - cdsTargets[1]: {Raw: clusterAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "2"}}, - }, - "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}, - }, + 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", }, - edsTargets[1]: {Raw: endpointAnys[1], MD: xdsresource.UpdateMetadata{Status: xdsresource.ServiceStatusACKed, Version: "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) } } diff --git a/xds/internal/xdsclient/tests/resource_update_test.go b/xds/internal/xdsclient/tests/resource_update_test.go index 89b5d338892e..dea76f4844b4 100644 --- a/xds/internal/xdsclient/tests/resource_update_test.go +++ b/xds/internal/xdsclient/tests/resource_update_test.go @@ -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) } })