diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_cds.go b/xds/internal/xdsclient/xdsresource/unmarshal_cds.go index 5b34c1ae6e1e..b0cc296307a0 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_cds.go +++ b/xds/internal/xdsclient/xdsresource/unmarshal_cds.go @@ -136,8 +136,8 @@ func validateClusterAndConstructClusterUpdate(cluster *v3clusterpb.Cluster) (Clu // Validate and set cluster type from the response. switch { case cluster.GetType() == v3clusterpb.Cluster_EDS: - if cluster.GetEdsClusterConfig().GetEdsConfig().GetAds() == nil { - return ClusterUpdate{}, fmt.Errorf("unexpected edsConfig in response: %+v", cluster) + if configsource := cluster.GetEdsClusterConfig().GetEdsConfig(); configsource.GetAds() == nil && configsource.GetSelf() == nil { + return ClusterUpdate{}, fmt.Errorf("CDS's EDS config source is not ADS or Self: %+v", cluster) } ret.ClusterType = ClusterTypeEDS ret.EDSServiceName = cluster.GetEdsClusterConfig().GetServiceName() diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go b/xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go index dd2f72e0fada..6b8deb2d9b95 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go +++ b/xds/internal/xdsclient/xdsresource/unmarshal_cds_test.go @@ -1421,6 +1421,23 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, }) + + v3ClusterAnyWithEDSConfigSourceSelf = testutils.MarshalAny(&v3clusterpb.Cluster{ + Name: v3ClusterName, + ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS}, + EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{ + EdsConfig: &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{}, + }, + ServiceName: v3Service, + }, + LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN, + LrsServer: &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{ + Self: &v3corepb.SelfConfigSource{}, + }, + }, + }) ) const testVersion = "test-version-cds" @@ -1513,6 +1530,21 @@ func (s) TestUnmarshalCluster(t *testing.T) { Version: testVersion, }, }, + { + name: "v3 cluster with EDS config source self", + resources: []*anypb.Any{v3ClusterAnyWithEDSConfigSourceSelf}, + wantUpdate: map[string]ClusterUpdateErrTuple{ + v3ClusterName: {Update: ClusterUpdate{ + ClusterName: v3ClusterName, + EDSServiceName: v3Service, EnableLRS: true, + Raw: v3ClusterAnyWithEDSConfigSourceSelf, + }}, + }, + wantMD: UpdateMetadata{ + Status: ServiceStatusACKed, + Version: testVersion, + }, + }, { name: "multiple clusters", resources: []*anypb.Any{v2ClusterAny, v3ClusterAny}, diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_lds.go b/xds/internal/xdsclient/xdsresource/unmarshal_lds.go index f9663d05bee3..b259c7b87e4c 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_lds.go +++ b/xds/internal/xdsclient/xdsresource/unmarshal_lds.go @@ -102,8 +102,8 @@ func processClientSideListener(lis *v3listenerpb.Listener, logger *grpclog.Prefi switch apiLis.RouteSpecifier.(type) { case *v3httppb.HttpConnectionManager_Rds: - if apiLis.GetRds().GetConfigSource().GetAds() == nil { - return nil, fmt.Errorf("ConfigSource is not ADS: %+v", lis) + if configsource := apiLis.GetRds().GetConfigSource(); configsource.GetAds() == nil && configsource.GetSelf() == nil { + return nil, fmt.Errorf("LDS's RDS configSource is not ADS or Self: %+v", lis) } name := apiLis.GetRds().GetRouteConfigName() if name == "" { diff --git a/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go b/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go index a5c53886ecbd..4444421a4929 100644 --- a/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go +++ b/xds/internal/xdsclient/xdsresource/unmarshal_lds_test.go @@ -204,6 +204,25 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }) } + + v3ListenerWithCDSConfigSourceSelf = testutils.MarshalAny(&v3listenerpb.Listener{ + Name: v3LDSTarget, + ApiListener: &v3listenerpb.ApiListener{ + ApiListener: testutils.MarshalAny( + &v3httppb.HttpConnectionManager{ + RouteSpecifier: &v3httppb.HttpConnectionManager_Rds{ + Rds: &v3httppb.Rds{ + ConfigSource: &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{}, + }, + RouteConfigName: v3RouteConfigName, + }, + }, + HttpFilters: []*v3httppb.HttpFilter{emptyRouterFilter}, + }), + }, + }) + errMD = UpdateMetadata{ Status: ServiceStatusNACKed, Version: testVersion, @@ -294,7 +313,22 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "rds.ConfigSource in apiListener is not ADS", + name: "rds.ConfigSource in apiListener is Self", + resources: []*anypb.Any{v3ListenerWithCDSConfigSourceSelf}, + wantUpdate: map[string]ListenerUpdateErrTuple{ + v3LDSTarget: {Update: ListenerUpdate{ + RouteConfigName: v3RouteConfigName, + HTTPFilters: []HTTPFilter{routerFilter}, + Raw: v3ListenerWithCDSConfigSourceSelf, + }}, + }, + wantMD: UpdateMetadata{ + Status: ServiceStatusACKed, + Version: testVersion, + }, + }, + { + name: "rds.ConfigSource in apiListener is not ADS or Self", resources: []*anypb.Any{testutils.MarshalAny(&v3listenerpb.Listener{ Name: v3LDSTarget, ApiListener: &v3listenerpb.ApiListener{