diff --git a/xds/csds/csds.go b/xds/csds/csds.go index c4477a55d1a..1d817fbcc86 100644 --- a/xds/csds/csds.go +++ b/xds/csds/csds.go @@ -26,7 +26,6 @@ package csds import ( "context" "io" - "time" v3adminpb "github.com/envoyproxy/go-control-plane/envoy/admin/v3" v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" @@ -56,6 +55,13 @@ var ( } ) +const ( + listenerTypeURL = "envoy.config.listener.v3.Listener" + routeConfigTypeURL = "envoy.config.route.v3.RouteConfiguration" + clusterTypeURL = "envoy.config.cluster.v3.Cluster" + endpointsTypeURL = "envoy.config.endpoint.v3.ClusterLoadAssignment" +) + // ClientStatusDiscoveryServer implementations interface ClientStatusDiscoveryServiceServer. type ClientStatusDiscoveryServer struct { // xdsClient will always be the same in practice. But we keep a copy in each @@ -108,16 +114,21 @@ func (s *ClientStatusDiscoveryServer) buildClientStatusRespForReq(req *v3statusp return nil, status.Errorf(codes.InvalidArgument, "node_matchers are not supported, request contains node_matchers: %v", req.NodeMatchers) } + lds := dumpToGenericXdsConfig(listenerTypeURL, s.xdsClient.DumpLDS) + rds := dumpToGenericXdsConfig(routeConfigTypeURL, s.xdsClient.DumpRDS) + cds := dumpToGenericXdsConfig(clusterTypeURL, s.xdsClient.DumpCDS) + eds := dumpToGenericXdsConfig(endpointsTypeURL, s.xdsClient.DumpEDS) + configs := make([]*v3statuspb.ClientConfig_GenericXdsConfig, 0, len(lds)+len(rds)+len(cds)+len(eds)) + configs = append(configs, lds...) + configs = append(configs, rds...) + configs = append(configs, cds...) + configs = append(configs, eds...) + ret := &v3statuspb.ClientStatusResponse{ Config: []*v3statuspb.ClientConfig{ { - Node: nodeProtoToV3(s.xdsClient.BootstrapConfig().NodeProto), - XdsConfig: []*v3statuspb.PerXdsConfig{ - s.buildLDSPerXDSConfig(), - s.buildRDSPerXDSConfig(), - s.buildCDSPerXDSConfig(), - s.buildEDSPerXDSConfig(), - }, + Node: nodeProtoToV3(s.xdsClient.BootstrapConfig().NodeProto), + GenericXdsConfigs: configs, }, }, } @@ -162,129 +173,28 @@ func nodeProtoToV3(n proto.Message) *v3corepb.Node { return node } -func (s *ClientStatusDiscoveryServer) buildLDSPerXDSConfig() *v3statuspb.PerXdsConfig { - version, dump := s.xdsClient.DumpLDS() - resources := make([]*v3adminpb.ListenersConfigDump_DynamicListener, 0, len(dump)) +func dumpToGenericXdsConfig(typeURL string, dumpF func() (string, map[string]xdsclient.UpdateWithMD)) []*v3statuspb.ClientConfig_GenericXdsConfig { + _, dump := dumpF() + ret := make([]*v3statuspb.ClientConfig_GenericXdsConfig, 0, len(dump)) for name, d := range dump { - configDump := &v3adminpb.ListenersConfigDump_DynamicListener{ + config := &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: typeURL, Name: name, - ClientStatus: serviceStatusToProto(d.MD.Status), - } - if (d.MD.Timestamp != time.Time{}) { - configDump.ActiveState = &v3adminpb.ListenersConfigDump_DynamicListenerState{ - VersionInfo: d.MD.Version, - Listener: d.Raw, - LastUpdated: timestamppb.New(d.MD.Timestamp), - } - } - if errState := d.MD.ErrState; errState != nil { - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - LastUpdateAttempt: timestamppb.New(errState.Timestamp), - Details: errState.Err.Error(), - VersionInfo: errState.Version, - } - } - resources = append(resources, configDump) - } - return &v3statuspb.PerXdsConfig{ - PerXdsConfig: &v3statuspb.PerXdsConfig_ListenerConfig{ - ListenerConfig: &v3adminpb.ListenersConfigDump{ - VersionInfo: version, - DynamicListeners: resources, - }, - }, - } -} - -func (s *ClientStatusDiscoveryServer) buildRDSPerXDSConfig() *v3statuspb.PerXdsConfig { - _, dump := s.xdsClient.DumpRDS() - resources := make([]*v3adminpb.RoutesConfigDump_DynamicRouteConfig, 0, len(dump)) - for _, d := range dump { - configDump := &v3adminpb.RoutesConfigDump_DynamicRouteConfig{ VersionInfo: d.MD.Version, + XdsConfig: d.Raw, + LastUpdated: timestamppb.New(d.MD.Timestamp), ClientStatus: serviceStatusToProto(d.MD.Status), } - if (d.MD.Timestamp != time.Time{}) { - configDump.RouteConfig = d.Raw - configDump.LastUpdated = timestamppb.New(d.MD.Timestamp) - } if errState := d.MD.ErrState; errState != nil { - configDump.ErrorState = &v3adminpb.UpdateFailureState{ + config.ErrorState = &v3adminpb.UpdateFailureState{ LastUpdateAttempt: timestamppb.New(errState.Timestamp), Details: errState.Err.Error(), VersionInfo: errState.Version, } } - resources = append(resources, configDump) - } - return &v3statuspb.PerXdsConfig{ - PerXdsConfig: &v3statuspb.PerXdsConfig_RouteConfig{ - RouteConfig: &v3adminpb.RoutesConfigDump{ - DynamicRouteConfigs: resources, - }, - }, - } -} - -func (s *ClientStatusDiscoveryServer) buildCDSPerXDSConfig() *v3statuspb.PerXdsConfig { - version, dump := s.xdsClient.DumpCDS() - resources := make([]*v3adminpb.ClustersConfigDump_DynamicCluster, 0, len(dump)) - for _, d := range dump { - configDump := &v3adminpb.ClustersConfigDump_DynamicCluster{ - VersionInfo: d.MD.Version, - ClientStatus: serviceStatusToProto(d.MD.Status), - } - if (d.MD.Timestamp != time.Time{}) { - configDump.Cluster = d.Raw - configDump.LastUpdated = timestamppb.New(d.MD.Timestamp) - } - if errState := d.MD.ErrState; errState != nil { - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - LastUpdateAttempt: timestamppb.New(errState.Timestamp), - Details: errState.Err.Error(), - VersionInfo: errState.Version, - } - } - resources = append(resources, configDump) - } - return &v3statuspb.PerXdsConfig{ - PerXdsConfig: &v3statuspb.PerXdsConfig_ClusterConfig{ - ClusterConfig: &v3adminpb.ClustersConfigDump{ - VersionInfo: version, - DynamicActiveClusters: resources, - }, - }, - } -} - -func (s *ClientStatusDiscoveryServer) buildEDSPerXDSConfig() *v3statuspb.PerXdsConfig { - _, dump := s.xdsClient.DumpEDS() - resources := make([]*v3adminpb.EndpointsConfigDump_DynamicEndpointConfig, 0, len(dump)) - for _, d := range dump { - configDump := &v3adminpb.EndpointsConfigDump_DynamicEndpointConfig{ - VersionInfo: d.MD.Version, - ClientStatus: serviceStatusToProto(d.MD.Status), - } - if (d.MD.Timestamp != time.Time{}) { - configDump.EndpointConfig = d.Raw - configDump.LastUpdated = timestamppb.New(d.MD.Timestamp) - } - if errState := d.MD.ErrState; errState != nil { - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - LastUpdateAttempt: timestamppb.New(errState.Timestamp), - Details: errState.Err.Error(), - VersionInfo: errState.Version, - } - } - resources = append(resources, configDump) - } - return &v3statuspb.PerXdsConfig{ - PerXdsConfig: &v3statuspb.PerXdsConfig_EndpointConfig{ - EndpointConfig: &v3adminpb.EndpointsConfigDump{ - DynamicEndpointConfigs: resources, - }, - }, + ret = append(ret, config) } + return ret } func serviceStatusToProto(serviceStatus xdsclient.ServiceStatus) v3adminpb.ClientResourceStatus { diff --git a/xds/csds/csds_test.go b/xds/csds/csds_test.go index 9de83d37fec..ed1088b4339 100644 --- a/xds/csds/csds_test.go +++ b/xds/csds/csds_test.go @@ -21,15 +21,13 @@ package csds import ( "context" "fmt" + "sort" "strings" "testing" "time" - "github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes" "github.com/google/go-cmp/cmp" - "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "google.golang.org/grpc" "google.golang.org/grpc/internal/testutils" @@ -40,7 +38,6 @@ import ( "google.golang.org/grpc/xds/internal/xdsclient" "google.golang.org/protobuf/testing/protocmp" "google.golang.org/protobuf/types/known/anypb" - "google.golang.org/protobuf/types/known/timestamppb" v3adminpb "github.com/envoyproxy/go-control-plane/envoy/admin/v3" v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" @@ -58,65 +55,42 @@ const ( ) var cmpOpts = cmp.Options{ - cmpopts.EquateEmpty(), - cmp.Comparer(func(a, b *timestamppb.Timestamp) bool { return true }), - protocmp.IgnoreFields(&v3adminpb.UpdateFailureState{}, "last_update_attempt", "details"), - protocmp.SortRepeated(func(a, b *v3adminpb.ListenersConfigDump_DynamicListener) bool { - return strings.Compare(a.Name, b.Name) < 0 - }), - protocmp.SortRepeated(func(a, b *v3adminpb.RoutesConfigDump_DynamicRouteConfig) bool { - if a.RouteConfig == nil { - return false - } - if b.RouteConfig == nil { - return true - } - var at, bt v3routepb.RouteConfiguration - if err := ptypes.UnmarshalAny(a.RouteConfig, &at); err != nil { - panic("failed to unmarshal RouteConfig" + err.Error()) - } - if err := ptypes.UnmarshalAny(b.RouteConfig, &bt); err != nil { - panic("failed to unmarshal RouteConfig" + err.Error()) - } - return strings.Compare(at.Name, bt.Name) < 0 - }), - protocmp.SortRepeated(func(a, b *v3adminpb.ClustersConfigDump_DynamicCluster) bool { - if a.Cluster == nil { - return false - } - if b.Cluster == nil { - return true - } - var at, bt v3clusterpb.Cluster - if err := ptypes.UnmarshalAny(a.Cluster, &at); err != nil { - panic("failed to unmarshal Cluster" + err.Error()) - } - if err := ptypes.UnmarshalAny(b.Cluster, &bt); err != nil { - panic("failed to unmarshal Cluster" + err.Error()) - } - return strings.Compare(at.Name, bt.Name) < 0 + 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.SortRepeated(func(a, b *v3adminpb.EndpointsConfigDump_DynamicEndpointConfig) bool { - if a.EndpointConfig == nil { - return false - } - if b.EndpointConfig == nil { - return true - } - var at, bt v3endpointpb.ClusterLoadAssignment - if err := ptypes.UnmarshalAny(a.EndpointConfig, &at); err != nil { - panic("failed to unmarshal Endpoints" + err.Error()) + protocmp.Transform(), +} + +// filterFields clears unimportant fields in the proto messages. +// +// protocmp.IgnoreFields() doesn't work on nil messages (it panics). +func filterFields(ms []*v3statuspb.ClientConfig_GenericXdsConfig) []*v3statuspb.ClientConfig_GenericXdsConfig { + out := append([]*v3statuspb.ClientConfig_GenericXdsConfig{}, ms...) + for _, m := range out { + if m == nil { + continue } - if err := ptypes.UnmarshalAny(b.EndpointConfig, &bt); err != nil { - panic("failed to unmarshal Endpoints" + err.Error()) + m.LastUpdated = nil + if m.ErrorState != nil { + m.ErrorState.Details = "blahblah" + m.ErrorState.LastUpdateAttempt = nil } - return strings.Compare(at.ClusterName, bt.ClusterName) < 0 - }), - protocmp.IgnoreFields(&v3adminpb.ListenersConfigDump_DynamicListenerState{}, "last_updated"), - protocmp.IgnoreFields(&v3adminpb.RoutesConfigDump_DynamicRouteConfig{}, "last_updated"), - protocmp.IgnoreFields(&v3adminpb.ClustersConfigDump_DynamicCluster{}, "last_updated"), - protocmp.IgnoreFields(&v3adminpb.EndpointsConfigDump_DynamicEndpointConfig{}, "last_updated"), - protocmp.Transform(), + } + return out } var ( @@ -329,67 +303,31 @@ func checkForRequested(stream v3statuspbgrpc.ClientStatusDiscoveryService_Stream if n := len(r.Config); n != 1 { return fmt.Errorf("got %d configs, want 1: %v", n, proto.MarshalTextString(r)) } - if n := len(r.Config[0].XdsConfig); n != 4 { - return fmt.Errorf("got %d xds configs (one for each type), want 4: %v", n, proto.MarshalTextString(r)) - } - for _, cfg := range r.Config[0].XdsConfig { - switch config := cfg.PerXdsConfig.(type) { - case *v3statuspb.PerXdsConfig_ListenerConfig: - var wantLis []*v3adminpb.ListenersConfigDump_DynamicListener - for i := range ldsTargets { - wantLis = append(wantLis, &v3adminpb.ListenersConfigDump_DynamicListener{ - Name: ldsTargets[i], - ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, - }) - } - wantDump := &v3adminpb.ListenersConfigDump{ - DynamicListeners: wantLis, - } - if diff := cmp.Diff(config.ListenerConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_RouteConfig: - var wantRoutes []*v3adminpb.RoutesConfigDump_DynamicRouteConfig - for range rdsTargets { - wantRoutes = append(wantRoutes, &v3adminpb.RoutesConfigDump_DynamicRouteConfig{ - ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, - }) - } - wantDump := &v3adminpb.RoutesConfigDump{ - DynamicRouteConfigs: wantRoutes, - } - if diff := cmp.Diff(config.RouteConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_ClusterConfig: - var wantCluster []*v3adminpb.ClustersConfigDump_DynamicCluster - for range cdsTargets { - wantCluster = append(wantCluster, &v3adminpb.ClustersConfigDump_DynamicCluster{ - ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, - }) - } - wantDump := &v3adminpb.ClustersConfigDump{ - DynamicActiveClusters: wantCluster, - } - if diff := cmp.Diff(config.ClusterConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_EndpointConfig: - var wantEndpoint []*v3adminpb.EndpointsConfigDump_DynamicEndpointConfig - for range cdsTargets { - wantEndpoint = append(wantEndpoint, &v3adminpb.EndpointsConfigDump_DynamicEndpointConfig{ - ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, - }) - } - wantDump := &v3adminpb.EndpointsConfigDump{ - DynamicEndpointConfigs: wantEndpoint, - } - if diff := cmp.Diff(config.EndpointConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - default: - return fmt.Errorf("unexpected PerXdsConfig: %+v; %v", cfg.PerXdsConfig, protoToJSON(r)) - } + + var want []*v3statuspb.ClientConfig_GenericXdsConfig + // Status is Requested, but version and xds config are all unset. + for i := range ldsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: listenerTypeURL, Name: ldsTargets[i], ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, + }) + } + for i := range rdsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: routeConfigTypeURL, Name: rdsTargets[i], ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, + }) + } + for i := range cdsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: clusterTypeURL, Name: cdsTargets[i], ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, + }) + } + for i := range edsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: endpointsTypeURL, Name: edsTargets[i], ClientStatus: v3adminpb.ClientResourceStatus_REQUESTED, + }) + } + if diff := cmp.Diff(filterFields(r.Config[0].GenericXdsConfigs), want, cmpOpts); diff != "" { + return fmt.Errorf(diff) } return nil } @@ -409,84 +347,47 @@ func checkForACKed(stream v3statuspbgrpc.ClientStatusDiscoveryService_StreamClie if n := len(r.Config); n != 1 { return fmt.Errorf("got %d configs, want 1: %v", n, proto.MarshalTextString(r)) } - if n := len(r.Config[0].XdsConfig); n != 4 { - return fmt.Errorf("got %d xds configs (one for each type), want 4: %v", n, proto.MarshalTextString(r)) - } - for _, cfg := range r.Config[0].XdsConfig { - switch config := cfg.PerXdsConfig.(type) { - case *v3statuspb.PerXdsConfig_ListenerConfig: - var wantLis []*v3adminpb.ListenersConfigDump_DynamicListener - for i := range ldsTargets { - wantLis = append(wantLis, &v3adminpb.ListenersConfigDump_DynamicListener{ - Name: ldsTargets[i], - ActiveState: &v3adminpb.ListenersConfigDump_DynamicListenerState{ - VersionInfo: wantVersion, - Listener: listenerAnys[i], - LastUpdated: nil, - }, - ErrorState: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - }) - } - wantDump := &v3adminpb.ListenersConfigDump{ - VersionInfo: wantVersion, - DynamicListeners: wantLis, - } - if diff := cmp.Diff(config.ListenerConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_RouteConfig: - var wantRoutes []*v3adminpb.RoutesConfigDump_DynamicRouteConfig - for i := range rdsTargets { - wantRoutes = append(wantRoutes, &v3adminpb.RoutesConfigDump_DynamicRouteConfig{ - VersionInfo: wantVersion, - RouteConfig: routeAnys[i], - LastUpdated: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - }) - } - wantDump := &v3adminpb.RoutesConfigDump{ - DynamicRouteConfigs: wantRoutes, - } - if diff := cmp.Diff(config.RouteConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_ClusterConfig: - var wantCluster []*v3adminpb.ClustersConfigDump_DynamicCluster - for i := range cdsTargets { - wantCluster = append(wantCluster, &v3adminpb.ClustersConfigDump_DynamicCluster{ - VersionInfo: wantVersion, - Cluster: clusterAnys[i], - LastUpdated: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - }) - } - wantDump := &v3adminpb.ClustersConfigDump{ - VersionInfo: wantVersion, - DynamicActiveClusters: wantCluster, - } - if diff := cmp.Diff(config.ClusterConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_EndpointConfig: - var wantEndpoint []*v3adminpb.EndpointsConfigDump_DynamicEndpointConfig - for i := range cdsTargets { - wantEndpoint = append(wantEndpoint, &v3adminpb.EndpointsConfigDump_DynamicEndpointConfig{ - VersionInfo: wantVersion, - EndpointConfig: endpointAnys[i], - LastUpdated: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - }) - } - wantDump := &v3adminpb.EndpointsConfigDump{ - DynamicEndpointConfigs: wantEndpoint, - } - if diff := cmp.Diff(config.EndpointConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - default: - return fmt.Errorf("unexpected PerXdsConfig: %+v; %v", cfg.PerXdsConfig, protoToJSON(r)) - } + + var want []*v3statuspb.ClientConfig_GenericXdsConfig + // Status is Acked, config is filled with the prebuilt Anys. + for i := range ldsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: listenerTypeURL, + Name: ldsTargets[i], + VersionInfo: wantVersion, + XdsConfig: listenerAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + }) + } + for i := range rdsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: routeConfigTypeURL, + Name: rdsTargets[i], + VersionInfo: wantVersion, + XdsConfig: routeAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + }) + } + for i := range cdsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: clusterTypeURL, + Name: cdsTargets[i], + VersionInfo: wantVersion, + XdsConfig: clusterAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + }) + } + for i := range edsTargets { + want = append(want, &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: endpointsTypeURL, + Name: edsTargets[i], + VersionInfo: wantVersion, + XdsConfig: endpointAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + }) + } + if diff := cmp.Diff(filterFields(r.Config[0].GenericXdsConfigs), want, cmpOpts); diff != "" { + return fmt.Errorf(diff) } return nil } @@ -508,129 +409,85 @@ func checkForNACKed(nackResourceIdx int, stream v3statuspbgrpc.ClientStatusDisco if n := len(r.Config); n != 1 { return fmt.Errorf("got %d configs, want 1: %v", n, proto.MarshalTextString(r)) } - if n := len(r.Config[0].XdsConfig); n != 4 { - return fmt.Errorf("got %d xds configs (one for each type), want 4: %v", n, proto.MarshalTextString(r)) - } - for _, cfg := range r.Config[0].XdsConfig { - switch config := cfg.PerXdsConfig.(type) { - case *v3statuspb.PerXdsConfig_ListenerConfig: - var wantLis []*v3adminpb.ListenersConfigDump_DynamicListener - for i := range ldsTargets { - configDump := &v3adminpb.ListenersConfigDump_DynamicListener{ - Name: ldsTargets[i], - ActiveState: &v3adminpb.ListenersConfigDump_DynamicListenerState{ - VersionInfo: nackVersion, - Listener: listenerAnys[i], - LastUpdated: nil, - }, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - } - if i == nackResourceIdx { - configDump.ActiveState.VersionInfo = ackVersion - configDump.ClientStatus = v3adminpb.ClientResourceStatus_NACKED - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - Details: "blahblah", - VersionInfo: nackVersion, - } - } - wantLis = append(wantLis, configDump) - } - wantDump := &v3adminpb.ListenersConfigDump{ - VersionInfo: nackVersion, - DynamicListeners: wantLis, - } - if diff := cmp.Diff(config.ListenerConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_RouteConfig: - var wantRoutes []*v3adminpb.RoutesConfigDump_DynamicRouteConfig - for i := range rdsTargets { - configDump := &v3adminpb.RoutesConfigDump_DynamicRouteConfig{ - VersionInfo: nackVersion, - RouteConfig: routeAnys[i], - LastUpdated: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - } - if i == nackResourceIdx { - configDump.VersionInfo = ackVersion - configDump.ClientStatus = v3adminpb.ClientResourceStatus_NACKED - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - Details: "blahblah", - VersionInfo: nackVersion, - } - } - wantRoutes = append(wantRoutes, configDump) - } - wantDump := &v3adminpb.RoutesConfigDump{ - DynamicRouteConfigs: wantRoutes, - } - if diff := cmp.Diff(config.RouteConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) - } - case *v3statuspb.PerXdsConfig_ClusterConfig: - var wantCluster []*v3adminpb.ClustersConfigDump_DynamicCluster - for i := range cdsTargets { - configDump := &v3adminpb.ClustersConfigDump_DynamicCluster{ - VersionInfo: nackVersion, - Cluster: clusterAnys[i], - LastUpdated: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - } - if i == nackResourceIdx { - configDump.VersionInfo = ackVersion - configDump.ClientStatus = v3adminpb.ClientResourceStatus_NACKED - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - Details: "blahblah", - VersionInfo: nackVersion, - } - } - wantCluster = append(wantCluster, configDump) - } - wantDump := &v3adminpb.ClustersConfigDump{ - VersionInfo: nackVersion, - DynamicActiveClusters: wantCluster, - } - if diff := cmp.Diff(config.ClusterConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) + + var want []*v3statuspb.ClientConfig_GenericXdsConfig + // Resources with the nackIdx are NACKed. + for i := range ldsTargets { + config := &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: listenerTypeURL, + Name: ldsTargets[i], + VersionInfo: nackVersion, + XdsConfig: listenerAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + } + if i == nackResourceIdx { + config.VersionInfo = ackVersion + config.ClientStatus = v3adminpb.ClientResourceStatus_NACKED + config.ErrorState = &v3adminpb.UpdateFailureState{ + Details: "blahblah", + VersionInfo: nackVersion, } - case *v3statuspb.PerXdsConfig_EndpointConfig: - var wantEndpoint []*v3adminpb.EndpointsConfigDump_DynamicEndpointConfig - for i := range cdsTargets { - configDump := &v3adminpb.EndpointsConfigDump_DynamicEndpointConfig{ - VersionInfo: nackVersion, - EndpointConfig: endpointAnys[i], - LastUpdated: nil, - ClientStatus: v3adminpb.ClientResourceStatus_ACKED, - } - if i == nackResourceIdx { - configDump.VersionInfo = ackVersion - configDump.ClientStatus = v3adminpb.ClientResourceStatus_NACKED - configDump.ErrorState = &v3adminpb.UpdateFailureState{ - Details: "blahblah", - VersionInfo: nackVersion, - } - } - wantEndpoint = append(wantEndpoint, configDump) + } + want = append(want, config) + } + for i := range rdsTargets { + config := &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: routeConfigTypeURL, + Name: rdsTargets[i], + VersionInfo: nackVersion, + XdsConfig: routeAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + } + if i == nackResourceIdx { + config.VersionInfo = ackVersion + config.ClientStatus = v3adminpb.ClientResourceStatus_NACKED + config.ErrorState = &v3adminpb.UpdateFailureState{ + Details: "blahblah", + VersionInfo: nackVersion, } - wantDump := &v3adminpb.EndpointsConfigDump{ - DynamicEndpointConfigs: wantEndpoint, + } + want = append(want, config) + } + for i := range cdsTargets { + config := &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: clusterTypeURL, + Name: cdsTargets[i], + VersionInfo: nackVersion, + XdsConfig: clusterAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + } + if i == nackResourceIdx { + config.VersionInfo = ackVersion + config.ClientStatus = v3adminpb.ClientResourceStatus_NACKED + config.ErrorState = &v3adminpb.UpdateFailureState{ + Details: "blahblah", + VersionInfo: nackVersion, } - if diff := cmp.Diff(config.EndpointConfig, wantDump, cmpOpts); diff != "" { - return fmt.Errorf(diff) + } + want = append(want, config) + } + for i := range edsTargets { + config := &v3statuspb.ClientConfig_GenericXdsConfig{ + TypeUrl: endpointsTypeURL, + Name: edsTargets[i], + VersionInfo: nackVersion, + XdsConfig: endpointAnys[i], + ClientStatus: v3adminpb.ClientResourceStatus_ACKED, + } + if i == nackResourceIdx { + config.VersionInfo = ackVersion + config.ClientStatus = v3adminpb.ClientResourceStatus_NACKED + config.ErrorState = &v3adminpb.UpdateFailureState{ + Details: "blahblah", + VersionInfo: nackVersion, } - default: - return fmt.Errorf("unexpected PerXdsConfig: %+v; %v", cfg.PerXdsConfig, protoToJSON(r)) } + want = append(want, config) } - return nil -} - -func protoToJSON(p proto.Message) string { - mm := jsonpb.Marshaler{ - Indent: " ", + if diff := cmp.Diff(filterFields(r.Config[0].GenericXdsConfigs), want, cmpOpts); diff != "" { + return fmt.Errorf(diff) } - ret, _ := mm.MarshalToString(p) - return ret + return nil } func TestCSDSNoXDSClient(t *testing.T) {