/* * * Copyright 2019 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 xdsclient implements a full fledged gRPC client for the xDS API used // by the xds resolver and balancer implementations. package xdsclient import ( "context" "errors" "fmt" "regexp" "sync" "time" v2corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core" v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" "github.com/golang/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" "google.golang.org/grpc/codes" "google.golang.org/grpc/internal/xds/matcher" "google.golang.org/grpc/xds/internal/httpfilter" "google.golang.org/grpc/xds/internal/xdsclient/load" "google.golang.org/grpc" "google.golang.org/grpc/internal/backoff" "google.golang.org/grpc/internal/buffer" "google.golang.org/grpc/internal/grpclog" "google.golang.org/grpc/internal/grpcsync" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/xds/internal" "google.golang.org/grpc/xds/internal/version" "google.golang.org/grpc/xds/internal/xdsclient/bootstrap" ) var ( m = make(map[version.TransportAPI]APIClientBuilder) ) // RegisterAPIClientBuilder registers a client builder for xDS transport protocol // version specified by b.Version(). // // NOTE: this function must only be called during initialization time (i.e. in // an init() function), and is not thread-safe. If multiple builders are // registered for the same version, the one registered last will take effect. func RegisterAPIClientBuilder(b APIClientBuilder) { m[b.Version()] = b } // getAPIClientBuilder returns the client builder registered for the provided // xDS transport API version. func getAPIClientBuilder(version version.TransportAPI) APIClientBuilder { if b, ok := m[version]; ok { return b } return nil } // UpdateValidatorFunc performs validations on update structs using // context/logic available at the xdsClient layer. Since these validation are // performed on internal update structs, they can be shared between different // API clients. type UpdateValidatorFunc func(interface{}) error // BuildOptions contains options to be passed to client builders. type BuildOptions struct { // Parent is a top-level xDS client which has the intelligence to take // appropriate action based on xDS responses received from the management // server. Parent UpdateHandler // Validator performs post unmarshal validation checks. Validator UpdateValidatorFunc // NodeProto contains the Node proto to be used in xDS requests. The actual // type depends on the transport protocol version used. NodeProto proto.Message // Backoff returns the amount of time to backoff before retrying broken // streams. Backoff func(int) time.Duration // Logger provides enhanced logging capabilities. Logger *grpclog.PrefixLogger } // APIClientBuilder creates an xDS client for a specific xDS transport protocol // version. type APIClientBuilder interface { // Build builds a transport protocol specific implementation of the xDS // client based on the provided clientConn to the management server and the // provided options. Build(*grpc.ClientConn, BuildOptions) (APIClient, error) // Version returns the xDS transport protocol version used by clients build // using this builder. Version() version.TransportAPI } // APIClient represents the functionality provided by transport protocol // version specific implementations of the xDS client. // // TODO: unexport this interface and all the methods after the PR to make // xdsClient sharable by clients. AddWatch and RemoveWatch are exported for // v2/v3 to override because they need to keep track of LDS name for RDS to use. // After the share xdsClient change, that's no longer necessary. After that, we // will still keep this interface for testing purposes. type APIClient interface { // AddWatch adds a watch for an xDS resource given its type and name. AddWatch(ResourceType, string) // RemoveWatch cancels an already registered watch for an xDS resource // given its type and name. RemoveWatch(ResourceType, string) // reportLoad starts an LRS stream to periodically report load using the // provided ClientConn, which represent a connection to the management // server. reportLoad(ctx context.Context, cc *grpc.ClientConn, opts loadReportingOptions) // Close cleans up resources allocated by the API client. Close() } // loadReportingOptions contains configuration knobs for reporting load data. type loadReportingOptions struct { loadStore *load.Store } // UpdateHandler receives and processes (by taking appropriate actions) xDS // resource updates from an APIClient for a specific version. type UpdateHandler interface { // NewListeners handles updates to xDS listener resources. NewListeners(map[string]ListenerUpdateErrTuple, UpdateMetadata) // NewRouteConfigs handles updates to xDS RouteConfiguration resources. NewRouteConfigs(map[string]RouteConfigUpdateErrTuple, UpdateMetadata) // NewClusters handles updates to xDS Cluster resources. NewClusters(map[string]ClusterUpdateErrTuple, UpdateMetadata) // NewEndpoints handles updates to xDS ClusterLoadAssignment (or tersely // referred to as Endpoints) resources. NewEndpoints(map[string]EndpointsUpdateErrTuple, UpdateMetadata) // NewConnectionError handles connection errors from the xDS stream. The // error will be reported to all the resource watchers. NewConnectionError(err error) } // ServiceStatus is the status of the update. type ServiceStatus int const ( // ServiceStatusUnknown is the default state, before a watch is started for // the resource. ServiceStatusUnknown ServiceStatus = iota // ServiceStatusRequested is when the watch is started, but before and // response is received. ServiceStatusRequested // ServiceStatusNotExist is when the resource doesn't exist in // state-of-the-world responses (e.g. LDS and CDS), which means the resource // is removed by the management server. ServiceStatusNotExist // Resource is removed in the server, in LDS/CDS. // ServiceStatusACKed is when the resource is ACKed. ServiceStatusACKed // ServiceStatusNACKed is when the resource is NACKed. ServiceStatusNACKed ) // UpdateErrorMetadata is part of UpdateMetadata. It contains the error state // when a response is NACKed. type UpdateErrorMetadata struct { // Version is the version of the NACKed response. Version string // Err contains why the response was NACKed. Err error // Timestamp is when the NACKed response was received. Timestamp time.Time } // UpdateMetadata contains the metadata for each update, including timestamp, // raw message, and so on. type UpdateMetadata struct { // Status is the status of this resource, e.g. ACKed, NACKed, or // Not_exist(removed). Status ServiceStatus // Version is the version of the xds response. Note that this is the version // of the resource in use (previous ACKed). If a response is NACKed, the // NACKed version is in ErrState. Version string // Timestamp is when the response is received. Timestamp time.Time // ErrState is set when the update is NACKed. ErrState *UpdateErrorMetadata } // ListenerUpdate contains information received in an LDS response, which is of // interest to the registered LDS watcher. type ListenerUpdate struct { // RouteConfigName is the route configuration name corresponding to the // target which is being watched through LDS. // // Only one of RouteConfigName and InlineRouteConfig is set. RouteConfigName string // InlineRouteConfig is the inline route configuration (RDS response) // returned inside LDS. // // Only one of RouteConfigName and InlineRouteConfig is set. InlineRouteConfig *RouteConfigUpdate // MaxStreamDuration contains the HTTP connection manager's // common_http_protocol_options.max_stream_duration field, or zero if // unset. MaxStreamDuration time.Duration // HTTPFilters is a list of HTTP filters (name, config) from the LDS // response. HTTPFilters []HTTPFilter // InboundListenerCfg contains inbound listener configuration. InboundListenerCfg *InboundListenerConfig // Raw is the resource from the xds response. Raw *anypb.Any } // HTTPFilter represents one HTTP filter from an LDS response's HTTP connection // manager field. type HTTPFilter struct { // Name is an arbitrary name of the filter. Used for applying override // settings in virtual host / route / weighted cluster configuration (not // yet supported). Name string // Filter is the HTTP filter found in the registry for the config type. Filter httpfilter.Filter // Config contains the filter's configuration Config httpfilter.FilterConfig } // InboundListenerConfig contains information about the inbound listener, i.e // the server-side listener. type InboundListenerConfig struct { // Address is the local address on which the inbound listener is expected to // accept incoming connections. Address string // Port is the local port on which the inbound listener is expected to // accept incoming connections. Port string // FilterChains is the list of filter chains associated with this listener. FilterChains *FilterChainManager } // RouteConfigUpdate contains information received in an RDS response, which is // of interest to the registered RDS watcher. type RouteConfigUpdate struct { VirtualHosts []*VirtualHost // Raw is the resource from the xds response. Raw *anypb.Any } // VirtualHost contains the routes for a list of Domains. // // Note that the domains in this slice can be a wildcard, not an exact string. // The consumer of this struct needs to find the best match for its hostname. type VirtualHost struct { Domains []string // Routes contains a list of routes, each containing matchers and // corresponding action. Routes []*Route // HTTPFilterConfigOverride contains any HTTP filter config overrides for // the virtual host which may be present. An individual filter's override // may be unused if the matching Route contains an override for that // filter. HTTPFilterConfigOverride map[string]httpfilter.FilterConfig RetryConfig *RetryConfig } // RetryConfig contains all retry-related configuration in either a VirtualHost // or Route. type RetryConfig struct { // RetryOn is a set of status codes on which to retry. Only Canceled, // DeadlineExceeded, Internal, ResourceExhausted, and Unavailable are // supported; any other values will be omitted. RetryOn map[codes.Code]bool NumRetries uint32 // maximum number of retry attempts RetryBackoff RetryBackoff // retry backoff policy } // RetryBackoff describes the backoff policy for retries. type RetryBackoff struct { BaseInterval time.Duration // initial backoff duration between attempts MaxInterval time.Duration // maximum backoff duration } // HashPolicyType specifies the type of HashPolicy from a received RDS Response. type HashPolicyType int const ( // HashPolicyTypeHeader specifies to hash a Header in the incoming request. HashPolicyTypeHeader HashPolicyType = iota // HashPolicyTypeChannelID specifies to hash a unique Identifier of the // Channel. In grpc-go, this will be done using the ClientConn pointer. HashPolicyTypeChannelID ) // HashPolicy specifies the HashPolicy if the upstream cluster uses a hashing // load balancer. type HashPolicy struct { HashPolicyType HashPolicyType Terminal bool // Fields used for type HEADER. HeaderName string Regex *regexp.Regexp RegexSubstitution string } // RouteAction is the action of the route from a received RDS response. type RouteAction int const ( // RouteActionUnsupported are routing types currently unsupported by grpc. // According to A36, "A Route with an inappropriate action causes RPCs // matching that route to fail." RouteActionUnsupported RouteAction = iota // RouteActionRoute is the expected route type on the client side. Route // represents routing a request to some upstream cluster. On the client // side, if an RPC matches to a route that is not RouteActionRoute, the RPC // will fail according to A36. RouteActionRoute // RouteActionNonForwardingAction is the expected route type on the server // side. NonForwardingAction represents when a route will generate a // response directly, without forwarding to an upstream host. RouteActionNonForwardingAction ) // Route is both a specification of how to match a request as well as an // indication of the action to take upon match. type Route struct { Path *string Prefix *string Regex *regexp.Regexp // Indicates if prefix/path matching should be case insensitive. The default // is false (case sensitive). CaseInsensitive bool Headers []*HeaderMatcher Fraction *uint32 HashPolicies []*HashPolicy // If the matchers above indicate a match, the below configuration is used. WeightedClusters map[string]WeightedCluster // If MaxStreamDuration is nil, it indicates neither of the route action's // max_stream_duration fields (grpc_timeout_header_max nor // max_stream_duration) were set. In this case, the ListenerUpdate's // MaxStreamDuration field should be used. If MaxStreamDuration is set to // an explicit zero duration, the application's deadline should be used. MaxStreamDuration *time.Duration // HTTPFilterConfigOverride contains any HTTP filter config overrides for // the route which may be present. An individual filter's override may be // unused if the matching WeightedCluster contains an override for that // filter. HTTPFilterConfigOverride map[string]httpfilter.FilterConfig RetryConfig *RetryConfig RouteAction RouteAction } // WeightedCluster contains settings for an xds RouteAction.WeightedCluster. type WeightedCluster struct { // Weight is the relative weight of the cluster. It will never be zero. Weight uint32 // HTTPFilterConfigOverride contains any HTTP filter config overrides for // the weighted cluster which may be present. HTTPFilterConfigOverride map[string]httpfilter.FilterConfig } // HeaderMatcher represents header matchers. type HeaderMatcher struct { Name string InvertMatch *bool ExactMatch *string RegexMatch *regexp.Regexp PrefixMatch *string SuffixMatch *string RangeMatch *Int64Range PresentMatch *bool } // Int64Range is a range for header range match. type Int64Range struct { Start int64 End int64 } // SecurityConfig contains the security configuration received as part of the // Cluster resource on the client-side, and as part of the Listener resource on // the server-side. type SecurityConfig struct { // RootInstanceName identifies the certProvider plugin to be used to fetch // root certificates. This instance name will be resolved to the plugin name // and its associated configuration from the certificate_providers field of // the bootstrap file. RootInstanceName string // RootCertName is the certificate name to be passed to the plugin (looked // up from the bootstrap file) while fetching root certificates. RootCertName string // IdentityInstanceName identifies the certProvider plugin to be used to // fetch identity certificates. This instance name will be resolved to the // plugin name and its associated configuration from the // certificate_providers field of the bootstrap file. IdentityInstanceName string // IdentityCertName is the certificate name to be passed to the plugin // (looked up from the bootstrap file) while fetching identity certificates. IdentityCertName string // SubjectAltNameMatchers is an optional list of match criteria for SANs // specified on the peer certificate. Used only on the client-side. // // Some intricacies: // - If this field is empty, then any peer certificate is accepted. // - If the peer certificate contains a wildcard DNS SAN, and an `exact` // matcher is configured, a wildcard DNS match is performed instead of a // regular string comparison. SubjectAltNameMatchers []matcher.StringMatcher // RequireClientCert indicates if the server handshake process expects the // client to present a certificate. Set to true when performing mTLS. Used // only on the server-side. RequireClientCert bool } // Equal returns true if sc is equal to other. func (sc *SecurityConfig) Equal(other *SecurityConfig) bool { switch { case sc == nil && other == nil: return true case (sc != nil) != (other != nil): return false } switch { case sc.RootInstanceName != other.RootInstanceName: return false case sc.RootCertName != other.RootCertName: return false case sc.IdentityInstanceName != other.IdentityInstanceName: return false case sc.IdentityCertName != other.IdentityCertName: return false case sc.RequireClientCert != other.RequireClientCert: return false default: if len(sc.SubjectAltNameMatchers) != len(other.SubjectAltNameMatchers) { return false } for i := 0; i < len(sc.SubjectAltNameMatchers); i++ { if !sc.SubjectAltNameMatchers[i].Equal(other.SubjectAltNameMatchers[i]) { return false } } } return true } // ClusterType is the type of cluster from a received CDS response. type ClusterType int const ( // ClusterTypeEDS represents the EDS cluster type, which will delegate endpoint // discovery to the management server. ClusterTypeEDS ClusterType = iota // ClusterTypeLogicalDNS represents the Logical DNS cluster type, which essentially // maps to the gRPC behavior of using the DNS resolver with pick_first LB policy. ClusterTypeLogicalDNS // ClusterTypeAggregate represents the Aggregate Cluster type, which provides a // prioritized list of clusters to use. It is used for failover between clusters // with a different configuration. ClusterTypeAggregate ) // ClusterLBPolicyRingHash represents ring_hash lb policy, and also contains its // config. type ClusterLBPolicyRingHash struct { MinimumRingSize uint64 MaximumRingSize uint64 } // ClusterUpdate contains information from a received CDS response, which is of // interest to the registered CDS watcher. type ClusterUpdate struct { ClusterType ClusterType // ClusterName is the clusterName being watched for through CDS. ClusterName string // EDSServiceName is an optional name for EDS. If it's not set, the balancer // should watch ClusterName for the EDS resources. EDSServiceName string // EnableLRS indicates whether or not load should be reported through LRS. EnableLRS bool // SecurityCfg contains security configuration sent by the control plane. SecurityCfg *SecurityConfig // MaxRequests for circuit breaking, if any (otherwise nil). MaxRequests *uint32 // DNSHostName is used only for cluster type DNS. It's the DNS name to // resolve in "host:port" form DNSHostName string // PrioritizedClusterNames is used only for cluster type aggregate. It represents // a prioritized list of cluster names. PrioritizedClusterNames []string // LBPolicy is the lb policy for this cluster. // // This only support round_robin and ring_hash. // - if it's nil, the lb policy is round_robin // - if it's not nil, the lb policy is ring_hash, the this field has the config. // // When we add more support policies, this can be made an interface, and // will be set to different types based on the policy type. LBPolicy *ClusterLBPolicyRingHash // Raw is the resource from the xds response. Raw *anypb.Any } // OverloadDropConfig contains the config to drop overloads. type OverloadDropConfig struct { Category string Numerator uint32 Denominator uint32 } // EndpointHealthStatus represents the health status of an endpoint. type EndpointHealthStatus int32 const ( // EndpointHealthStatusUnknown represents HealthStatus UNKNOWN. EndpointHealthStatusUnknown EndpointHealthStatus = iota // EndpointHealthStatusHealthy represents HealthStatus HEALTHY. EndpointHealthStatusHealthy // EndpointHealthStatusUnhealthy represents HealthStatus UNHEALTHY. EndpointHealthStatusUnhealthy // EndpointHealthStatusDraining represents HealthStatus DRAINING. EndpointHealthStatusDraining // EndpointHealthStatusTimeout represents HealthStatus TIMEOUT. EndpointHealthStatusTimeout // EndpointHealthStatusDegraded represents HealthStatus DEGRADED. EndpointHealthStatusDegraded ) // Endpoint contains information of an endpoint. type Endpoint struct { Address string HealthStatus EndpointHealthStatus Weight uint32 } // Locality contains information of a locality. type Locality struct { Endpoints []Endpoint ID internal.LocalityID Priority uint32 Weight uint32 } // EndpointsUpdate contains an EDS update. type EndpointsUpdate struct { Drops []OverloadDropConfig Localities []Locality // Raw is the resource from the xds response. Raw *anypb.Any } // Function to be overridden in tests. var newAPIClient = func(apiVersion version.TransportAPI, cc *grpc.ClientConn, opts BuildOptions) (APIClient, error) { cb := getAPIClientBuilder(apiVersion) if cb == nil { return nil, fmt.Errorf("no client builder for xDS API version: %v", apiVersion) } return cb.Build(cc, opts) } // clientImpl is the real implementation of the xds client. The exported Client // is a wrapper of this struct with a ref count. // // Implements UpdateHandler interface. // TODO(easwars): Make a wrapper struct which implements this interface in the // style of ccBalancerWrapper so that the Client type does not implement these // exported methods. type clientImpl struct { done *grpcsync.Event config *bootstrap.Config cc *grpc.ClientConn // Connection to the management server. apiClient APIClient watchExpiryTimeout time.Duration logger *grpclog.PrefixLogger updateCh *buffer.Unbounded // chan *watcherInfoWithUpdate // All the following maps are to keep the updates/metadata in a cache. // TODO: move them to a separate struct/package, to cleanup the xds_client. // And CSDS handler can be implemented directly by the cache. mu sync.Mutex ldsWatchers map[string]map[*watchInfo]bool ldsVersion string // Only used in CSDS. ldsCache map[string]ListenerUpdate ldsMD map[string]UpdateMetadata rdsWatchers map[string]map[*watchInfo]bool rdsVersion string // Only used in CSDS. rdsCache map[string]RouteConfigUpdate rdsMD map[string]UpdateMetadata cdsWatchers map[string]map[*watchInfo]bool cdsVersion string // Only used in CSDS. cdsCache map[string]ClusterUpdate cdsMD map[string]UpdateMetadata edsWatchers map[string]map[*watchInfo]bool edsVersion string // Only used in CSDS. edsCache map[string]EndpointsUpdate edsMD map[string]UpdateMetadata // Changes to map lrsClients and the lrsClient inside the map need to be // protected by lrsMu. lrsMu sync.Mutex lrsClients map[string]*lrsClient } // newWithConfig returns a new xdsClient with the given config. func newWithConfig(config *bootstrap.Config, watchExpiryTimeout time.Duration) (*clientImpl, error) { switch { case config.BalancerName == "": return nil, errors.New("xds: no xds_server name provided in options") case config.Creds == nil: return nil, errors.New("xds: no credentials provided in options") case config.NodeProto == nil: return nil, errors.New("xds: no node_proto provided in options") } switch config.TransportAPI { case version.TransportV2: if _, ok := config.NodeProto.(*v2corepb.Node); !ok { return nil, fmt.Errorf("xds: Node proto type (%T) does not match API version: %v", config.NodeProto, config.TransportAPI) } case version.TransportV3: if _, ok := config.NodeProto.(*v3corepb.Node); !ok { return nil, fmt.Errorf("xds: Node proto type (%T) does not match API version: %v", config.NodeProto, config.TransportAPI) } } dopts := []grpc.DialOption{ config.Creds, grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: 5 * time.Minute, Timeout: 20 * time.Second, }), } c := &clientImpl{ done: grpcsync.NewEvent(), config: config, watchExpiryTimeout: watchExpiryTimeout, updateCh: buffer.NewUnbounded(), ldsWatchers: make(map[string]map[*watchInfo]bool), ldsCache: make(map[string]ListenerUpdate), ldsMD: make(map[string]UpdateMetadata), rdsWatchers: make(map[string]map[*watchInfo]bool), rdsCache: make(map[string]RouteConfigUpdate), rdsMD: make(map[string]UpdateMetadata), cdsWatchers: make(map[string]map[*watchInfo]bool), cdsCache: make(map[string]ClusterUpdate), cdsMD: make(map[string]UpdateMetadata), edsWatchers: make(map[string]map[*watchInfo]bool), edsCache: make(map[string]EndpointsUpdate), edsMD: make(map[string]UpdateMetadata), lrsClients: make(map[string]*lrsClient), } cc, err := grpc.Dial(config.BalancerName, dopts...) if err != nil { // An error from a non-blocking dial indicates something serious. return nil, fmt.Errorf("xds: failed to dial balancer {%s}: %v", config.BalancerName, err) } c.cc = cc c.logger = prefixLogger((c)) c.logger.Infof("Created ClientConn to xDS management server: %s", config.BalancerName) apiClient, err := newAPIClient(config.TransportAPI, cc, BuildOptions{ Parent: c, Validator: c.updateValidator, NodeProto: config.NodeProto, Backoff: backoff.DefaultExponential.Backoff, Logger: c.logger, }) if err != nil { return nil, err } c.apiClient = apiClient c.logger.Infof("Created") go c.run() return c, nil } // BootstrapConfig returns the configuration read from the bootstrap file. // Callers must treat the return value as read-only. func (c *clientRefCounted) BootstrapConfig() *bootstrap.Config { return c.config } // run is a goroutine for all the callbacks. // // Callback can be called in watch(), if an item is found in cache. Without this // goroutine, the callback will be called inline, which might cause a deadlock // in user's code. Callbacks also cannot be simple `go callback()` because the // order matters. func (c *clientImpl) run() { for { select { case t := <-c.updateCh.Get(): c.updateCh.Load() if c.done.HasFired() { return } c.callCallback(t.(*watcherInfoWithUpdate)) case <-c.done.Done(): return } } } // Close closes the gRPC connection to the management server. func (c *clientImpl) Close() { if c.done.HasFired() { return } c.done.Fire() // TODO: Should we invoke the registered callbacks here with an error that // the client is closed? c.apiClient.Close() c.cc.Close() c.logger.Infof("Shutdown") } func (c *clientImpl) filterChainUpdateValidator(fc *FilterChain) error { if fc == nil { return nil } return c.securityConfigUpdateValidator(fc.SecurityCfg) } func (c *clientImpl) securityConfigUpdateValidator(sc *SecurityConfig) error { if sc == nil { return nil } if sc.IdentityInstanceName != "" { if _, ok := c.config.CertProviderConfigs[sc.IdentityInstanceName]; !ok { return fmt.Errorf("identitiy certificate provider instance name %q missing in bootstrap configuration", sc.IdentityInstanceName) } } if sc.RootInstanceName != "" { if _, ok := c.config.CertProviderConfigs[sc.RootInstanceName]; !ok { return fmt.Errorf("root certificate provider instance name %q missing in bootstrap configuration", sc.RootInstanceName) } } return nil } func (c *clientImpl) updateValidator(u interface{}) error { switch update := u.(type) { case ListenerUpdate: if update.InboundListenerCfg == nil || update.InboundListenerCfg.FilterChains == nil { return nil } fcm := update.InboundListenerCfg.FilterChains for _, dst := range fcm.dstPrefixMap { for _, srcType := range dst.srcTypeArr { if srcType == nil { continue } for _, src := range srcType.srcPrefixMap { for _, fc := range src.srcPortMap { if err := c.filterChainUpdateValidator(fc); err != nil { return err } } } } } return c.filterChainUpdateValidator(fcm.def) case ClusterUpdate: return c.securityConfigUpdateValidator(update.SecurityCfg) default: // We currently invoke this update validation function only for LDS and // CDS updates. In the future, if we wish to invoke it for other xDS // updates, corresponding plumbing needs to be added to those unmarshal // functions. } return nil } // ResourceType identifies resources in a transport protocol agnostic way. These // will be used in transport version agnostic code, while the versioned API // clients will map these to appropriate version URLs. type ResourceType int // Version agnostic resource type constants. const ( UnknownResource ResourceType = iota ListenerResource HTTPConnManagerResource RouteConfigResource ClusterResource EndpointsResource ) func (r ResourceType) String() string { switch r { case ListenerResource: return "ListenerResource" case HTTPConnManagerResource: return "HTTPConnManagerResource" case RouteConfigResource: return "RouteConfigResource" case ClusterResource: return "ClusterResource" case EndpointsResource: return "EndpointsResource" default: return "UnknownResource" } } // IsListenerResource returns true if the provider URL corresponds to an xDS // Listener resource. func IsListenerResource(url string) bool { return url == version.V2ListenerURL || url == version.V3ListenerURL } // IsHTTPConnManagerResource returns true if the provider URL corresponds to an xDS // HTTPConnManager resource. func IsHTTPConnManagerResource(url string) bool { return url == version.V2HTTPConnManagerURL || url == version.V3HTTPConnManagerURL } // IsRouteConfigResource returns true if the provider URL corresponds to an xDS // RouteConfig resource. func IsRouteConfigResource(url string) bool { return url == version.V2RouteConfigURL || url == version.V3RouteConfigURL } // IsClusterResource returns true if the provider URL corresponds to an xDS // Cluster resource. func IsClusterResource(url string) bool { return url == version.V2ClusterURL || url == version.V3ClusterURL } // IsEndpointsResource returns true if the provider URL corresponds to an xDS // Endpoints resource. func IsEndpointsResource(url string) bool { return url == version.V2EndpointsURL || url == version.V3EndpointsURL }