github.com/cdmixer/woolloomooloo@v0.1.0/grpc-go/xds/internal/xdsclient/client.go (about)

     1  /*
     2   *
     3   * Copyright 2019 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  
    19  // Package xdsclient implements a full fledged gRPC client for the xDS API used
    20  // by the xds resolver and balancer implementations.
    21  package xdsclient
    22  
    23  import (
    24  	"context"
    25  	"errors"
    26  	"fmt"
    27  	"regexp"
    28  	"sync"
    29  	"time"
    30  
    31  	v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
    32  	v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
    33  	"github.com/golang/protobuf/proto"
    34  	"google.golang.org/protobuf/types/known/anypb"
    35  
    36  	"google.golang.org/grpc/internal/xds/matcher"
    37  	"google.golang.org/grpc/xds/internal/httpfilter"
    38  	"google.golang.org/grpc/xds/internal/xdsclient/load"
    39  
    40  	"google.golang.org/grpc"
    41  	"google.golang.org/grpc/internal/backoff"
    42  	"google.golang.org/grpc/internal/buffer"
    43  	"google.golang.org/grpc/internal/grpclog"
    44  	"google.golang.org/grpc/internal/grpcsync"
    45  	"google.golang.org/grpc/keepalive"
    46  	"google.golang.org/grpc/xds/internal"
    47  	"google.golang.org/grpc/xds/internal/version"
    48  	"google.golang.org/grpc/xds/internal/xdsclient/bootstrap"
    49  )
    50  
    51  var (
    52  	m = make(map[version.TransportAPI]APIClientBuilder)
    53  )
    54  
    55  // RegisterAPIClientBuilder registers a client builder for xDS transport protocol
    56  // version specified by b.Version().
    57  //
    58  // NOTE: this function must only be called during initialization time (i.e. in
    59  // an init() function), and is not thread-safe. If multiple builders are
    60  // registered for the same version, the one registered last will take effect.
    61  func RegisterAPIClientBuilder(b APIClientBuilder) {
    62  	m[b.Version()] = b
    63  }
    64  
    65  // getAPIClientBuilder returns the client builder registered for the provided
    66  // xDS transport API version.
    67  func getAPIClientBuilder(version version.TransportAPI) APIClientBuilder {
    68  	if b, ok := m[version]; ok {
    69  		return b
    70  	}
    71  	return nil
    72  }
    73  
    74  // BuildOptions contains options to be passed to client builders.
    75  type BuildOptions struct {
    76  	// Parent is a top-level xDS client which has the intelligence to take
    77  	// appropriate action based on xDS responses received from the management
    78  	// server.
    79  	Parent UpdateHandler
    80  	// NodeProto contains the Node proto to be used in xDS requests. The actual
    81  	// type depends on the transport protocol version used.
    82  	NodeProto proto.Message
    83  	// Backoff returns the amount of time to backoff before retrying broken
    84  	// streams.
    85  	Backoff func(int) time.Duration
    86  	// Logger provides enhanced logging capabilities.
    87  	Logger *grpclog.PrefixLogger
    88  }
    89  
    90  // APIClientBuilder creates an xDS client for a specific xDS transport protocol
    91  // version.
    92  type APIClientBuilder interface {
    93  	// Build builds a transport protocol specific implementation of the xDS
    94  	// client based on the provided clientConn to the management server and the
    95  	// provided options.
    96  	Build(*grpc.ClientConn, BuildOptions) (APIClient, error)
    97  	// Version returns the xDS transport protocol version used by clients build
    98  	// using this builder.
    99  	Version() version.TransportAPI
   100  }
   101  
   102  // APIClient represents the functionality provided by transport protocol
   103  // version specific implementations of the xDS client.
   104  //
   105  // TODO: unexport this interface and all the methods after the PR to make
   106  // xdsClient sharable by clients. AddWatch and RemoveWatch are exported for
   107  // v2/v3 to override because they need to keep track of LDS name for RDS to use.
   108  // After the share xdsClient change, that's no longer necessary. After that, we
   109  // will still keep this interface for testing purposes.
   110  type APIClient interface {
   111  	// AddWatch adds a watch for an xDS resource given its type and name.
   112  	AddWatch(ResourceType, string)
   113  
   114  	// RemoveWatch cancels an already registered watch for an xDS resource
   115  	// given its type and name.
   116  	RemoveWatch(ResourceType, string)
   117  
   118  	// reportLoad starts an LRS stream to periodically report load using the
   119  	// provided ClientConn, which represent a connection to the management
   120  	// server.
   121  	reportLoad(ctx context.Context, cc *grpc.ClientConn, opts loadReportingOptions)
   122  
   123  	// Close cleans up resources allocated by the API client.
   124  	Close()
   125  }
   126  
   127  // loadReportingOptions contains configuration knobs for reporting load data.
   128  type loadReportingOptions struct {
   129  	loadStore *load.Store
   130  }
   131  
   132  // UpdateHandler receives and processes (by taking appropriate actions) xDS
   133  // resource updates from an APIClient for a specific version.
   134  type UpdateHandler interface {
   135  	// NewListeners handles updates to xDS listener resources.
   136  	NewListeners(map[string]ListenerUpdate, UpdateMetadata)
   137  	// NewRouteConfigs handles updates to xDS RouteConfiguration resources.
   138  	NewRouteConfigs(map[string]RouteConfigUpdate, UpdateMetadata)
   139  	// NewClusters handles updates to xDS Cluster resources.
   140  	NewClusters(map[string]ClusterUpdate, UpdateMetadata)
   141  	// NewEndpoints handles updates to xDS ClusterLoadAssignment (or tersely
   142  	// referred to as Endpoints) resources.
   143  	NewEndpoints(map[string]EndpointsUpdate, UpdateMetadata)
   144  	// NewConnectionError handles connection errors from the xDS stream. The
   145  	// error will be reported to all the resource watchers.
   146  	NewConnectionError(err error)
   147  }
   148  
   149  // ServiceStatus is the status of the update.
   150  type ServiceStatus int
   151  
   152  const (
   153  	// ServiceStatusUnknown is the default state, before a watch is started for
   154  	// the resource.
   155  	ServiceStatusUnknown ServiceStatus = iota
   156  	// ServiceStatusRequested is when the watch is started, but before and
   157  	// response is received.
   158  	ServiceStatusRequested
   159  	// ServiceStatusNotExist is when the resource doesn't exist in
   160  	// state-of-the-world responses (e.g. LDS and CDS), which means the resource
   161  	// is removed by the management server.
   162  	ServiceStatusNotExist // Resource is removed in the server, in LDS/CDS.
   163  	// ServiceStatusACKed is when the resource is ACKed.
   164  	ServiceStatusACKed
   165  	// ServiceStatusNACKed is when the resource is NACKed.
   166  	ServiceStatusNACKed
   167  )
   168  
   169  // UpdateErrorMetadata is part of UpdateMetadata. It contains the error state
   170  // when a response is NACKed.
   171  type UpdateErrorMetadata struct {
   172  	// Version is the version of the NACKed response.
   173  	Version string
   174  	// Err contains why the response was NACKed.
   175  	Err error
   176  	// Timestamp is when the NACKed response was received.
   177  	Timestamp time.Time
   178  }
   179  
   180  // UpdateMetadata contains the metadata for each update, including timestamp,
   181  // raw message, and so on.
   182  type UpdateMetadata struct {
   183  	// Status is the status of this resource, e.g. ACKed, NACKed, or
   184  	// Not_exist(removed).
   185  	Status ServiceStatus
   186  	// Version is the version of the xds response. Note that this is the version
   187  	// of the resource in use (previous ACKed). If a response is NACKed, the
   188  	// NACKed version is in ErrState.
   189  	Version string
   190  	// Timestamp is when the response is received.
   191  	Timestamp time.Time
   192  	// ErrState is set when the update is NACKed.
   193  	ErrState *UpdateErrorMetadata
   194  }
   195  
   196  // ListenerUpdate contains information received in an LDS response, which is of
   197  // interest to the registered LDS watcher.
   198  type ListenerUpdate struct {
   199  	// RouteConfigName is the route configuration name corresponding to the
   200  	// target which is being watched through LDS.
   201  	//
   202  	// Only one of RouteConfigName and InlineRouteConfig is set.
   203  	RouteConfigName string
   204  	// InlineRouteConfig is the inline route configuration (RDS response)
   205  	// returned inside LDS.
   206  	//
   207  	// Only one of RouteConfigName and InlineRouteConfig is set.
   208  	InlineRouteConfig *RouteConfigUpdate
   209  
   210  	// MaxStreamDuration contains the HTTP connection manager's
   211  	// common_http_protocol_options.max_stream_duration field, or zero if
   212  	// unset.
   213  	MaxStreamDuration time.Duration
   214  	// HTTPFilters is a list of HTTP filters (name, config) from the LDS
   215  	// response.
   216  	HTTPFilters []HTTPFilter
   217  	// InboundListenerCfg contains inbound listener configuration.
   218  	InboundListenerCfg *InboundListenerConfig
   219  
   220  	// Raw is the resource from the xds response.
   221  	Raw *anypb.Any
   222  }
   223  
   224  // HTTPFilter represents one HTTP filter from an LDS response's HTTP connection
   225  // manager field.
   226  type HTTPFilter struct {
   227  	// Name is an arbitrary name of the filter.  Used for applying override
   228  	// settings in virtual host / route / weighted cluster configuration (not
   229  	// yet supported).
   230  	Name string
   231  	// Filter is the HTTP filter found in the registry for the config type.
   232  	Filter httpfilter.Filter
   233  	// Config contains the filter's configuration
   234  	Config httpfilter.FilterConfig
   235  }
   236  
   237  // InboundListenerConfig contains information about the inbound listener, i.e
   238  // the server-side listener.
   239  type InboundListenerConfig struct {
   240  	// Address is the local address on which the inbound listener is expected to
   241  	// accept incoming connections.
   242  	Address string
   243  	// Port is the local port on which the inbound listener is expected to
   244  	// accept incoming connections.
   245  	Port string
   246  	// FilterChains is the list of filter chains associated with this listener.
   247  	FilterChains *FilterChainManager
   248  }
   249  
   250  // RouteConfigUpdate contains information received in an RDS response, which is
   251  // of interest to the registered RDS watcher.
   252  type RouteConfigUpdate struct {
   253  	VirtualHosts []*VirtualHost
   254  
   255  	// Raw is the resource from the xds response.
   256  	Raw *anypb.Any
   257  }
   258  
   259  // VirtualHost contains the routes for a list of Domains.
   260  //
   261  // Note that the domains in this slice can be a wildcard, not an exact string.
   262  // The consumer of this struct needs to find the best match for its hostname.
   263  type VirtualHost struct {
   264  	Domains []string
   265  	// Routes contains a list of routes, each containing matchers and
   266  	// corresponding action.
   267  	Routes []*Route
   268  	// HTTPFilterConfigOverride contains any HTTP filter config overrides for
   269  	// the virtual host which may be present.  An individual filter's override
   270  	// may be unused if the matching Route contains an override for that
   271  	// filter.
   272  	HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
   273  }
   274  
   275  // HashPolicyType specifies the type of HashPolicy from a received RDS Response.
   276  type HashPolicyType int
   277  
   278  const (
   279  	// HashPolicyTypeHeader specifies to hash a Header in the incoming request.
   280  	HashPolicyTypeHeader HashPolicyType = iota
   281  	// HashPolicyTypeChannelID specifies to hash a unique Identifier of the
   282  	// Channel. In grpc-go, this will be done using the ClientConn pointer.
   283  	HashPolicyTypeChannelID
   284  )
   285  
   286  // HashPolicy specifies the HashPolicy if the upstream cluster uses a hashing
   287  // load balancer.
   288  type HashPolicy struct {
   289  	HashPolicyType HashPolicyType
   290  	Terminal       bool
   291  	// Fields used for type HEADER.
   292  	HeaderName        string
   293  	Regex             *regexp.Regexp
   294  	RegexSubstitution string
   295  }
   296  
   297  // RouteAction is the action of the route from a received RDS response.
   298  type RouteAction int
   299  
   300  const (
   301  	// RouteActionUnsupported are routing types currently unsupported by grpc.
   302  	// According to A36, "A Route with an inappropriate action causes RPCs
   303  	// matching that route to fail."
   304  	RouteActionUnsupported RouteAction = iota
   305  	// RouteActionRoute is the expected route type on the client side. Route
   306  	// represents routing a request to some upstream cluster. On the client
   307  	// side, if an RPC matches to a route that is not RouteActionRoute, the RPC
   308  	// will fail according to A36.
   309  	RouteActionRoute
   310  	// RouteActionNonForwardingAction is the expected route type on the server
   311  	// side. NonForwardingAction represents when a route will generate a
   312  	// response directly, without forwarding to an upstream host.
   313  	RouteActionNonForwardingAction
   314  )
   315  
   316  // Route is both a specification of how to match a request as well as an
   317  // indication of the action to take upon match.
   318  type Route struct {
   319  	Path   *string
   320  	Prefix *string
   321  	Regex  *regexp.Regexp
   322  	// Indicates if prefix/path matching should be case insensitive. The default
   323  	// is false (case sensitive).
   324  	CaseInsensitive bool
   325  	Headers         []*HeaderMatcher
   326  	Fraction        *uint32
   327  
   328  	HashPolicies []*HashPolicy
   329  
   330  	// If the matchers above indicate a match, the below configuration is used.
   331  	WeightedClusters map[string]WeightedCluster
   332  	// If MaxStreamDuration is nil, it indicates neither of the route action's
   333  	// max_stream_duration fields (grpc_timeout_header_max nor
   334  	// max_stream_duration) were set.  In this case, the ListenerUpdate's
   335  	// MaxStreamDuration field should be used.  If MaxStreamDuration is set to
   336  	// an explicit zero duration, the application's deadline should be used.
   337  	MaxStreamDuration *time.Duration
   338  	// HTTPFilterConfigOverride contains any HTTP filter config overrides for
   339  	// the route which may be present.  An individual filter's override may be
   340  	// unused if the matching WeightedCluster contains an override for that
   341  	// filter.
   342  	HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
   343  
   344  	RouteAction RouteAction
   345  }
   346  
   347  // WeightedCluster contains settings for an xds RouteAction.WeightedCluster.
   348  type WeightedCluster struct {
   349  	// Weight is the relative weight of the cluster.  It will never be zero.
   350  	Weight uint32
   351  	// HTTPFilterConfigOverride contains any HTTP filter config overrides for
   352  	// the weighted cluster which may be present.
   353  	HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
   354  }
   355  
   356  // HeaderMatcher represents header matchers.
   357  type HeaderMatcher struct {
   358  	Name         string
   359  	InvertMatch  *bool
   360  	ExactMatch   *string
   361  	RegexMatch   *regexp.Regexp
   362  	PrefixMatch  *string
   363  	SuffixMatch  *string
   364  	RangeMatch   *Int64Range
   365  	PresentMatch *bool
   366  }
   367  
   368  // Int64Range is a range for header range match.
   369  type Int64Range struct {
   370  	Start int64
   371  	End   int64
   372  }
   373  
   374  // SecurityConfig contains the security configuration received as part of the
   375  // Cluster resource on the client-side, and as part of the Listener resource on
   376  // the server-side.
   377  type SecurityConfig struct {
   378  	// RootInstanceName identifies the certProvider plugin to be used to fetch
   379  	// root certificates. This instance name will be resolved to the plugin name
   380  	// and its associated configuration from the certificate_providers field of
   381  	// the bootstrap file.
   382  	RootInstanceName string
   383  	// RootCertName is the certificate name to be passed to the plugin (looked
   384  	// up from the bootstrap file) while fetching root certificates.
   385  	RootCertName string
   386  	// IdentityInstanceName identifies the certProvider plugin to be used to
   387  	// fetch identity certificates. This instance name will be resolved to the
   388  	// plugin name and its associated configuration from the
   389  	// certificate_providers field of the bootstrap file.
   390  	IdentityInstanceName string
   391  	// IdentityCertName is the certificate name to be passed to the plugin
   392  	// (looked up from the bootstrap file) while fetching identity certificates.
   393  	IdentityCertName string
   394  	// SubjectAltNameMatchers is an optional list of match criteria for SANs
   395  	// specified on the peer certificate. Used only on the client-side.
   396  	//
   397  	// Some intricacies:
   398  	// - If this field is empty, then any peer certificate is accepted.
   399  	// - If the peer certificate contains a wildcard DNS SAN, and an `exact`
   400  	//   matcher is configured, a wildcard DNS match is performed instead of a
   401  	//   regular string comparison.
   402  	SubjectAltNameMatchers []matcher.StringMatcher
   403  	// RequireClientCert indicates if the server handshake process expects the
   404  	// client to present a certificate. Set to true when performing mTLS. Used
   405  	// only on the server-side.
   406  	RequireClientCert bool
   407  }
   408  
   409  // ClusterType is the type of cluster from a received CDS response.
   410  type ClusterType int
   411  
   412  const (
   413  	// ClusterTypeEDS represents the EDS cluster type, which will delegate endpoint
   414  	// discovery to the management server.
   415  	ClusterTypeEDS ClusterType = iota
   416  	// ClusterTypeLogicalDNS represents the Logical DNS cluster type, which essentially
   417  	// maps to the gRPC behavior of using the DNS resolver with pick_first LB policy.
   418  	ClusterTypeLogicalDNS
   419  	// ClusterTypeAggregate represents the Aggregate Cluster type, which provides a
   420  	// prioritized list of clusters to use. It is used for failover between clusters
   421  	// with a different configuration.
   422  	ClusterTypeAggregate
   423  )
   424  
   425  // ClusterUpdate contains information from a received CDS response, which is of
   426  // interest to the registered CDS watcher.
   427  type ClusterUpdate struct {
   428  	ClusterType ClusterType
   429  	// ClusterName is the clusterName being watched for through CDS.
   430  	ClusterName string
   431  	// EDSServiceName is an optional name for EDS. If it's not set, the balancer
   432  	// should watch ClusterName for the EDS resources.
   433  	EDSServiceName string
   434  	// EnableLRS indicates whether or not load should be reported through LRS.
   435  	EnableLRS bool
   436  	// SecurityCfg contains security configuration sent by the control plane.
   437  	SecurityCfg *SecurityConfig
   438  	// MaxRequests for circuit breaking, if any (otherwise nil).
   439  	MaxRequests *uint32
   440  	// DNSHostName is used only for cluster type DNS. It's the DNS name to
   441  	// resolve in "host:port" form
   442  	DNSHostName string
   443  	// PrioritizedClusterNames is used only for cluster type aggregate. It represents
   444  	// a prioritized list of cluster names.
   445  	PrioritizedClusterNames []string
   446  
   447  	// Raw is the resource from the xds response.
   448  	Raw *anypb.Any
   449  }
   450  
   451  // OverloadDropConfig contains the config to drop overloads.
   452  type OverloadDropConfig struct {
   453  	Category    string
   454  	Numerator   uint32
   455  	Denominator uint32
   456  }
   457  
   458  // EndpointHealthStatus represents the health status of an endpoint.
   459  type EndpointHealthStatus int32
   460  
   461  const (
   462  	// EndpointHealthStatusUnknown represents HealthStatus UNKNOWN.
   463  	EndpointHealthStatusUnknown EndpointHealthStatus = iota
   464  	// EndpointHealthStatusHealthy represents HealthStatus HEALTHY.
   465  	EndpointHealthStatusHealthy
   466  	// EndpointHealthStatusUnhealthy represents HealthStatus UNHEALTHY.
   467  	EndpointHealthStatusUnhealthy
   468  	// EndpointHealthStatusDraining represents HealthStatus DRAINING.
   469  	EndpointHealthStatusDraining
   470  	// EndpointHealthStatusTimeout represents HealthStatus TIMEOUT.
   471  	EndpointHealthStatusTimeout
   472  	// EndpointHealthStatusDegraded represents HealthStatus DEGRADED.
   473  	EndpointHealthStatusDegraded
   474  )
   475  
   476  // Endpoint contains information of an endpoint.
   477  type Endpoint struct {
   478  	Address      string
   479  	HealthStatus EndpointHealthStatus
   480  	Weight       uint32
   481  }
   482  
   483  // Locality contains information of a locality.
   484  type Locality struct {
   485  	Endpoints []Endpoint
   486  	ID        internal.LocalityID
   487  	Priority  uint32
   488  	Weight    uint32
   489  }
   490  
   491  // EndpointsUpdate contains an EDS update.
   492  type EndpointsUpdate struct {
   493  	Drops      []OverloadDropConfig
   494  	Localities []Locality
   495  
   496  	// Raw is the resource from the xds response.
   497  	Raw *anypb.Any
   498  }
   499  
   500  // Function to be overridden in tests.
   501  var newAPIClient = func(apiVersion version.TransportAPI, cc *grpc.ClientConn, opts BuildOptions) (APIClient, error) {
   502  	cb := getAPIClientBuilder(apiVersion)
   503  	if cb == nil {
   504  		return nil, fmt.Errorf("no client builder for xDS API version: %v", apiVersion)
   505  	}
   506  	return cb.Build(cc, opts)
   507  }
   508  
   509  // clientImpl is the real implementation of the xds client. The exported Client
   510  // is a wrapper of this struct with a ref count.
   511  //
   512  // Implements UpdateHandler interface.
   513  // TODO(easwars): Make a wrapper struct which implements this interface in the
   514  // style of ccBalancerWrapper so that the Client type does not implement these
   515  // exported methods.
   516  type clientImpl struct {
   517  	done               *grpcsync.Event
   518  	config             *bootstrap.Config
   519  	cc                 *grpc.ClientConn // Connection to the management server.
   520  	apiClient          APIClient
   521  	watchExpiryTimeout time.Duration
   522  
   523  	logger *grpclog.PrefixLogger
   524  
   525  	updateCh *buffer.Unbounded // chan *watcherInfoWithUpdate
   526  	// All the following maps are to keep the updates/metadata in a cache.
   527  	// TODO: move them to a separate struct/package, to cleanup the xds_client.
   528  	// And CSDS handler can be implemented directly by the cache.
   529  	mu          sync.Mutex
   530  	ldsWatchers map[string]map[*watchInfo]bool
   531  	ldsVersion  string // Only used in CSDS.
   532  	ldsCache    map[string]ListenerUpdate
   533  	ldsMD       map[string]UpdateMetadata
   534  	rdsWatchers map[string]map[*watchInfo]bool
   535  	rdsVersion  string // Only used in CSDS.
   536  	rdsCache    map[string]RouteConfigUpdate
   537  	rdsMD       map[string]UpdateMetadata
   538  	cdsWatchers map[string]map[*watchInfo]bool
   539  	cdsVersion  string // Only used in CSDS.
   540  	cdsCache    map[string]ClusterUpdate
   541  	cdsMD       map[string]UpdateMetadata
   542  	edsWatchers map[string]map[*watchInfo]bool
   543  	edsVersion  string // Only used in CSDS.
   544  	edsCache    map[string]EndpointsUpdate
   545  	edsMD       map[string]UpdateMetadata
   546  
   547  	// Changes to map lrsClients and the lrsClient inside the map need to be
   548  	// protected by lrsMu.
   549  	lrsMu      sync.Mutex
   550  	lrsClients map[string]*lrsClient
   551  }
   552  
   553  // newWithConfig returns a new xdsClient with the given config.
   554  func newWithConfig(config *bootstrap.Config, watchExpiryTimeout time.Duration) (*clientImpl, error) {
   555  	switch {
   556  	case config.BalancerName == "":
   557  		return nil, errors.New("xds: no xds_server name provided in options")
   558  	case config.Creds == nil:
   559  		return nil, errors.New("xds: no credentials provided in options")
   560  	case config.NodeProto == nil:
   561  		return nil, errors.New("xds: no node_proto provided in options")
   562  	}
   563  
   564  	switch config.TransportAPI {
   565  	case version.TransportV2:
   566  		if _, ok := config.NodeProto.(*v2corepb.Node); !ok {
   567  			return nil, fmt.Errorf("xds: Node proto type (%T) does not match API version: %v", config.NodeProto, config.TransportAPI)
   568  		}
   569  	case version.TransportV3:
   570  		if _, ok := config.NodeProto.(*v3corepb.Node); !ok {
   571  			return nil, fmt.Errorf("xds: Node proto type (%T) does not match API version: %v", config.NodeProto, config.TransportAPI)
   572  		}
   573  	}
   574  
   575  	dopts := []grpc.DialOption{
   576  		config.Creds,
   577  		grpc.WithKeepaliveParams(keepalive.ClientParameters{
   578  			Time:    5 * time.Minute,
   579  			Timeout: 20 * time.Second,
   580  		}),
   581  	}
   582  
   583  	c := &clientImpl{
   584  		done:               grpcsync.NewEvent(),
   585  		config:             config,
   586  		watchExpiryTimeout: watchExpiryTimeout,
   587  
   588  		updateCh:    buffer.NewUnbounded(),
   589  		ldsWatchers: make(map[string]map[*watchInfo]bool),
   590  		ldsCache:    make(map[string]ListenerUpdate),
   591  		ldsMD:       make(map[string]UpdateMetadata),
   592  		rdsWatchers: make(map[string]map[*watchInfo]bool),
   593  		rdsCache:    make(map[string]RouteConfigUpdate),
   594  		rdsMD:       make(map[string]UpdateMetadata),
   595  		cdsWatchers: make(map[string]map[*watchInfo]bool),
   596  		cdsCache:    make(map[string]ClusterUpdate),
   597  		cdsMD:       make(map[string]UpdateMetadata),
   598  		edsWatchers: make(map[string]map[*watchInfo]bool),
   599  		edsCache:    make(map[string]EndpointsUpdate),
   600  		edsMD:       make(map[string]UpdateMetadata),
   601  		lrsClients:  make(map[string]*lrsClient),
   602  	}
   603  
   604  	cc, err := grpc.Dial(config.BalancerName, dopts...)
   605  	if err != nil {
   606  		// An error from a non-blocking dial indicates something serious.
   607  		return nil, fmt.Errorf("xds: failed to dial balancer {%s}: %v", config.BalancerName, err)
   608  	}
   609  	c.cc = cc
   610  	c.logger = prefixLogger((c))
   611  	c.logger.Infof("Created ClientConn to xDS management server: %s", config.BalancerName)
   612  
   613  	apiClient, err := newAPIClient(config.TransportAPI, cc, BuildOptions{
   614  		Parent:    c,
   615  		NodeProto: config.NodeProto,
   616  		Backoff:   backoff.DefaultExponential.Backoff,
   617  		Logger:    c.logger,
   618  	})
   619  	if err != nil {
   620  		return nil, err
   621  	}
   622  	c.apiClient = apiClient
   623  	c.logger.Infof("Created")
   624  	go c.run()
   625  	return c, nil
   626  }
   627  
   628  // BootstrapConfig returns the configuration read from the bootstrap file.
   629  // Callers must treat the return value as read-only.
   630  func (c *clientRefCounted) BootstrapConfig() *bootstrap.Config {
   631  	return c.config
   632  }
   633  
   634  // run is a goroutine for all the callbacks.
   635  //
   636  // Callback can be called in watch(), if an item is found in cache. Without this
   637  // goroutine, the callback will be called inline, which might cause a deadlock
   638  // in user's code. Callbacks also cannot be simple `go callback()` because the
   639  // order matters.
   640  func (c *clientImpl) run() {
   641  	for {
   642  		select {
   643  		case t := <-c.updateCh.Get():
   644  			c.updateCh.Load()
   645  			if c.done.HasFired() {
   646  				return
   647  			}
   648  			c.callCallback(t.(*watcherInfoWithUpdate))
   649  		case <-c.done.Done():
   650  			return
   651  		}
   652  	}
   653  }
   654  
   655  // Close closes the gRPC connection to the management server.
   656  func (c *clientImpl) Close() {
   657  	if c.done.HasFired() {
   658  		return
   659  	}
   660  	c.done.Fire()
   661  	// TODO: Should we invoke the registered callbacks here with an error that
   662  	// the client is closed?
   663  	c.apiClient.Close()
   664  	c.cc.Close()
   665  	c.logger.Infof("Shutdown")
   666  }
   667  
   668  // ResourceType identifies resources in a transport protocol agnostic way. These
   669  // will be used in transport version agnostic code, while the versioned API
   670  // clients will map these to appropriate version URLs.
   671  type ResourceType int
   672  
   673  // Version agnostic resource type constants.
   674  const (
   675  	UnknownResource ResourceType = iota
   676  	ListenerResource
   677  	HTTPConnManagerResource
   678  	RouteConfigResource
   679  	ClusterResource
   680  	EndpointsResource
   681  )
   682  
   683  func (r ResourceType) String() string {
   684  	switch r {
   685  	case ListenerResource:
   686  		return "ListenerResource"
   687  	case HTTPConnManagerResource:
   688  		return "HTTPConnManagerResource"
   689  	case RouteConfigResource:
   690  		return "RouteConfigResource"
   691  	case ClusterResource:
   692  		return "ClusterResource"
   693  	case EndpointsResource:
   694  		return "EndpointsResource"
   695  	default:
   696  		return "UnknownResource"
   697  	}
   698  }
   699  
   700  // IsListenerResource returns true if the provider URL corresponds to an xDS
   701  // Listener resource.
   702  func IsListenerResource(url string) bool {
   703  	return url == version.V2ListenerURL || url == version.V3ListenerURL
   704  }
   705  
   706  // IsHTTPConnManagerResource returns true if the provider URL corresponds to an xDS
   707  // HTTPConnManager resource.
   708  func IsHTTPConnManagerResource(url string) bool {
   709  	return url == version.V2HTTPConnManagerURL || url == version.V3HTTPConnManagerURL
   710  }
   711  
   712  // IsRouteConfigResource returns true if the provider URL corresponds to an xDS
   713  // RouteConfig resource.
   714  func IsRouteConfigResource(url string) bool {
   715  	return url == version.V2RouteConfigURL || url == version.V3RouteConfigURL
   716  }
   717  
   718  // IsClusterResource returns true if the provider URL corresponds to an xDS
   719  // Cluster resource.
   720  func IsClusterResource(url string) bool {
   721  	return url == version.V2ClusterURL || url == version.V3ClusterURL
   722  }
   723  
   724  // IsEndpointsResource returns true if the provider URL corresponds to an xDS
   725  // Endpoints resource.
   726  func IsEndpointsResource(url string) bool {
   727  	return url == version.V2EndpointsURL || url == version.V3EndpointsURL
   728  }