From 2c468f44759e06c3e31b3c8b55dc9214b7465784 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Tue, 10 Mar 2026 12:13:23 +0000 Subject: [PATCH 1/6] resolve panic condition --- internal/xds/clients/xdsclient/channel.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/xds/clients/xdsclient/channel.go b/internal/xds/clients/xdsclient/channel.go index b4c3e65be009..df87130c2e29 100644 --- a/internal/xds/clients/xdsclient/channel.go +++ b/internal/xds/clients/xdsclient/channel.go @@ -271,7 +271,7 @@ func decodeResponse(opts *DecodeOptions, rType *ResourceType, resp response) (ma if result != nil { name = xdsresource.ParseName(result.Name).String() } - if err == nil { + if err == nil && result != nil { ret[name] = dataAndErrTuple{Resource: result.Resource} continue } From 9a8ab74edc8fa5455e0f976512bd76a2710cb1b2 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Tue, 10 Mar 2026 15:43:38 +0000 Subject: [PATCH 2/6] add nil check --- internal/xds/clients/xdsclient/channel.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/internal/xds/clients/xdsclient/channel.go b/internal/xds/clients/xdsclient/channel.go index df87130c2e29..48154d7d3218 100644 --- a/internal/xds/clients/xdsclient/channel.go +++ b/internal/xds/clients/xdsclient/channel.go @@ -268,10 +268,13 @@ func decodeResponse(opts *DecodeOptions, rType *ResourceType, resp response) (ma // Name field of the result is left unpopulated only when resource // deserialization fails. name := "" + if result == nil && err == nil { + continue + } if result != nil { name = xdsresource.ParseName(result.Name).String() } - if err == nil && result != nil { + if err == nil { ret[name] = dataAndErrTuple{Resource: result.Resource} continue } From 7c122f8c5d9c35c62619a14385e7a46caf55d609 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Fri, 13 Mar 2026 05:29:41 +0000 Subject: [PATCH 3/6] handle empty name in Decoder --- .../xds/xdsclient/xdsresource/cluster_resource_type.go | 6 ++++-- .../xds/xdsclient/xdsresource/endpoints_resource_type.go | 7 +++++-- .../xds/xdsclient/xdsresource/listener_resource_type.go | 6 ++++-- .../xdsclient/xdsresource/route_config_resource_type.go | 7 +++++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/internal/xds/xdsclient/xdsresource/cluster_resource_type.go b/internal/xds/xdsclient/xdsresource/cluster_resource_type.go index af4e785b5a49..3ee23dee821b 100644 --- a/internal/xds/xdsclient/xdsresource/cluster_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/cluster_resource_type.go @@ -46,8 +46,10 @@ func (d *clusterResourceDecoder) Decode(resource *xdsclient.AnyProto, opts xdscl } name, cluster, err := unmarshalClusterResource(resource.ToAny(), serverCfg) if name == "" { - // Name is unset only when protobuf deserialization fails. - return nil, err + if err != nil { + return nil, err + } + return nil, fmt.Errorf("empty resource name in Cluster resource") } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go b/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go index cf72c49574a2..f1ec93083be5 100644 --- a/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go @@ -19,6 +19,7 @@ package xdsresource import ( "bytes" + "fmt" "google.golang.org/grpc/internal/xds/bootstrap" xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" @@ -40,8 +41,10 @@ type endpointsResourceDecoder struct { func (d *endpointsResourceDecoder) Decode(resource *xdsclient.AnyProto, _ xdsclient.DecodeOptions) (*xdsclient.DecodeResult, error) { name, endpoints, err := unmarshalEndpointsResource(resource.ToAny()) if name == "" { - // Name is unset only when protobuf deserialization fails. - return nil, err + if err != nil { + return nil, err + } + return nil, fmt.Errorf("empty resource name in Endpoints resource") } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/listener_resource_type.go b/internal/xds/xdsclient/xdsresource/listener_resource_type.go index 71d529f92f21..2acc9bb4d782 100644 --- a/internal/xds/xdsclient/xdsresource/listener_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/listener_resource_type.go @@ -38,8 +38,10 @@ type listenerResourceDecoder struct { func (d *listenerResourceDecoder) Decode(resource *xdsclient.AnyProto, opts xdsclient.DecodeOptions) (*xdsclient.DecodeResult, error) { name, listener, err := unmarshalListenerResource(resource.ToAny(), &opts) if name == "" { - // Name is unset only when protobuf deserialization fails. - return nil, err + if err != nil { + return nil, err + } + return nil, fmt.Errorf("empty resource name in Listener resource") } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/route_config_resource_type.go b/internal/xds/xdsclient/xdsresource/route_config_resource_type.go index 1104fe9f2b4d..9d846201ef89 100644 --- a/internal/xds/xdsclient/xdsresource/route_config_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/route_config_resource_type.go @@ -19,6 +19,7 @@ package xdsresource import ( "bytes" + "fmt" "google.golang.org/grpc/internal/xds/bootstrap" xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" @@ -40,8 +41,10 @@ type routeConfigResourceDecoder struct { func (d *routeConfigResourceDecoder) Decode(resource *xdsclient.AnyProto, opts xdsclient.DecodeOptions) (*xdsclient.DecodeResult, error) { name, rc, err := unmarshalRouteConfigResource(resource.ToAny(), &opts) if name == "" { - // Name is unset only when protobuf deserialization fails. - return nil, err + if err != nil { + return nil, err + } + return nil, fmt.Errorf("empty resource name in RouteConfig resource") } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. From c59a831c54cde5730c0c5ce1971cbfd026745e74 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Fri, 13 Mar 2026 11:03:49 +0000 Subject: [PATCH 4/6] resolving comments --- .../xdsresource/cluster_resource_type.go | 6 +- .../xdsresource/endpoints_resource_type.go | 7 +- .../xdsresource/filter_chain_test.go | 19 +++++ .../xdsresource/listener_resource_type.go | 6 +- .../xdsresource/route_config_resource_type.go | 7 +- .../xdsclient/xdsresource/unmarshal_cds.go | 3 + .../xdsresource/unmarshal_cds_test.go | 41 ++++++++--- .../xdsclient/xdsresource/unmarshal_eds.go | 4 ++ .../xdsresource/unmarshal_eds_test.go | 22 ++++-- .../xdsclient/xdsresource/unmarshal_lds.go | 4 ++ .../xdsresource/unmarshal_lds_test.go | 69 ++++++++++++------- .../xdsclient/xdsresource/unmarshal_rds.go | 4 ++ .../xdsresource/unmarshal_rds_test.go | 9 +++ 13 files changed, 145 insertions(+), 56 deletions(-) diff --git a/internal/xds/xdsclient/xdsresource/cluster_resource_type.go b/internal/xds/xdsclient/xdsresource/cluster_resource_type.go index 3ee23dee821b..af4e785b5a49 100644 --- a/internal/xds/xdsclient/xdsresource/cluster_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/cluster_resource_type.go @@ -46,10 +46,8 @@ func (d *clusterResourceDecoder) Decode(resource *xdsclient.AnyProto, opts xdscl } name, cluster, err := unmarshalClusterResource(resource.ToAny(), serverCfg) if name == "" { - if err != nil { - return nil, err - } - return nil, fmt.Errorf("empty resource name in Cluster resource") + // Name is unset only when protobuf deserialization fails. + return nil, err } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go b/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go index f1ec93083be5..cf72c49574a2 100644 --- a/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/endpoints_resource_type.go @@ -19,7 +19,6 @@ package xdsresource import ( "bytes" - "fmt" "google.golang.org/grpc/internal/xds/bootstrap" xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" @@ -41,10 +40,8 @@ type endpointsResourceDecoder struct { func (d *endpointsResourceDecoder) Decode(resource *xdsclient.AnyProto, _ xdsclient.DecodeOptions) (*xdsclient.DecodeResult, error) { name, endpoints, err := unmarshalEndpointsResource(resource.ToAny()) if name == "" { - if err != nil { - return nil, err - } - return nil, fmt.Errorf("empty resource name in Endpoints resource") + // Name is unset only when protobuf deserialization fails. + return nil, err } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/filter_chain_test.go b/internal/xds/xdsclient/xdsresource/filter_chain_test.go index db295eb51c6a..2bc3cee9c8da 100644 --- a/internal/xds/xdsclient/xdsresource/filter_chain_test.go +++ b/internal/xds/xdsclient/xdsresource/filter_chain_test.go @@ -606,6 +606,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodRouteUpdate(t *testing.T) { { name: "one_route_config_name", lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -683,6 +684,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodRouteUpdate(t *testing.T) { { name: "inline_route_config", lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -750,6 +752,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodRouteUpdate(t *testing.T) { { name: "two_route_config_names", lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1060,6 +1063,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodHTTPFilters(t *testing.T) { { name: "singular valid http filter", lis: &v3listenerpb.Listener{ + Name: "listener-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1147,6 +1151,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodHTTPFilters(t *testing.T) { { name: "two valid http filters", lis: &v3listenerpb.Listener{ + Name: "listener-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1248,6 +1253,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodHTTPFilters(t *testing.T) { { name: "two hcms", lis: &v3listenerpb.Listener{ + Name: "listener-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1400,6 +1406,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodSecurityConfig(t *testing.T) { { desc: "empty transport socket", lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1443,6 +1450,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodSecurityConfig(t *testing.T) { { desc: "no validation context", lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1519,6 +1527,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodSecurityConfig(t *testing.T) { { desc: "validation context with certificate provider", lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1617,6 +1626,7 @@ func (s) TestUnmarshalListener_ServerSide_GoodSecurityConfig(t *testing.T) { desc: "validation context with certificate provider and system root certs", enableSystemRootCertsFlag: true, lis: &v3listenerpb.Listener{ + Name: "listerner-1", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1756,6 +1766,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_UnsupportedMatchFields(t *test { desc: "unsupported destination port", lis: &v3listenerpb.Listener{ + Name: "listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1805,6 +1816,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_UnsupportedMatchFields(t *test { desc: "unsupported server names", lis: &v3listenerpb.Listener{ + Name: "listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1854,6 +1866,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_UnsupportedMatchFields(t *test { desc: "unsupported transport protocol", lis: &v3listenerpb.Listener{ + Name: "listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1903,6 +1916,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_UnsupportedMatchFields(t *test { desc: "unsupported application protocol", lis: &v3listenerpb.Listener{ + Name: "listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -1976,6 +1990,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_AllCombinations(t *testing.T) { desc: "multiple destination prefixes", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -2112,6 +2127,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_AllCombinations(t *testing.T) { desc: "multiple source types", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -2185,6 +2201,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_AllCombinations(t *testing.T) { desc: "multiple source prefixes", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -2256,6 +2273,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_AllCombinations(t *testing.T) { desc: "multiple source ports", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -2354,6 +2372,7 @@ func (s) TestUnmarshalListener_ServerSide_Success_AllCombinations(t *testing.T) { desc: "some chains have unsupported fields", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { diff --git a/internal/xds/xdsclient/xdsresource/listener_resource_type.go b/internal/xds/xdsclient/xdsresource/listener_resource_type.go index 2acc9bb4d782..71d529f92f21 100644 --- a/internal/xds/xdsclient/xdsresource/listener_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/listener_resource_type.go @@ -38,10 +38,8 @@ type listenerResourceDecoder struct { func (d *listenerResourceDecoder) Decode(resource *xdsclient.AnyProto, opts xdsclient.DecodeOptions) (*xdsclient.DecodeResult, error) { name, listener, err := unmarshalListenerResource(resource.ToAny(), &opts) if name == "" { - if err != nil { - return nil, err - } - return nil, fmt.Errorf("empty resource name in Listener resource") + // Name is unset only when protobuf deserialization fails. + return nil, err } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/route_config_resource_type.go b/internal/xds/xdsclient/xdsresource/route_config_resource_type.go index 9d846201ef89..1104fe9f2b4d 100644 --- a/internal/xds/xdsclient/xdsresource/route_config_resource_type.go +++ b/internal/xds/xdsclient/xdsresource/route_config_resource_type.go @@ -19,7 +19,6 @@ package xdsresource import ( "bytes" - "fmt" "google.golang.org/grpc/internal/xds/bootstrap" xdsclient "google.golang.org/grpc/internal/xds/clients/xdsclient" @@ -41,10 +40,8 @@ type routeConfigResourceDecoder struct { func (d *routeConfigResourceDecoder) Decode(resource *xdsclient.AnyProto, opts xdsclient.DecodeOptions) (*xdsclient.DecodeResult, error) { name, rc, err := unmarshalRouteConfigResource(resource.ToAny(), &opts) if name == "" { - if err != nil { - return nil, err - } - return nil, fmt.Errorf("empty resource name in RouteConfig resource") + // Name is unset only when protobuf deserialization fails. + return nil, err } if err != nil { // Protobuf deserialization succeeded, but resource validation failed. diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_cds.go b/internal/xds/xdsclient/xdsresource/unmarshal_cds.go index d7133c996cb3..87c08e155146 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_cds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_cds.go @@ -71,6 +71,9 @@ func unmarshalClusterResource(r *anypb.Any, serverCfg *bootstrap.ServerConfig) ( } cu.Raw = r + if cluster.GetName() == "" { + return "", ClusterUpdate{}, fmt.Errorf("empty resource name in Cluster resource") + } return cluster.GetName(), cu, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go index cef43b25b50c..a27177c8059c 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_cds_test.go @@ -1401,6 +1401,24 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, }) + v3ClusterWithEmptyName = testutils.MarshalAny(t, &v3clusterpb.Cluster{ + Name: "", + ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS}, + EdsClusterConfig: &v3clusterpb.Cluster_EdsClusterConfig{ + EdsConfig: &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Ads{ + Ads: &v3corepb.AggregatedConfigSource{}, + }, + }, + ServiceName: v3Service, + }, + LbPolicy: v3clusterpb.Cluster_ROUND_ROBIN, + LrsServer: &v3corepb.ConfigSource{ + ConfigSourceSpecifier: &v3corepb.ConfigSource_Self{ + Self: &v3corepb.SelfConfigSource{}, + }, + }, + }) v3ClusterAnyWithEDSConfigSourceSelf = testutils.MarshalAny(t, &v3clusterpb.Cluster{ Name: v3ClusterName, @@ -1512,7 +1530,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { wantErr: true, }, { - name: "bad cluster resource", + name: "bad_cluster_resource", resource: testutils.MarshalAny(t, &v3clusterpb.Cluster{ Name: "test", ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_STATIC}, @@ -1521,7 +1539,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { wantErr: true, }, { - name: "cluster resource with non-self lrs_server field", + name: "cluster_resource_with_non-self_lrs_server_field", resource: testutils.MarshalAny(t, &v3clusterpb.Cluster{ Name: "test", ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS}, @@ -1544,7 +1562,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { wantErr: true, }, { - name: "v3 cluster", + name: "v3_cluster", resource: v3ClusterAny, serverCfg: serverCfg, wantName: v3ClusterName, @@ -1557,7 +1575,14 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, { - name: "v3 cluster wrapped", + name: "cluster_resource_with_empty_name", + resource: v3ClusterWithEmptyName, + serverCfg: serverCfg, + wantName: "", + wantErr: true, + }, + { + name: "v3_cluster_wrapped", resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3ClusterAny}), serverCfg: serverCfg, wantName: v3ClusterName, @@ -1570,7 +1595,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, { - name: "v3 cluster with EDS config source self", + name: "v3_cluster_with_EDS_config_source_self", resource: v3ClusterAnyWithEDSConfigSourceSelf, serverCfg: serverCfg, wantName: v3ClusterName, @@ -1583,7 +1608,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, { - name: "v3 cluster with telemetry case", + name: "v3_cluster_with_telemetry_case", resource: v3ClusterAnyWithTelemetryLabels, serverCfg: serverCfg, wantName: v3ClusterName, @@ -1599,7 +1624,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, { - name: "v3 metadata ignore other types not string and not com.google.csm.telemetry_labels", + name: "v3_metadata_ignore_other_types_not_string_and_not_com.google.csm.telemetry_labels", resource: v3ClusterAnyWithTelemetryLabelsIgnoreSome, serverCfg: serverCfg, wantName: v3ClusterName, @@ -1615,7 +1640,7 @@ func (s) TestUnmarshalCluster(t *testing.T) { }, }, { - name: "xdstp cluster resource with unset EDS service name", + name: "xdstp_cluster_resource_with_unset_EDS_service_name", resource: testutils.MarshalAny(t, &v3clusterpb.Cluster{ Name: "xdstp:foo", ClusterDiscoveryType: &v3clusterpb.Cluster_Type{Type: v3clusterpb.Cluster_EDS}, diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go index 581cbf6f72ea..d65e9a675572 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -79,6 +79,10 @@ func unmarshalEndpointsResource(r *anypb.Any) (string, EndpointsUpdate, error) { return cla.GetClusterName(), EndpointsUpdate{}, err } u.Raw = r + + if cla.GetClusterName() == "" { + return "", EndpointsUpdate{}, fmt.Errorf("empty resource name in endpoints resource") + } return cla.GetClusterName(), u, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go index cabc0c83bddf..9e2d9a59145d 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds_test.go @@ -396,6 +396,7 @@ func (s) TestEDSParseRespProtoAdditionalAddrs(t *testing.T) { func (s) TestUnmarshalEndpointHashKey(t *testing.T) { baseCLA := &v3endpointpb.ClusterLoadAssignment{ + ClusterName: "test-cluster", Endpoints: []*v3endpointpb.LocalityLbEndpoints{ { Locality: &v3corepb.Locality{Region: "r"}, @@ -550,12 +551,12 @@ func (s) TestUnmarshalEndpoints(t *testing.T) { wantErr bool }{ { - name: "non-clusterLoadAssignment resource type", + name: "non-clusterLoadAssignment_resourcetype", resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL}, wantErr: true, }, { - name: "badly marshaled clusterLoadAssignment resource", + name: "badly_marshaled_clusterLoadAssignment_resource", resource: &anypb.Any{ TypeUrl: version.V3EndpointsURL, Value: []byte{1, 2, 3, 4}, @@ -563,7 +564,7 @@ func (s) TestUnmarshalEndpoints(t *testing.T) { wantErr: true, }, { - name: "bad endpoints resource", + name: "bad_endpoints_resource", resource: testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment { clab0 := newClaBuilder("test", nil) clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) @@ -574,7 +575,18 @@ func (s) TestUnmarshalEndpoints(t *testing.T) { wantErr: true, }, { - name: "v3 endpoints", + name: "endpoint_resource_with_empty_cluster_name", + resource: testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment { + clab0 := newClaBuilder("", nil) + clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) + clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil) + return clab0.Build() + }()), + wantName: "", + wantErr: true, + }, + { + name: "v3_endpoints", resource: v3EndpointsAny, wantName: "test", wantUpdate: EndpointsUpdate{ @@ -605,7 +617,7 @@ func (s) TestUnmarshalEndpoints(t *testing.T) { }, }, { - name: "v3 endpoints wrapped", + name: "v3_endpoints_wrapped", resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3EndpointsAny}), wantName: "test", wantUpdate: EndpointsUpdate{ diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_lds.go b/internal/xds/xdsclient/xdsresource/unmarshal_lds.go index 95816d146c15..5d154a3c613d 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_lds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_lds.go @@ -56,6 +56,10 @@ func unmarshalListenerResource(r *anypb.Any, opts *xdsclient.DecodeOptions) (str return lis.GetName(), ListenerUpdate{}, err } lu.Raw = r + + if lis.GetName() == "" { + return "", ListenerUpdate{}, fmt.Errorf("empty resource name in listener resource") + } return lis.GetName(), *lu, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go index 331f83a9b720..2e28f8294974 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_lds_test.go @@ -212,12 +212,31 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr bool }{ { - name: "non-listener resource", + name: "non-listener_resource", resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL}, wantErr: true, }, { - name: "badly marshaled listener resource", + name: "listener_resource_with_empty_name", + resource: &anypb.Any{ + TypeUrl: version.V3ListenerURL, + Value: func() []byte { + lis := &v3listenerpb.Listener{ + ApiListener: &v3listenerpb.ApiListener{ + ApiListener: &anypb.Any{ + TypeUrl: version.V3HTTPConnManagerURL, + Value: []byte{1, 2, 3, 4}, + }, + }, + } + mLis, _ := proto.Marshal(lis) + return mLis + }(), + }, + wantErr: true, + }, + { + name: "badly_marshaled_listener_resource", resource: &anypb.Any{ TypeUrl: version.V3ListenerURL, Value: func() []byte { @@ -238,7 +257,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "wrong type in apiListener", + name: "wrong_type_in_apiListener", resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ Name: v3LDSTarget, ApiListener: &v3listenerpb.ApiListener{ @@ -249,7 +268,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "empty httpConnMgr in apiListener", + name: "empty_httpConnMgr_in_apiListener", resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ Name: v3LDSTarget, ApiListener: &v3listenerpb.ApiListener{ @@ -264,7 +283,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "scopedRoutes routeConfig in apiListener", + name: "scopedRoutes_routeConfig_in_apiListener", resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ Name: v3LDSTarget, ApiListener: &v3listenerpb.ApiListener{ @@ -277,7 +296,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "rds.ConfigSource in apiListener is Self", + name: "rds.ConfigSource_in_apiListener_is_Self", resource: v3ListenerWithCDSConfigSourceSelf, wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -289,7 +308,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "rds.ConfigSource in apiListener is not ADS or Self", + name: "rds.ConfigSource_in_apiListener_is_not_ADS_or_Self", resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ Name: v3LDSTarget, ApiListener: &v3listenerpb.ApiListener{ @@ -311,7 +330,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "v3 with no filters", + name: "v3_with_no_filters", resource: v3LisWithFilters(), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -324,7 +343,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 no terminal filter", + name: "v3_no_terminal_filter", resource: testutils.MarshalAny(t, &v3listenerpb.Listener{ Name: v3LDSTarget, ApiListener: &v3listenerpb.ApiListener{ @@ -348,7 +367,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "v3 with custom filter", + name: "v3_with_custom_filter", resource: v3LisWithFilters(customFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -368,7 +387,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with custom filter in old typed struct", + name: "v3_with_custom_filter_in_old_typed_struct", resource: v3LisWithFilters(oldTypedStructFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -388,7 +407,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with custom filter in new typed struct", + name: "v3_with_custom_filter_in_new_typed_struct", resource: v3LisWithFilters(newTypedStructFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -408,7 +427,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with optional custom filter", + name: "v3_with_optional_custom_filter", resource: v3LisWithFilters(customOptionalFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -428,13 +447,13 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with two filters with same name", + name: "v3_with_two_filters_with_same_name", resource: v3LisWithFilters(customFilter, customFilter), wantName: v3LDSTarget, wantErr: true, }, { - name: "v3 with two filters - same type different name", + name: "v3_with_two_filters_same_type_different_name", resource: v3LisWithFilters(customFilter, customFilter2), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -457,13 +476,13 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with server-only filter", + name: "v3_with_server_only_filter", resource: v3LisWithFilters(serverOnlyCustomFilter), wantName: v3LDSTarget, wantErr: true, }, { - name: "v3 with optional server-only filter", + name: "v3_with_optional_server_only_filter", resource: v3LisWithFilters(serverOnlyOptionalCustomFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -476,7 +495,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with client-only filter", + name: "v3_with_client_only_filter", resource: v3LisWithFilters(clientOnlyCustomFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -495,25 +514,25 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 with err filter", + name: "v3_with_err_filter", resource: v3LisWithFilters(errFilter), wantName: v3LDSTarget, wantErr: true, }, { - name: "v3 with optional err filter", + name: "v3_with_optional_err_filter", resource: v3LisWithFilters(errOptionalFilter), wantName: v3LDSTarget, wantErr: true, }, { - name: "v3 with unknown filter", + name: "v3_with_unknown_filter", resource: v3LisWithFilters(unknownFilter), wantName: v3LDSTarget, wantErr: true, }, { - name: "v3 with unknown filter (optional)", + name: "v3_with_unknown_filter_optional", resource: v3LisWithFilters(unknownOptionalFilter), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -526,7 +545,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 listener resource", + name: "v3_listener_resource", resource: v3LisWithFilters(), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -539,7 +558,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { }, }, { - name: "v3 listener resource wrapped", + name: "v3_listener_resource_wrapped", resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3LisWithFilters()}), wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ @@ -590,7 +609,7 @@ func (s) TestUnmarshalListener_ClientSide(t *testing.T) { wantErr: true, }, { - name: "v3 listener with inline route configuration", + name: "v3_listener_with_inline_route_configuration", resource: v3LisWithInlineRoute, wantName: v3LDSTarget, wantUpdate: ListenerUpdate{ diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_rds.go b/internal/xds/xdsclient/xdsresource/unmarshal_rds.go index d988b4e77f9a..7734bfb4965e 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_rds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_rds.go @@ -55,6 +55,10 @@ func unmarshalRouteConfigResource(r *anypb.Any, opts *xdsclient.DecodeOptions) ( return rc.GetName(), RouteConfigUpdate{}, err } u.Raw = r + + if rc.GetName() == "" { + return "", RouteConfigUpdate{}, fmt.Errorf("empty resource name in route config resource") + } return rc.GetName(), u, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go b/internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go index 8c04dbb2b8ce..e47fade0fda7 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_rds_test.go @@ -918,6 +918,15 @@ func (s) TestUnmarshalRouteConfig(t *testing.T) { }, wantErr: true, }, + { + name: "v3 routeConfig resource with empty name", + resource: testutils.MarshalAny(t, &v3routepb.RouteConfiguration{ + Name: "", + VirtualHosts: v3VirtualHost, + }), + wantName: "", + wantErr: true, + }, { name: "v3 routeConfig resource", resource: v3RouteConfig, From 5a40c4b8257515c4a59e978c7413a64936d94aae Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Mon, 16 Mar 2026 12:08:45 +0000 Subject: [PATCH 5/6] resolving comments --- .../xdsresource/filter_chain_test.go | 36 +++++++++++++++++-- .../xdsclient/xdsresource/unmarshal_cds.go | 7 ++-- .../xdsclient/xdsresource/unmarshal_eds.go | 7 ++-- .../xdsclient/xdsresource/unmarshal_lds.go | 7 ++-- .../xdsclient/xdsresource/unmarshal_rds.go | 7 ++-- 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/internal/xds/xdsclient/xdsresource/filter_chain_test.go b/internal/xds/xdsclient/xdsresource/filter_chain_test.go index 2bc3cee9c8da..cb6e3e690403 100644 --- a/internal/xds/xdsclient/xdsresource/filter_chain_test.go +++ b/internal/xds/xdsclient/xdsresource/filter_chain_test.go @@ -60,6 +60,7 @@ func (s) TestUnmarshalListener_ServerSide_DroppedFilterChains(t *testing.T) { { desc: "unsupported destination port field", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -73,6 +74,7 @@ func (s) TestUnmarshalListener_ServerSide_DroppedFilterChains(t *testing.T) { { desc: "unsupported server names field", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -86,6 +88,7 @@ func (s) TestUnmarshalListener_ServerSide_DroppedFilterChains(t *testing.T) { { desc: "unsupported transport protocol field", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -99,6 +102,7 @@ func (s) TestUnmarshalListener_ServerSide_DroppedFilterChains(t *testing.T) { { desc: "unsupported application protocol field", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -133,6 +137,7 @@ func (s) TestUnmarshalListener_ServerSide_FilterChains_FailureCases(t *testing.T { desc: "bad dest address prefix", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -146,6 +151,7 @@ func (s) TestUnmarshalListener_ServerSide_FilterChains_FailureCases(t *testing.T { desc: "bad dest prefix length", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -159,6 +165,7 @@ func (s) TestUnmarshalListener_ServerSide_FilterChains_FailureCases(t *testing.T { desc: "bad source address prefix", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -172,6 +179,7 @@ func (s) TestUnmarshalListener_ServerSide_FilterChains_FailureCases(t *testing.T { desc: "bad source prefix length", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -204,6 +212,7 @@ func (s) TestUnmarshalListener_ServerSide_OverlappingMatchingRules(t *testing.T) { desc: "matching destination prefixes with no other matchers", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -224,6 +233,7 @@ func (s) TestUnmarshalListener_ServerSide_OverlappingMatchingRules(t *testing.T) { desc: "matching source type", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -248,6 +258,7 @@ func (s) TestUnmarshalListener_ServerSide_OverlappingMatchingRules(t *testing.T) { desc: "matching source prefixes", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -268,6 +279,7 @@ func (s) TestUnmarshalListener_ServerSide_OverlappingMatchingRules(t *testing.T) { desc: "matching source ports", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -307,13 +319,17 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { enableSystemRootCertsFlag bool }{ { - desc: "no filter chains", - lis: &v3listenerpb.Listener{Address: localSocketAddress}, + desc: "no filter chains", + lis: &v3listenerpb.Listener{ + Name: "test-listener", + Address: localSocketAddress, + }, wantErr: "no supported filter chains and no default filter chain", }, { desc: "unexpected transport socket name", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -327,6 +343,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "unexpected transport socket URL", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -345,6 +362,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "badly marshaled transport socket", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -366,6 +384,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "missing CommonTlsContext", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -384,6 +403,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "require_sni-set-to-true-in-downstreamTlsContext", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -404,6 +424,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "unsupported-ocsp_staple_policy-in-downstreamTlsContext", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -424,6 +445,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "unsupported validation context in transport socket", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -450,6 +472,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "unsupported match_subject_alt_names field in transport socket", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -476,6 +499,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "no root certificate provider with require_client_cert", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -500,8 +524,9 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { wantErr: "security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set", }, { - desc: "no identity certificate provider", + desc: "no_identity_certificate_provider", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -523,6 +548,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { desc: "system root certificate field set on server", enableSystemRootCertsFlag: true, lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -554,6 +580,7 @@ func (s) TestUnmarshalListener_ServerSide_BadSecurityConfig(t *testing.T) { { desc: "system root certificate field set on server, env var disabled", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -853,6 +880,7 @@ func (s) TestUnmarshalListener_ServerSide_BadRouteUpdate(t *testing.T) { { name: "missing-route-specifier", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -888,6 +916,7 @@ func (s) TestUnmarshalListener_ServerSide_BadRouteUpdate(t *testing.T) { { name: "not-ads", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { @@ -933,6 +962,7 @@ func (s) TestUnmarshalListener_ServerSide_BadRouteUpdate(t *testing.T) { { name: "unsupported-route-specifier", lis: &v3listenerpb.Listener{ + Name: "test-listener", Address: localSocketAddress, FilterChains: []*v3listenerpb.FilterChain{ { diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_cds.go b/internal/xds/xdsclient/xdsresource/unmarshal_cds.go index 87c08e155146..182f612599af 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_cds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_cds.go @@ -65,15 +65,16 @@ func unmarshalClusterResource(r *anypb.Any, serverCfg *bootstrap.ServerConfig) ( if err := proto.Unmarshal(r.GetValue(), cluster); err != nil { return "", ClusterUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err) } + + if cluster.GetName() == "" { + return "", ClusterUpdate{}, fmt.Errorf("empty resource name in Cluster resource") + } cu, err := validateClusterAndConstructClusterUpdate(cluster, serverCfg) if err != nil { return cluster.GetName(), ClusterUpdate{}, err } cu.Raw = r - if cluster.GetName() == "" { - return "", ClusterUpdate{}, fmt.Errorf("empty resource name in Cluster resource") - } return cluster.GetName(), cu, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go index d65e9a675572..93bb3e42416a 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_eds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_eds.go @@ -74,15 +74,16 @@ func unmarshalEndpointsResource(r *anypb.Any) (string, EndpointsUpdate, error) { return "", EndpointsUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err) } + if cla.GetClusterName() == "" { + return "", EndpointsUpdate{}, fmt.Errorf("empty resource name in endpoints resource") + } + u, err := parseEDSRespProto(cla) if err != nil { return cla.GetClusterName(), EndpointsUpdate{}, err } u.Raw = r - if cla.GetClusterName() == "" { - return "", EndpointsUpdate{}, fmt.Errorf("empty resource name in endpoints resource") - } return cla.GetClusterName(), u, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_lds.go b/internal/xds/xdsclient/xdsresource/unmarshal_lds.go index 5d154a3c613d..1a2e495b865a 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_lds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_lds.go @@ -51,15 +51,16 @@ func unmarshalListenerResource(r *anypb.Any, opts *xdsclient.DecodeOptions) (str return "", ListenerUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err) } + if lis.GetName() == "" { + return "", ListenerUpdate{}, fmt.Errorf("empty resource name in listener resource") + } + lu, err := processListener(lis, opts) if err != nil { return lis.GetName(), ListenerUpdate{}, err } lu.Raw = r - if lis.GetName() == "" { - return "", ListenerUpdate{}, fmt.Errorf("empty resource name in listener resource") - } return lis.GetName(), *lu, nil } diff --git a/internal/xds/xdsclient/xdsresource/unmarshal_rds.go b/internal/xds/xdsclient/xdsresource/unmarshal_rds.go index 7734bfb4965e..09589d6bcaa0 100644 --- a/internal/xds/xdsclient/xdsresource/unmarshal_rds.go +++ b/internal/xds/xdsclient/xdsresource/unmarshal_rds.go @@ -50,15 +50,16 @@ func unmarshalRouteConfigResource(r *anypb.Any, opts *xdsclient.DecodeOptions) ( return "", RouteConfigUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err) } + if rc.GetName() == "" { + return "", RouteConfigUpdate{}, fmt.Errorf("empty resource name in route config resource") + } + u, err := generateRDSUpdateFromRouteConfiguration(rc, opts) if err != nil { return rc.GetName(), RouteConfigUpdate{}, err } u.Raw = r - if rc.GetName() == "" { - return "", RouteConfigUpdate{}, fmt.Errorf("empty resource name in route config resource") - } return rc.GetName(), u, nil } From 054d10a43a013f81e9f05fe73079eaf3bc41fd44 Mon Sep 17 00:00:00 2001 From: Pranjali-2501 Date: Mon, 16 Mar 2026 18:22:13 +0000 Subject: [PATCH 6/6] added logger.Error in decodeResponse --- internal/xds/clients/xdsclient/channel.go | 14 +++++++------- internal/xds/clients/xdsclient/channel_test.go | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/internal/xds/clients/xdsclient/channel.go b/internal/xds/clients/xdsclient/channel.go index 48154d7d3218..354c0496539d 100644 --- a/internal/xds/clients/xdsclient/channel.go +++ b/internal/xds/clients/xdsclient/channel.go @@ -214,12 +214,7 @@ func (xc *xdsChannel) onResponse(resp response, onDone func()) ([]string, error) return nil, xdsresource.NewErrorf(xdsresource.ErrorTypeResourceTypeUnsupported, "Resource type URL %q unknown in response from server", resp.typeURL) } - // Decode the resources and build the list of resource names to return. - opts := &DecodeOptions{ - Config: xc.clientConfig, - ServerConfig: xc.serverConfig, - } - updates, md, err := decodeResponse(opts, &rType, resp) + updates, md, err := xc.decodeResponse(&rType, resp) var names []string for name := range updates { names = append(names, name) @@ -243,12 +238,16 @@ func (xc *xdsChannel) onResponse(resp response, onDone func()) ([]string, error) // If there are any errors decoding the resources, the metadata will indicate // that the update was NACKed, and the returned error will contain information // about all errors encountered by this function. -func decodeResponse(opts *DecodeOptions, rType *ResourceType, resp response) (map[string]dataAndErrTuple, xdsresource.UpdateMetadata, error) { +func (xc *xdsChannel) decodeResponse(rType *ResourceType, resp response) (map[string]dataAndErrTuple, xdsresource.UpdateMetadata, error) { timestamp := time.Now() md := xdsresource.UpdateMetadata{ Version: resp.version, Timestamp: timestamp, } + opts := &DecodeOptions{ + Config: xc.clientConfig, + ServerConfig: xc.serverConfig, + } topLevelErrors := make([]error, 0) // Tracks deserialization errors, where we don't have a resource name. perResourceErrors := make(map[string]error) // Tracks resource validation errors, where we have a resource name. @@ -269,6 +268,7 @@ func decodeResponse(opts *DecodeOptions, rType *ResourceType, resp response) (ma // deserialization fails. name := "" if result == nil && err == nil { + xc.logger.Errorf("Decode() returned nil result and nil error for resource: %v", r) continue } if result != nil { diff --git a/internal/xds/clients/xdsclient/channel_test.go b/internal/xds/clients/xdsclient/channel_test.go index 19541e2f14db..b471a2a1a694 100644 --- a/internal/xds/clients/xdsclient/channel_test.go +++ b/internal/xds/clients/xdsclient/channel_test.go @@ -793,7 +793,8 @@ func (s) TestDecodeResponse_PanicRecoveryEnabled(t *testing.T) { resp := response{resources: []*anypb.Any{{Value: []byte("test")}}} wantErr := "recovered from panic during resource parsing" - if _, _, err := decodeResponse(&DecodeOptions{}, rType, resp); err == nil || !strings.Contains(err.Error(), wantErr) { + xc := &xdsChannel{} + if _, _, err := xc.decodeResponse(rType, resp); err == nil || !strings.Contains(err.Error(), wantErr) { t.Fatalf("decodeResponse() failed with err: %v, want %q", err, wantErr) } } @@ -809,11 +810,12 @@ func (s) TestDecodeResponse_PanicRecoveryDisabled(t *testing.T) { } resp := response{resources: []*anypb.Any{{Value: []byte("test")}}} wantErr := "simulate panic" + xc := &xdsChannel{} defer func() { if r := recover(); r == nil || !strings.Contains(fmt.Sprint(r), wantErr) { t.Fatalf("Expected panic in decodeResponse, got: %v, want: %q", r, wantErr) } }() - decodeResponse(&DecodeOptions{}, rType, resp) + xc.decodeResponse(rType, resp) }