xds/csds: populate new GenericXdsConfig field (#4898)

This commit is contained in:
Menghan Li 2021-10-26 15:11:36 -07:00 committed by GitHub
parent 6e8625df63
commit 9fa2698264
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 204 additions and 437 deletions

View File

@ -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 {

View File

@ -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,67 +55,44 @@ 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
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.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
}),
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())
}
if err := ptypes.UnmarshalAny(b.EndpointConfig, &bt); err != nil {
panic("failed to unmarshal Endpoints" + err.Error())
}
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(),
}
// 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
}
m.LastUpdated = nil
if m.ErrorState != nil {
m.ErrorState.Details = "blahblah"
m.ErrorState.LastUpdateAttempt = nil
}
}
return out
}
var (
ldsTargets = []string{"lds.target.good:0000", "lds.target.good:1111"}
listeners = make([]*v3listenerpb.Listener, len(ldsTargets))
@ -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))
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 _, 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))
}
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))
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 _, 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))
}
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,131 +409,87 @@ 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)
}
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)
}
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
// 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,
}
}
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,
}
}
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,
}
}
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,
}
}
want = append(want, config)
}
if diff := cmp.Diff(filterFields(r.Config[0].GenericXdsConfigs), want, cmpOpts); diff != "" {
return fmt.Errorf(diff)
}
return nil
}
func protoToJSON(p proto.Message) string {
mm := jsonpb.Marshaler{
Indent: " ",
}
ret, _ := mm.MarshalToString(p)
return ret
}
func TestCSDSNoXDSClient(t *testing.T) {
oldNewXDSClient := newXDSClient
newXDSClient = func() xdsclient.XDSClient { return nil }