dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/client/resource/unmarshal_eds.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. 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 /* 19 * 20 * Copyright 2021 gRPC authors. 21 * 22 */ 23 24 package resource 25 26 import ( 27 "fmt" 28 "net" 29 "strconv" 30 ) 31 32 import ( 33 dubbogoLogger "github.com/dubbogo/gost/log/logger" 34 35 v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" 36 v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" 37 v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3" 38 39 "github.com/golang/protobuf/proto" 40 41 "google.golang.org/protobuf/types/known/anypb" 42 ) 43 44 import ( 45 "dubbo.apache.org/dubbo-go/v3/xds/utils/pretty" 46 ) 47 48 // UnmarshalEndpoints processes resources received in an EDS response, 49 // validates them, and transforms them into a native struct which contains only 50 // fields we are interested in. 51 func UnmarshalEndpoints(opts *UnmarshalOptions) (map[string]EndpointsUpdateErrTuple, UpdateMetadata, error) { 52 update := make(map[string]EndpointsUpdateErrTuple) 53 md, err := processAllResources(opts, update) 54 return update, md, err 55 } 56 57 func unmarshalEndpointsResource(r *anypb.Any, logger dubbogoLogger.Logger) (string, EndpointsUpdate, error) { 58 if !IsEndpointsResource(r.GetTypeUrl()) { 59 return "", EndpointsUpdate{}, fmt.Errorf("unexpected resource type: %q ", r.GetTypeUrl()) 60 } 61 62 cla := &v3endpointpb.ClusterLoadAssignment{} 63 if err := proto.Unmarshal(r.GetValue(), cla); err != nil { 64 return "", EndpointsUpdate{}, fmt.Errorf("failed to unmarshal resource: %v", err) 65 } 66 dubbogoLogger.Debugf("Resource with name: %v, type: %T, contains: %v", cla.GetClusterName(), cla, pretty.ToJSON(cla)) 67 68 u, err := parseEDSRespProto(cla) 69 if err != nil { 70 return cla.GetClusterName(), EndpointsUpdate{}, err 71 } 72 u.Raw = r 73 return cla.GetClusterName(), u, nil 74 } 75 76 func parseAddress(socketAddress *v3corepb.SocketAddress) string { 77 return net.JoinHostPort(socketAddress.GetAddress(), strconv.Itoa(int(socketAddress.GetPortValue()))) 78 } 79 80 func parseDropPolicy(dropPolicy *v3endpointpb.ClusterLoadAssignment_Policy_DropOverload) OverloadDropConfig { 81 percentage := dropPolicy.GetDropPercentage() 82 var ( 83 numerator = percentage.GetNumerator() 84 denominator uint32 85 ) 86 switch percentage.GetDenominator() { 87 case v3typepb.FractionalPercent_HUNDRED: 88 denominator = 100 89 case v3typepb.FractionalPercent_TEN_THOUSAND: 90 denominator = 10000 91 case v3typepb.FractionalPercent_MILLION: 92 denominator = 1000000 93 } 94 return OverloadDropConfig{ 95 Category: dropPolicy.GetCategory(), 96 Numerator: numerator, 97 Denominator: denominator, 98 } 99 } 100 101 func parseEndpoints(lbEndpoints []*v3endpointpb.LbEndpoint) []Endpoint { 102 endpoints := make([]Endpoint, 0, len(lbEndpoints)) 103 for _, lbEndpoint := range lbEndpoints { 104 endpoints = append(endpoints, Endpoint{ 105 HealthStatus: EndpointHealthStatus(lbEndpoint.GetHealthStatus()), 106 Address: parseAddress(lbEndpoint.GetEndpoint().GetAddress().GetSocketAddress()), 107 Weight: lbEndpoint.GetLoadBalancingWeight().GetValue(), 108 }) 109 } 110 return endpoints 111 } 112 113 func parseEDSRespProto(m *v3endpointpb.ClusterLoadAssignment) (EndpointsUpdate, error) { 114 ret := EndpointsUpdate{} 115 for _, dropPolicy := range m.GetPolicy().GetDropOverloads() { 116 ret.Drops = append(ret.Drops, parseDropPolicy(dropPolicy)) 117 } 118 priorities := make(map[uint32]struct{}) 119 for _, locality := range m.Endpoints { 120 l := locality.GetLocality() 121 if l == nil { 122 return EndpointsUpdate{}, fmt.Errorf("EDS response contains a locality without ID, locality: %+v", locality) 123 } 124 lid := LocalityID{ 125 Region: l.Region, 126 Zone: l.Zone, 127 SubZone: l.SubZone, 128 } 129 priority := locality.GetPriority() 130 priorities[priority] = struct{}{} 131 ret.Localities = append(ret.Localities, Locality{ 132 ID: lid, 133 Endpoints: parseEndpoints(locality.GetLbEndpoints()), 134 Weight: locality.GetLoadBalancingWeight().GetValue(), 135 Priority: priority, 136 }) 137 } 138 for i := 0; i < len(priorities); i++ { 139 if _, ok := priorities[uint32(i)]; !ok { 140 return EndpointsUpdate{}, fmt.Errorf("priority %v missing (with different priorities %v received)", i, priorities) 141 } 142 } 143 return ret, nil 144 }