github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/xdsresource/unmarshal_eds.go (about)

     1  /*
     2   *
     3   * Copyright 2021 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package xdsresource
    19  
    20  import (
    21  	"fmt"
    22  	"net"
    23  	"strconv"
    24  
    25  	"github.com/golang/protobuf/proto"
    26  	v3corepb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/core/v3"
    27  	v3endpointpb "github.com/hxx258456/ccgo/go-control-plane/envoy/config/endpoint/v3"
    28  	v3typepb "github.com/hxx258456/ccgo/go-control-plane/envoy/type/v3"
    29  	"github.com/hxx258456/ccgo/grpc/internal/grpclog"
    30  	"github.com/hxx258456/ccgo/grpc/internal/pretty"
    31  	"github.com/hxx258456/ccgo/grpc/xds/internal"
    32  	"google.golang.org/protobuf/types/known/anypb"
    33  )
    34  
    35  // UnmarshalEndpoints processes resources received in an EDS response,
    36  // validates them, and transforms them into a native struct which contains only
    37  // fields we are interested in.
    38  func UnmarshalEndpoints(opts *UnmarshalOptions) (map[string]EndpointsUpdateErrTuple, UpdateMetadata, error) {
    39  	update := make(map[string]EndpointsUpdateErrTuple)
    40  	md, err := processAllResources(opts, update)
    41  	return update, md, err
    42  }
    43  
    44  func unmarshalEndpointsResource(r *anypb.Any, logger *grpclog.PrefixLogger) (string, EndpointsUpdate, error) {
    45  	if !IsEndpointsResource(r.GetTypeUrl()) {
    46  		return "", EndpointsUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl())
    47  	}
    48  
    49  	cla := &v3endpointpb.ClusterLoadAssignment{}
    50  	if err := proto.Unmarshal(r.GetValue(), cla); err != nil {
    51  		return "", EndpointsUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err)
    52  	}
    53  	logger.Infof("Resource with name: %v, type: %T, contains: %v", cla.GetClusterName(), cla, pretty.ToJSON(cla))
    54  
    55  	u, err := parseEDSRespProto(cla)
    56  	if err != nil {
    57  		return cla.GetClusterName(), EndpointsUpdate{}, err
    58  	}
    59  	u.Raw = r
    60  	return cla.GetClusterName(), u, nil
    61  }
    62  
    63  func parseAddress(socketAddress *v3corepb.SocketAddress) string {
    64  	return net.JoinHostPort(socketAddress.GetAddress(), strconv.Itoa(int(socketAddress.GetPortValue())))
    65  }
    66  
    67  func parseDropPolicy(dropPolicy *v3endpointpb.ClusterLoadAssignment_Policy_DropOverload) OverloadDropConfig {
    68  	percentage := dropPolicy.GetDropPercentage()
    69  	var (
    70  		numerator   = percentage.GetNumerator()
    71  		denominator uint32
    72  	)
    73  	switch percentage.GetDenominator() {
    74  	case v3typepb.FractionalPercent_HUNDRED:
    75  		denominator = 100
    76  	case v3typepb.FractionalPercent_TEN_THOUSAND:
    77  		denominator = 10000
    78  	case v3typepb.FractionalPercent_MILLION:
    79  		denominator = 1000000
    80  	}
    81  	return OverloadDropConfig{
    82  		Category:    dropPolicy.GetCategory(),
    83  		Numerator:   numerator,
    84  		Denominator: denominator,
    85  	}
    86  }
    87  
    88  func parseEndpoints(lbEndpoints []*v3endpointpb.LbEndpoint) []Endpoint {
    89  	endpoints := make([]Endpoint, 0, len(lbEndpoints))
    90  	for _, lbEndpoint := range lbEndpoints {
    91  		endpoints = append(endpoints, Endpoint{
    92  			HealthStatus: EndpointHealthStatus(lbEndpoint.GetHealthStatus()),
    93  			Address:      parseAddress(lbEndpoint.GetEndpoint().GetAddress().GetSocketAddress()),
    94  			Weight:       lbEndpoint.GetLoadBalancingWeight().GetValue(),
    95  		})
    96  	}
    97  	return endpoints
    98  }
    99  
   100  func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate, error) {
   101  	ret := EndpointsUpdate{}
   102  	for _, dropPolicy := range m.GetPolicy().GetDropOverloads() {
   103  		ret.Drops = append(ret.Drops, parseDropPolicy(dropPolicy))
   104  	}
   105  	priorities := make(map[uint32]struct{})
   106  	for _, locality := range m.Endpoints {
   107  		l := locality.GetLocality()
   108  		if l == nil {
   109  			return EndpointsUpdate{}, fmt.Errorf("EDS response contains a locality without ID, locality: %+v", locality)
   110  		}
   111  		lid := internal.LocalityID{
   112  			Region:  l.Region,
   113  			Zone:    l.Zone,
   114  			SubZone: l.SubZone,
   115  		}
   116  		priority := locality.GetPriority()
   117  		priorities[priority] = struct{}{}
   118  		ret.Localities = append(ret.Localities, Locality{
   119  			ID:        lid,
   120  			Endpoints: parseEndpoints(locality.GetLbEndpoints()),
   121  			Weight:    locality.GetLoadBalancingWeight().GetValue(),
   122  			Priority:  priority,
   123  		})
   124  	}
   125  	for i := 0; i < len(priorities); i++ {
   126  		if _, ok := priorities[uint32(i)]; !ok {
   127  			return EndpointsUpdate{}, fmt.Errorf("priority %v missing (with different priorities %v received)", i, priorities)
   128  		}
   129  	}
   130  	return ret, nil
   131  }