Repository: grpc/grpc-go
File: internal/xds/xdsclient/xdsresource/unmarshal_cds.go (Go)

Code before:
	v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	v3aggregateclusterpb "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/aggregate/v3"
	v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"

	"google.golang.org/grpc/internal/envconfig"
	"google.golang.org/grpc/internal/pretty"
	iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
	"google.golang.org/grpc/internal/xds/bootstrap"
	"google.golang.org/grpc/internal/xds/matcher"
	"google.golang.org/grpc/internal/xds/xdsclient/xdslbregistry"
	"google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
	"google.golang.org/protobuf/types/known/structpb"
)

// ValidateClusterAndConstructClusterUpdateForTesting exports the
// validateClusterAndConstructClusterUpdate function for testing purposes.
var ValidateClusterAndConstructClusterUpdateForTesting = validateClusterAndConstructClusterUpdate

// TransportSocket proto message has a `name` field which is expected to be set
// to this value by the management server.
const transportSocketName = "envoy.transport_sockets.tls"

func unmarshalClusterResource(r *anypb.Any, serverCfg *bootstrap.ServerConfig) (name string, update ClusterUpdate, err error) {
	defer func() {
		if envconfig.XDSRecoverPanic {
			if r := recover(); r != nil {
				err = fmt.Errorf("panic during CDS resource unmarshaling: %v", r)
			}
		}
	}()
	r, err = UnwrapResource(r)
	if err != nil {
		return "", ClusterUpdate{}, fmt.Errorf("failed to unwrap resource: %v", err)
	}

	if !IsClusterResource(r.GetTypeUrl()) {
		return "", ClusterUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl())
	}

	cluster := &v3clusterpb.Cluster{}
	if err := proto.Unmarshal(r.GetValue(), cluster); err != nil {
		return "", ClusterUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err)
	}
	cu, err := validateClusterAndConstructClusterUpdate(cluster, serverCfg)
	if err != nil {
		return cluster.GetName(), ClusterUpdate{}, err
	}
	cu.Raw = r

Review comment (bug):
Can you add to the description example of where the panics can occur? From the unmarshal functions, it looks like all the edge cases are handled by returning appropriate errors.

Code after:
	v3clusterpb "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	v3aggregateclusterpb "github.com/envoyproxy/go-control-plane/envoy/extensions/clusters/aggregate/v3"
	v3tlspb "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/tls/v3"

	"google.golang.org/grpc/internal/envconfig"
	"google.golang.org/grpc/internal/pretty"
	iserviceconfig "google.golang.org/grpc/internal/serviceconfig"
	"google.golang.org/grpc/internal/xds/bootstrap"
	"google.golang.org/grpc/internal/xds/matcher"
	"google.golang.org/grpc/internal/xds/xdsclient/xdslbregistry"
	"google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
	"google.golang.org/protobuf/types/known/structpb"
)

// ValidateClusterAndConstructClusterUpdateForTesting exports the
// validateClusterAndConstructClusterUpdate function for testing purposes.
var ValidateClusterAndConstructClusterUpdateForTesting = validateClusterAndConstructClusterUpdate

// TransportSocket proto message has a `name` field which is expected to be set
// to this value by the management server.
const transportSocketName = "envoy.transport_sockets.tls"

func unmarshalClusterResource(r *anypb.Any, serverCfg *bootstrap.ServerConfig) (string, ClusterUpdate, error) {
	r, err := UnwrapResource(r)
	if err != nil {
		return "", ClusterUpdate{}, fmt.Errorf("failed to unwrap resource: %v", err)
	}

	if !IsClusterResource(r.GetTypeUrl()) {
		return "", ClusterUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl())
	}

	cluster := &v3clusterpb.Cluster{}
	if err := proto.Unmarshal(r.GetValue(), cluster); err != nil {
		return "", ClusterUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err)
	}
	cu, err := validateClusterAndConstructClusterUpdate(cluster, serverCfg)
	if err != nil {
		return cluster.GetName(), ClusterUpdate{}, err
	}
	cu.Raw = r

	return cluster.GetName(), cu, nil
}

const (
	defaultRingHashMinSize = 1024
	defaultRingHashMaxSize = 8 * 1024 * 1024 // 8M