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 client implements a full fledged gRPC client for the xDS API used by
20// the xds resolver and balancer implementations.
21package client
22
23import (
24	"context"
25	"errors"
26	"fmt"
27	"net"
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"
37	"google.golang.org/grpc/xds/internal/client/load"
38	"google.golang.org/grpc/xds/internal/httpfilter"
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/client/bootstrap"
48	"google.golang.org/grpc/xds/internal/version"
49)
50
51var (
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.
61func 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.
67func 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.
75type 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.
92type 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.
110type 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.
128type 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.
134type 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}
145
146// ServiceStatus is the status of the update.
147type ServiceStatus int
148
149const (
150	// ServiceStatusUnknown is the default state, before a watch is started for
151	// the resource.
152	ServiceStatusUnknown ServiceStatus = iota
153	// ServiceStatusRequested is when the watch is started, but before and
154	// response is received.
155	ServiceStatusRequested
156	// ServiceStatusNotExist is when the resource doesn't exist in
157	// state-of-the-world responses (e.g. LDS and CDS), which means the resource
158	// is removed by the management server.
159	ServiceStatusNotExist // Resource is removed in the server, in LDS/CDS.
160	// ServiceStatusACKed is when the resource is ACKed.
161	ServiceStatusACKed
162	// ServiceStatusNACKed is when the resource is NACKed.
163	ServiceStatusNACKed
164)
165
166// UpdateErrorMetadata is part of UpdateMetadata. It contains the error state
167// when a response is NACKed.
168type UpdateErrorMetadata struct {
169	// Version is the version of the NACKed response.
170	Version string
171	// Err contains why the response was NACKed.
172	Err error
173	// Timestamp is when the NACKed response was received.
174	Timestamp time.Time
175}
176
177// UpdateMetadata contains the metadata for each update, including timestamp,
178// raw message, and so on.
179type UpdateMetadata struct {
180	// Status is the status of this resource, e.g. ACKed, NACKed, or
181	// Not_exist(removed).
182	Status ServiceStatus
183	// Version is the version of the xds response. Note that this is the version
184	// of the resource in use (previous ACKed). If a response is NACKed, the
185	// NACKed version is in ErrState.
186	Version string
187	// Timestamp is when the response is received.
188	Timestamp time.Time
189	// ErrState is set when the update is NACKed.
190	ErrState *UpdateErrorMetadata
191}
192
193// ListenerUpdate contains information received in an LDS response, which is of
194// interest to the registered LDS watcher.
195type ListenerUpdate struct {
196	// RouteConfigName is the route configuration name corresponding to the
197	// target which is being watched through LDS.
198	RouteConfigName string
199	// MaxStreamDuration contains the HTTP connection manager's
200	// common_http_protocol_options.max_stream_duration field, or zero if
201	// unset.
202	MaxStreamDuration time.Duration
203	// HTTPFilters is a list of HTTP filters (name, config) from the LDS
204	// response.
205	HTTPFilters []HTTPFilter
206	// InboundListenerCfg contains inbound listener configuration.
207	InboundListenerCfg *InboundListenerConfig
208
209	// Raw is the resource from the xds response.
210	Raw *anypb.Any
211}
212
213// HTTPFilter represents one HTTP filter from an LDS response's HTTP connection
214// manager field.
215type HTTPFilter struct {
216	// Name is an arbitrary name of the filter.  Used for applying override
217	// settings in virtual host / route / weighted cluster configuration (not
218	// yet supported).
219	Name string
220	// Filter is the HTTP filter found in the registry for the config type.
221	Filter httpfilter.Filter
222	// Config contains the filter's configuration
223	Config httpfilter.FilterConfig
224}
225
226// InboundListenerConfig contains information about the inbound listener, i.e
227// the server-side listener.
228type InboundListenerConfig struct {
229	// Address is the local address on which the inbound listener is expected to
230	// accept incoming connections.
231	Address string
232	// Port is the local port on which the inbound listener is expected to
233	// accept incoming connections.
234	Port string
235	// FilterChains is the list of filter chains associated with this listener.
236	FilterChains []*FilterChain
237	// DefaultFilterChain is the filter chain to be used when none of the above
238	// filter chains matches an incoming connection.
239	DefaultFilterChain *FilterChain
240}
241
242// FilterChain wraps a set of match criteria and associated security
243// configuration.
244//
245// The actual set filters associated with this filter chain are not captured
246// here, since we do not support these filters on the server yet.
247type FilterChain struct {
248	// Match contains the criteria to use when matching a connection to this
249	// filter chain.
250	Match *FilterChainMatch
251	// SecurityCfg contains transport socket security configuration.
252	SecurityCfg *SecurityConfig
253}
254
255// SourceType specifies the connection source IP match type.
256type SourceType int
257
258const (
259	// SourceTypeAny matches connection attempts from any source.
260	SourceTypeAny SourceType = iota
261	// SourceTypeSameOrLoopback matches connection attempts from the same host.
262	SourceTypeSameOrLoopback
263	// SourceTypeExternal matches connection attempts from a different host.
264	SourceTypeExternal
265)
266
267// FilterChainMatch specifies the match criteria for selecting a specific filter
268// chain of a listener, for an incoming connection.
269//
270// The xDS FilterChainMatch proto specifies 8 match criteria. But we only have a
271// subset of those fields here because we explicitly ignore filter chains whose
272// match criteria specifies values for fields like destination_port,
273// server_names, application_protocols, transport_protocol.
274type FilterChainMatch struct {
275	// DestPrefixRanges specifies a set of IP addresses and prefix lengths to
276	// match the destination address of the incoming connection when the
277	// listener is bound to 0.0.0.0/[::]. If this field is empty, the
278	// destination address is ignored.
279	DestPrefixRanges []net.IP
280	// SourceType specifies the connection source IP match type. Can be any,
281	// local or external network.
282	SourceType SourceType
283	// SourcePrefixRanges specifies a set of IP addresses and prefix lengths to
284	// match the source address of the incoming connection. If this field is
285	// empty, the source address is ignored.
286	SourcePrefixRanges []net.IP
287	// SourcePorts specifies a set of ports to match the source port of the
288	// incoming connection. If this field is empty, the source port is ignored.
289	SourcePorts []uint32
290}
291
292// RouteConfigUpdate contains information received in an RDS response, which is
293// of interest to the registered RDS watcher.
294type RouteConfigUpdate struct {
295	VirtualHosts []*VirtualHost
296
297	// Raw is the resource from the xds response.
298	Raw *anypb.Any
299}
300
301// VirtualHost contains the routes for a list of Domains.
302//
303// Note that the domains in this slice can be a wildcard, not an exact string.
304// The consumer of this struct needs to find the best match for its hostname.
305type VirtualHost struct {
306	Domains []string
307	// Routes contains a list of routes, each containing matchers and
308	// corresponding action.
309	Routes []*Route
310	// HTTPFilterConfigOverride contains any HTTP filter config overrides for
311	// the virtual host which may be present.  An individual filter's override
312	// may be unused if the matching Route contains an override for that
313	// filter.
314	HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
315}
316
317// Route is both a specification of how to match a request as well as an
318// indication of the action to take upon match.
319type Route struct {
320	Path, Prefix, Regex *string
321	// Indicates if prefix/path matching should be case insensitive. The default
322	// is false (case sensitive).
323	CaseInsensitive bool
324	Headers         []*HeaderMatcher
325	Fraction        *uint32
326
327	// If the matchers above indicate a match, the below configuration is used.
328	WeightedClusters map[string]WeightedCluster
329	// If MaxStreamDuration is nil, it indicates neither of the route action's
330	// max_stream_duration fields (grpc_timeout_header_max nor
331	// max_stream_duration) were set.  In this case, the ListenerUpdate's
332	// MaxStreamDuration field should be used.  If MaxStreamDuration is set to
333	// an explicit zero duration, the application's deadline should be used.
334	MaxStreamDuration *time.Duration
335	// HTTPFilterConfigOverride contains any HTTP filter config overrides for
336	// the route which may be present.  An individual filter's override may be
337	// unused if the matching WeightedCluster contains an override for that
338	// filter.
339	HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
340}
341
342// WeightedCluster contains settings for an xds RouteAction.WeightedCluster.
343type WeightedCluster struct {
344	// Weight is the relative weight of the cluster.  It will never be zero.
345	Weight uint32
346	// HTTPFilterConfigOverride contains any HTTP filter config overrides for
347	// the weighted cluster which may be present.
348	HTTPFilterConfigOverride map[string]httpfilter.FilterConfig
349}
350
351// HeaderMatcher represents header matchers.
352type HeaderMatcher struct {
353	Name         string      `json:"name"`
354	InvertMatch  *bool       `json:"invertMatch,omitempty"`
355	ExactMatch   *string     `json:"exactMatch,omitempty"`
356	RegexMatch   *string     `json:"regexMatch,omitempty"`
357	PrefixMatch  *string     `json:"prefixMatch,omitempty"`
358	SuffixMatch  *string     `json:"suffixMatch,omitempty"`
359	RangeMatch   *Int64Range `json:"rangeMatch,omitempty"`
360	PresentMatch *bool       `json:"presentMatch,omitempty"`
361}
362
363// Int64Range is a range for header range match.
364type Int64Range struct {
365	Start int64 `json:"start"`
366	End   int64 `json:"end"`
367}
368
369// SecurityConfig contains the security configuration received as part of the
370// Cluster resource on the client-side, and as part of the Listener resource on
371// the server-side.
372type SecurityConfig struct {
373	// RootInstanceName identifies the certProvider plugin to be used to fetch
374	// root certificates. This instance name will be resolved to the plugin name
375	// and its associated configuration from the certificate_providers field of
376	// the bootstrap file.
377	RootInstanceName string
378	// RootCertName is the certificate name to be passed to the plugin (looked
379	// up from the bootstrap file) while fetching root certificates.
380	RootCertName string
381	// IdentityInstanceName identifies the certProvider plugin to be used to
382	// fetch identity certificates. This instance name will be resolved to the
383	// plugin name and its associated configuration from the
384	// certificate_providers field of the bootstrap file.
385	IdentityInstanceName string
386	// IdentityCertName is the certificate name to be passed to the plugin
387	// (looked up from the bootstrap file) while fetching identity certificates.
388	IdentityCertName string
389	// SubjectAltNameMatchers is an optional list of match criteria for SANs
390	// specified on the peer certificate. Used only on the client-side.
391	//
392	// Some intricacies:
393	// - If this field is empty, then any peer certificate is accepted.
394	// - If the peer certificate contains a wildcard DNS SAN, and an `exact`
395	//   matcher is configured, a wildcard DNS match is performed instead of a
396	//   regular string comparison.
397	SubjectAltNameMatchers []xds.StringMatcher
398	// RequireClientCert indicates if the server handshake process expects the
399	// client to present a certificate. Set to true when performing mTLS. Used
400	// only on the server-side.
401	RequireClientCert bool
402}
403
404// ClusterUpdate contains information from a received CDS response, which is of
405// interest to the registered CDS watcher.
406type ClusterUpdate struct {
407	// ServiceName is the service name corresponding to the clusterName which
408	// is being watched for through CDS.
409	ServiceName string
410	// EnableLRS indicates whether or not load should be reported through LRS.
411	EnableLRS bool
412	// SecurityCfg contains security configuration sent by the control plane.
413	SecurityCfg *SecurityConfig
414	// MaxRequests for circuit breaking, if any (otherwise nil).
415	MaxRequests *uint32
416
417	// Raw is the resource from the xds response.
418	Raw *anypb.Any
419}
420
421// OverloadDropConfig contains the config to drop overloads.
422type OverloadDropConfig struct {
423	Category    string
424	Numerator   uint32
425	Denominator uint32
426}
427
428// EndpointHealthStatus represents the health status of an endpoint.
429type EndpointHealthStatus int32
430
431const (
432	// EndpointHealthStatusUnknown represents HealthStatus UNKNOWN.
433	EndpointHealthStatusUnknown EndpointHealthStatus = iota
434	// EndpointHealthStatusHealthy represents HealthStatus HEALTHY.
435	EndpointHealthStatusHealthy
436	// EndpointHealthStatusUnhealthy represents HealthStatus UNHEALTHY.
437	EndpointHealthStatusUnhealthy
438	// EndpointHealthStatusDraining represents HealthStatus DRAINING.
439	EndpointHealthStatusDraining
440	// EndpointHealthStatusTimeout represents HealthStatus TIMEOUT.
441	EndpointHealthStatusTimeout
442	// EndpointHealthStatusDegraded represents HealthStatus DEGRADED.
443	EndpointHealthStatusDegraded
444)
445
446// Endpoint contains information of an endpoint.
447type Endpoint struct {
448	Address      string
449	HealthStatus EndpointHealthStatus
450	Weight       uint32
451}
452
453// Locality contains information of a locality.
454type Locality struct {
455	Endpoints []Endpoint
456	ID        internal.LocalityID
457	Priority  uint32
458	Weight    uint32
459}
460
461// EndpointsUpdate contains an EDS update.
462type EndpointsUpdate struct {
463	Drops      []OverloadDropConfig
464	Localities []Locality
465
466	// Raw is the resource from the xds response.
467	Raw *anypb.Any
468}
469
470// Function to be overridden in tests.
471var newAPIClient = func(apiVersion version.TransportAPI, cc *grpc.ClientConn, opts BuildOptions) (APIClient, error) {
472	cb := getAPIClientBuilder(apiVersion)
473	if cb == nil {
474		return nil, fmt.Errorf("no client builder for xDS API version: %v", apiVersion)
475	}
476	return cb.Build(cc, opts)
477}
478
479// clientImpl is the real implementation of the xds client. The exported Client
480// is a wrapper of this struct with a ref count.
481//
482// Implements UpdateHandler interface.
483// TODO(easwars): Make a wrapper struct which implements this interface in the
484// style of ccBalancerWrapper so that the Client type does not implement these
485// exported methods.
486type clientImpl struct {
487	done               *grpcsync.Event
488	config             *bootstrap.Config
489	cc                 *grpc.ClientConn // Connection to the management server.
490	apiClient          APIClient
491	watchExpiryTimeout time.Duration
492
493	logger *grpclog.PrefixLogger
494
495	updateCh *buffer.Unbounded // chan *watcherInfoWithUpdate
496	// All the following maps are to keep the updates/metadata in a cache.
497	// TODO: move them to a separate struct/package, to cleanup the xds_client.
498	// And CSDS handler can be implemented directly by the cache.
499	mu          sync.Mutex
500	ldsWatchers map[string]map[*watchInfo]bool
501	ldsVersion  string // Only used in CSDS.
502	ldsCache    map[string]ListenerUpdate
503	ldsMD       map[string]UpdateMetadata
504	rdsWatchers map[string]map[*watchInfo]bool
505	rdsVersion  string // Only used in CSDS.
506	rdsCache    map[string]RouteConfigUpdate
507	rdsMD       map[string]UpdateMetadata
508	cdsWatchers map[string]map[*watchInfo]bool
509	cdsVersion  string // Only used in CSDS.
510	cdsCache    map[string]ClusterUpdate
511	cdsMD       map[string]UpdateMetadata
512	edsWatchers map[string]map[*watchInfo]bool
513	edsVersion  string // Only used in CSDS.
514	edsCache    map[string]EndpointsUpdate
515	edsMD       map[string]UpdateMetadata
516
517	// Changes to map lrsClients and the lrsClient inside the map need to be
518	// protected by lrsMu.
519	lrsMu      sync.Mutex
520	lrsClients map[string]*lrsClient
521}
522
523// newWithConfig returns a new xdsClient with the given config.
524func newWithConfig(config *bootstrap.Config, watchExpiryTimeout time.Duration) (*clientImpl, error) {
525	switch {
526	case config.BalancerName == "":
527		return nil, errors.New("xds: no xds_server name provided in options")
528	case config.Creds == nil:
529		return nil, errors.New("xds: no credentials provided in options")
530	case config.NodeProto == nil:
531		return nil, errors.New("xds: no node_proto provided in options")
532	}
533
534	switch config.TransportAPI {
535	case version.TransportV2:
536		if _, ok := config.NodeProto.(*v2corepb.Node); !ok {
537			return nil, fmt.Errorf("xds: Node proto type (%T) does not match API version: %v", config.NodeProto, config.TransportAPI)
538		}
539	case version.TransportV3:
540		if _, ok := config.NodeProto.(*v3corepb.Node); !ok {
541			return nil, fmt.Errorf("xds: Node proto type (%T) does not match API version: %v", config.NodeProto, config.TransportAPI)
542		}
543	}
544
545	dopts := []grpc.DialOption{
546		config.Creds,
547		grpc.WithKeepaliveParams(keepalive.ClientParameters{
548			Time:    5 * time.Minute,
549			Timeout: 20 * time.Second,
550		}),
551	}
552
553	c := &clientImpl{
554		done:               grpcsync.NewEvent(),
555		config:             config,
556		watchExpiryTimeout: watchExpiryTimeout,
557
558		updateCh:    buffer.NewUnbounded(),
559		ldsWatchers: make(map[string]map[*watchInfo]bool),
560		ldsCache:    make(map[string]ListenerUpdate),
561		ldsMD:       make(map[string]UpdateMetadata),
562		rdsWatchers: make(map[string]map[*watchInfo]bool),
563		rdsCache:    make(map[string]RouteConfigUpdate),
564		rdsMD:       make(map[string]UpdateMetadata),
565		cdsWatchers: make(map[string]map[*watchInfo]bool),
566		cdsCache:    make(map[string]ClusterUpdate),
567		cdsMD:       make(map[string]UpdateMetadata),
568		edsWatchers: make(map[string]map[*watchInfo]bool),
569		edsCache:    make(map[string]EndpointsUpdate),
570		edsMD:       make(map[string]UpdateMetadata),
571		lrsClients:  make(map[string]*lrsClient),
572	}
573
574	cc, err := grpc.Dial(config.BalancerName, dopts...)
575	if err != nil {
576		// An error from a non-blocking dial indicates something serious.
577		return nil, fmt.Errorf("xds: failed to dial balancer {%s}: %v", config.BalancerName, err)
578	}
579	c.cc = cc
580	c.logger = prefixLogger((c))
581	c.logger.Infof("Created ClientConn to xDS management server: %s", config.BalancerName)
582
583	apiClient, err := newAPIClient(config.TransportAPI, cc, BuildOptions{
584		Parent:    c,
585		NodeProto: config.NodeProto,
586		Backoff:   backoff.DefaultExponential.Backoff,
587		Logger:    c.logger,
588	})
589	if err != nil {
590		return nil, err
591	}
592	c.apiClient = apiClient
593	c.logger.Infof("Created")
594	go c.run()
595	return c, nil
596}
597
598// BootstrapConfig returns the configuration read from the bootstrap file.
599// Callers must treat the return value as read-only.
600func (c *Client) BootstrapConfig() *bootstrap.Config {
601	return c.config
602}
603
604// run is a goroutine for all the callbacks.
605//
606// Callback can be called in watch(), if an item is found in cache. Without this
607// goroutine, the callback will be called inline, which might cause a deadlock
608// in user's code. Callbacks also cannot be simple `go callback()` because the
609// order matters.
610func (c *clientImpl) run() {
611	for {
612		select {
613		case t := <-c.updateCh.Get():
614			c.updateCh.Load()
615			if c.done.HasFired() {
616				return
617			}
618			c.callCallback(t.(*watcherInfoWithUpdate))
619		case <-c.done.Done():
620			return
621		}
622	}
623}
624
625// Close closes the gRPC connection to the management server.
626func (c *clientImpl) Close() {
627	if c.done.HasFired() {
628		return
629	}
630	c.done.Fire()
631	// TODO: Should we invoke the registered callbacks here with an error that
632	// the client is closed?
633	c.apiClient.Close()
634	c.cc.Close()
635	c.logger.Infof("Shutdown")
636}
637
638// ResourceType identifies resources in a transport protocol agnostic way. These
639// will be used in transport version agnostic code, while the versioned API
640// clients will map these to appropriate version URLs.
641type ResourceType int
642
643// Version agnostic resource type constants.
644const (
645	UnknownResource ResourceType = iota
646	ListenerResource
647	HTTPConnManagerResource
648	RouteConfigResource
649	ClusterResource
650	EndpointsResource
651)
652
653func (r ResourceType) String() string {
654	switch r {
655	case ListenerResource:
656		return "ListenerResource"
657	case HTTPConnManagerResource:
658		return "HTTPConnManagerResource"
659	case RouteConfigResource:
660		return "RouteConfigResource"
661	case ClusterResource:
662		return "ClusterResource"
663	case EndpointsResource:
664		return "EndpointsResource"
665	default:
666		return "UnknownResource"
667	}
668}
669
670// IsListenerResource returns true if the provider URL corresponds to an xDS
671// Listener resource.
672func IsListenerResource(url string) bool {
673	return url == version.V2ListenerURL || url == version.V3ListenerURL
674}
675
676// IsHTTPConnManagerResource returns true if the provider URL corresponds to an xDS
677// HTTPConnManager resource.
678func IsHTTPConnManagerResource(url string) bool {
679	return url == version.V2HTTPConnManagerURL || url == version.V3HTTPConnManagerURL
680}
681
682// IsRouteConfigResource returns true if the provider URL corresponds to an xDS
683// RouteConfig resource.
684func IsRouteConfigResource(url string) bool {
685	return url == version.V2RouteConfigURL || url == version.V3RouteConfigURL
686}
687
688// IsClusterResource returns true if the provider URL corresponds to an xDS
689// Cluster resource.
690func IsClusterResource(url string) bool {
691	return url == version.V2ClusterURL || url == version.V3ClusterURL
692}
693
694// IsEndpointsResource returns true if the provider URL corresponds to an xDS
695// Endpoints resource.
696func IsEndpointsResource(url string) bool {
697	return url == version.V2EndpointsURL || url == version.V3EndpointsURL
698}
699