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 }