| /* |
| * |
| * Copyright 2020 gRPC authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package testutils |
| |
| import ( |
| "fmt" |
| "net" |
| "strconv" |
| |
| v2xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2" |
| v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" |
| v2endpointpb "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint" |
| v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" |
| v2typepb "github.com/envoyproxy/go-control-plane/envoy/type" |
| wrapperspb "github.com/golang/protobuf/ptypes/wrappers" |
| "google.golang.org/grpc/xds/internal" |
| ) |
| |
| // EmptyNodeProtoV2 is a v2 Node proto with no fields set. |
| var EmptyNodeProtoV2 = &v2corepb.Node{} |
| |
| // EmptyNodeProtoV3 is a v3 Node proto with no fields set. |
| var EmptyNodeProtoV3 = &v3corepb.Node{} |
| |
| // LocalityIDToProto converts a LocalityID to its proto representation. |
| func LocalityIDToProto(l internal.LocalityID) *v2corepb.Locality { |
| return &v2corepb.Locality{ |
| Region: l.Region, |
| Zone: l.Zone, |
| SubZone: l.SubZone, |
| } |
| } |
| |
| // The helper structs/functions related to EDS protos are used in EDS balancer |
| // tests now, to generate test inputs. Eventually, EDS balancer tests should |
| // generate EndpointsUpdate directly, instead of generating and parsing the |
| // proto message. |
| // TODO: Once EDS balancer tests don't use these, these can be moved to v2 client code. |
| |
| // ClusterLoadAssignmentBuilder builds a ClusterLoadAssignment, aka EDS |
| // response. |
| type ClusterLoadAssignmentBuilder struct { |
| v *v2xdspb.ClusterLoadAssignment |
| } |
| |
| // NewClusterLoadAssignmentBuilder creates a ClusterLoadAssignmentBuilder. |
| func NewClusterLoadAssignmentBuilder(clusterName string, dropPercents []uint32) *ClusterLoadAssignmentBuilder { |
| var drops []*v2xdspb.ClusterLoadAssignment_Policy_DropOverload |
| for i, d := range dropPercents { |
| drops = append(drops, &v2xdspb.ClusterLoadAssignment_Policy_DropOverload{ |
| Category: fmt.Sprintf("test-drop-%d", i), |
| DropPercentage: &v2typepb.FractionalPercent{ |
| Numerator: d, |
| Denominator: v2typepb.FractionalPercent_HUNDRED, |
| }, |
| }) |
| } |
| |
| return &ClusterLoadAssignmentBuilder{ |
| v: &v2xdspb.ClusterLoadAssignment{ |
| ClusterName: clusterName, |
| Policy: &v2xdspb.ClusterLoadAssignment_Policy{ |
| DropOverloads: drops, |
| }, |
| }, |
| } |
| } |
| |
| // AddLocalityOptions contains options when adding locality to the builder. |
| type AddLocalityOptions struct { |
| Health []v2corepb.HealthStatus |
| Weight []uint32 |
| } |
| |
| // AddLocality adds a locality to the builder. |
| func (clab *ClusterLoadAssignmentBuilder) AddLocality(subzone string, weight uint32, priority uint32, addrsWithPort []string, opts *AddLocalityOptions) { |
| var lbEndPoints []*v2endpointpb.LbEndpoint |
| for i, a := range addrsWithPort { |
| host, portStr, err := net.SplitHostPort(a) |
| if err != nil { |
| panic("failed to split " + a) |
| } |
| port, err := strconv.Atoi(portStr) |
| if err != nil { |
| panic("failed to atoi " + portStr) |
| } |
| |
| lbe := &v2endpointpb.LbEndpoint{ |
| HostIdentifier: &v2endpointpb.LbEndpoint_Endpoint{ |
| Endpoint: &v2endpointpb.Endpoint{ |
| Address: &v2corepb.Address{ |
| Address: &v2corepb.Address_SocketAddress{ |
| SocketAddress: &v2corepb.SocketAddress{ |
| Protocol: v2corepb.SocketAddress_TCP, |
| Address: host, |
| PortSpecifier: &v2corepb.SocketAddress_PortValue{ |
| PortValue: uint32(port)}}}}}}, |
| } |
| if opts != nil { |
| if i < len(opts.Health) { |
| lbe.HealthStatus = opts.Health[i] |
| } |
| if i < len(opts.Weight) { |
| lbe.LoadBalancingWeight = &wrapperspb.UInt32Value{Value: opts.Weight[i]} |
| } |
| } |
| lbEndPoints = append(lbEndPoints, lbe) |
| } |
| |
| var localityID *v2corepb.Locality |
| if subzone != "" { |
| localityID = &v2corepb.Locality{ |
| Region: "", |
| Zone: "", |
| SubZone: subzone, |
| } |
| } |
| |
| clab.v.Endpoints = append(clab.v.Endpoints, &v2endpointpb.LocalityLbEndpoints{ |
| Locality: localityID, |
| LbEndpoints: lbEndPoints, |
| LoadBalancingWeight: &wrapperspb.UInt32Value{Value: weight}, |
| Priority: priority, |
| }) |
| } |
| |
| // Build builds ClusterLoadAssignment. |
| func (clab *ClusterLoadAssignmentBuilder) Build() *v2xdspb.ClusterLoadAssignment { |
| return clab.v |
| } |