istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/xds/cds.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package xds
    16  
    17  import (
    18  	"istio.io/istio/pilot/pkg/features"
    19  	"istio.io/istio/pilot/pkg/model"
    20  	"istio.io/istio/pilot/pkg/networking/core"
    21  	"istio.io/istio/pkg/config/schema/kind"
    22  	"istio.io/istio/pkg/jwt"
    23  	"istio.io/istio/pkg/util/sets"
    24  )
    25  
    26  type CdsGenerator struct {
    27  	ConfigGenerator core.ConfigGenerator
    28  }
    29  
    30  var _ model.XdsDeltaResourceGenerator = &CdsGenerator{}
    31  
    32  // Map of all configs that do not impact CDS
    33  var skippedCdsConfigs = sets.New(
    34  	kind.Gateway,
    35  	kind.WorkloadEntry,
    36  	kind.WorkloadGroup,
    37  	kind.AuthorizationPolicy,
    38  	kind.RequestAuthentication,
    39  	kind.Secret,
    40  	kind.Telemetry,
    41  	kind.WasmPlugin,
    42  	kind.ProxyConfig,
    43  	kind.DNSName,
    44  
    45  	kind.KubernetesGateway,
    46  )
    47  
    48  // Map all configs that impact CDS for gateways when `PILOT_FILTER_GATEWAY_CLUSTER_CONFIG = true`.
    49  var pushCdsGatewayConfig = func() sets.Set[kind.Kind] {
    50  	s := sets.New(
    51  		kind.VirtualService,
    52  		kind.Gateway,
    53  
    54  		kind.KubernetesGateway,
    55  		kind.HTTPRoute,
    56  		kind.TCPRoute,
    57  		kind.TLSRoute,
    58  		kind.GRPCRoute,
    59  	)
    60  	if features.JwksFetchMode != jwt.Istiod {
    61  		s.Insert(kind.RequestAuthentication)
    62  	}
    63  	return s
    64  }()
    65  
    66  func cdsNeedsPush(req *model.PushRequest, proxy *model.Proxy) bool {
    67  	if req == nil {
    68  		return true
    69  	}
    70  	switch proxy.Type {
    71  	case model.Waypoint:
    72  		if model.HasConfigsOfKind(req.ConfigsUpdated, kind.Address) {
    73  			// TODO: this logic is identical to that used in LDS, consider refactor into a common function
    74  			// taken directly from LDS... waypoints need CDS updates on kind.Address changes
    75  			// after implementing use-waypoint which decouples waypoint creation, wl pod creation
    76  			// user specifying waypoint use. Without this we're not getting correct waypoint config
    77  			// in a timely manner
    78  			return true
    79  		}
    80  		// Otherwise, only handle full pushes (skip endpoint-only updates)
    81  		if !req.Full {
    82  			return false
    83  		}
    84  	default:
    85  		if !req.Full {
    86  			// CDS only handles full push
    87  			return false
    88  		}
    89  	}
    90  	// If none set, we will always push
    91  	if len(req.ConfigsUpdated) == 0 {
    92  		return true
    93  	}
    94  
    95  	checkGateway := false
    96  	for config := range req.ConfigsUpdated {
    97  		if proxy.Type == model.Router {
    98  			if features.FilterGatewayClusterConfig {
    99  				if _, f := pushCdsGatewayConfig[config.Kind]; f {
   100  					return true
   101  				}
   102  			}
   103  			if config.Kind == kind.Gateway {
   104  				// Do the check outside of the loop since its slow; just trigger we need it
   105  				checkGateway = true
   106  			}
   107  		}
   108  
   109  		if _, f := skippedCdsConfigs[config.Kind]; !f {
   110  			return true
   111  		}
   112  	}
   113  	if checkGateway {
   114  		autoPassthroughModeChanged := proxy.MergedGateway.HasAutoPassthroughGateways() != proxy.PrevMergedGateway.HasAutoPassthroughGateway()
   115  		autoPassthroughHostsChanged := !proxy.MergedGateway.GetAutoPassthrughGatewaySNIHosts().Equals(proxy.PrevMergedGateway.GetAutoPassthroughSNIHosts())
   116  		if autoPassthroughModeChanged || autoPassthroughHostsChanged {
   117  			return true
   118  		}
   119  	}
   120  	return false
   121  }
   122  
   123  func (c CdsGenerator) Generate(proxy *model.Proxy, w *model.WatchedResource, req *model.PushRequest) (model.Resources, model.XdsLogDetails, error) {
   124  	if !cdsNeedsPush(req, proxy) {
   125  		return nil, model.DefaultXdsLogDetails, nil
   126  	}
   127  	clusters, logs := c.ConfigGenerator.BuildClusters(proxy, req)
   128  	return clusters, logs, nil
   129  }
   130  
   131  // GenerateDeltas for CDS currently only builds deltas when services change. todo implement changes for DestinationRule, etc
   132  func (c CdsGenerator) GenerateDeltas(proxy *model.Proxy, req *model.PushRequest,
   133  	w *model.WatchedResource,
   134  ) (model.Resources, model.DeletedResources, model.XdsLogDetails, bool, error) {
   135  	if !cdsNeedsPush(req, proxy) {
   136  		return nil, nil, model.DefaultXdsLogDetails, false, nil
   137  	}
   138  	updatedClusters, removedClusters, logs, usedDelta := c.ConfigGenerator.BuildDeltaClusters(proxy, req, w)
   139  	return updatedClusters, removedClusters, logs, usedDelta, nil
   140  }