dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/client/controller/version/v2/client.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 2019 gRPC authors. 21 * 22 */ 23 24 // Package v2 provides xDS v2 transport protocol specific functionality. 25 package v2 26 27 import ( 28 "context" 29 "fmt" 30 ) 31 32 import ( 33 dubbogoLogger "github.com/dubbogo/gost/log/logger" 34 35 v2xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2" 36 v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" 37 v2adsgrpc "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v2" 38 39 "github.com/golang/protobuf/proto" 40 _struct "github.com/golang/protobuf/ptypes/struct" 41 42 statuspb "google.golang.org/genproto/googleapis/rpc/status" 43 44 "google.golang.org/grpc" 45 "google.golang.org/grpc/codes" 46 47 "google.golang.org/protobuf/types/known/anypb" 48 ) 49 50 import ( 51 controllerversion "dubbo.apache.org/dubbo-go/v3/xds/client/controller/version" 52 "dubbo.apache.org/dubbo-go/v3/xds/client/resource" 53 resourceversion "dubbo.apache.org/dubbo-go/v3/xds/client/resource/version" 54 "dubbo.apache.org/dubbo-go/v3/xds/utils/pretty" 55 ) 56 57 func init() { 58 controllerversion.RegisterAPIClientBuilder(resourceversion.TransportV2, newClient) 59 } 60 61 var ( 62 resourceTypeToURL = map[resource.ResourceType]string{ 63 resource.ListenerResource: resourceversion.V2ListenerURL, 64 resource.RouteConfigResource: resourceversion.V2RouteConfigURL, 65 resource.ClusterResource: resourceversion.V2ClusterURL, 66 resource.EndpointsResource: resourceversion.V2EndpointsURL, 67 } 68 ) 69 70 func newClient(opts controllerversion.BuildOptions) (controllerversion.MetadataWrappedVersionClient, error) { 71 nodeProto, ok := opts.NodeProto.(*v2corepb.Node) 72 if !ok { 73 return nil, fmt.Errorf("xds: unsupported Node proto type: %T, want %T", opts.NodeProto, (*v2corepb.Node)(nil)) 74 } 75 v2c := &client{nodeProto: nodeProto, logger: dubbogoLogger.GetLogger()} 76 return v2c, nil 77 } 78 79 type adsStream v2adsgrpc.AggregatedDiscoveryService_StreamAggregatedResourcesClient 80 81 // client performs the actual xDS RPCs using the xDS v2 API. It creates a 82 // single ADS stream on which the different types of xDS requests and responses 83 // are multiplexed. 84 type client struct { 85 nodeProto *v2corepb.Node 86 logger dubbogoLogger.Logger 87 } 88 89 // SetMetadata update client metadata 90 func (v2c *client) SetMetadata(p *_struct.Struct) { 91 v2c.nodeProto.Metadata = p 92 } 93 94 func (v2c *client) NewStream(ctx context.Context, cc *grpc.ClientConn) (grpc.ClientStream, error) { 95 return v2adsgrpc.NewAggregatedDiscoveryServiceClient(cc).StreamAggregatedResources(ctx, grpc.WaitForReady(true)) 96 } 97 98 // SendRequest sends out a DiscoveryRequest for the given resourceNames, of type 99 // rType, on the provided stream. 100 // 101 // version is the ack version to be sent with the request 102 // - If this is the new request (not an ack/nack), version will be empty. 103 // - If this is an ack, version will be the version from the response. 104 // - If this is a nack, version will be the previous acked version (from 105 // versionMap). If there was no ack before, it will be empty. 106 func (v2c *client) SendRequest(s grpc.ClientStream, resourceNames []string, rType resource.ResourceType, version, nonce, errMsg string) error { 107 stream, ok := s.(adsStream) 108 if !ok { 109 return fmt.Errorf("xds: Attempt to send request on unsupported stream type: %T", s) 110 } 111 req := &v2xdspb.DiscoveryRequest{ 112 Node: v2c.nodeProto, 113 TypeUrl: resourceTypeToURL[rType], 114 ResourceNames: resourceNames, 115 VersionInfo: version, 116 ResponseNonce: nonce, 117 } 118 if errMsg != "" { 119 req.ErrorDetail = &statuspb.Status{ 120 Code: int32(codes.InvalidArgument), Message: errMsg, 121 } 122 } 123 if err := stream.Send(req); err != nil { 124 return fmt.Errorf("xds: stream.Send(%+v) failed: %v", req, err) 125 } 126 v2c.logger.Debugf("ADS request sent: %v", pretty.ToJSON(req)) 127 return nil 128 } 129 130 // RecvResponse blocks on the receipt of one response message on the provided 131 // stream. 132 func (v2c *client) RecvResponse(s grpc.ClientStream) (proto.Message, error) { 133 stream, ok := s.(adsStream) 134 if !ok { 135 return nil, fmt.Errorf("xds: Attempt to receive response on unsupported stream type: %T", s) 136 } 137 138 resp, err := stream.Recv() 139 if err != nil { 140 return nil, fmt.Errorf("xds: stream.Recv() failed: %v", err) 141 } 142 v2c.logger.Infof("ADS response received, type: %v", resp.GetTypeUrl()) 143 v2c.logger.Debugf("ADS response received: %v", pretty.ToJSON(resp)) 144 return resp, nil 145 } 146 147 func (v2c *client) ParseResponse(r proto.Message) (resource.ResourceType, []*anypb.Any, string, string, error) { 148 rType := resource.UnknownResource 149 resp, ok := r.(*v2xdspb.DiscoveryResponse) 150 if !ok { 151 return rType, nil, "", "", fmt.Errorf("xds: unsupported message type: %T", resp) 152 } 153 154 // Note that the xDS transport protocol is versioned independently of 155 // the resource types, and it is supported to transfer older versions 156 // of resource types using new versions of the transport protocol, or 157 // vice-versa. Hence we need to handle v3 type_urls as well here. 158 var err error 159 url := resp.GetTypeUrl() 160 switch { 161 case resource.IsListenerResource(url): 162 rType = resource.ListenerResource 163 case resource.IsRouteConfigResource(url): 164 rType = resource.RouteConfigResource 165 case resource.IsClusterResource(url): 166 rType = resource.ClusterResource 167 case resource.IsEndpointsResource(url): 168 rType = resource.EndpointsResource 169 default: 170 return rType, nil, "", "", controllerversion.ErrResourceTypeUnsupported{ 171 ErrStr: fmt.Sprintf("Resource type %v unknown in response from server", resp.GetTypeUrl()), 172 } 173 } 174 return rType, resp.GetResources(), resp.GetVersionInfo(), resp.GetNonce(), err 175 }