istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/proxy_config.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 model
    16  
    17  import (
    18  	"istio.io/api/annotation"
    19  	meshconfig "istio.io/api/mesh/v1alpha1"
    20  	"istio.io/api/networking/v1beta1"
    21  	"istio.io/istio/pkg/config/labels"
    22  	"istio.io/istio/pkg/config/mesh"
    23  	"istio.io/istio/pkg/config/schema/gvk"
    24  	"istio.io/istio/pkg/util/protomarshal"
    25  )
    26  
    27  // ProxyConfigs organizes ProxyConfig configuration by namespace.
    28  type ProxyConfigs struct {
    29  	// namespaceToProxyConfigs
    30  	namespaceToProxyConfigs map[string][]*v1beta1.ProxyConfig
    31  
    32  	// root namespace
    33  	rootNamespace string
    34  }
    35  
    36  // EffectiveProxyConfig generates the correct merged ProxyConfig for a given ProxyConfigTarget.
    37  func (p *ProxyConfigs) EffectiveProxyConfig(meta *NodeMetadata, mc *meshconfig.MeshConfig) *meshconfig.ProxyConfig {
    38  	if p == nil || meta == nil {
    39  		return nil
    40  	}
    41  
    42  	effectiveProxyConfig := mesh.DefaultProxyConfig()
    43  
    44  	// Merge the proxy config from default config.
    45  	effectiveProxyConfig = mergeWithPrecedence(mc.GetDefaultConfig(), effectiveProxyConfig)
    46  	if p.rootNamespace != "" {
    47  		effectiveProxyConfig = mergeWithPrecedence(p.mergedGlobalConfig(), effectiveProxyConfig)
    48  	}
    49  
    50  	if meta.Namespace != p.rootNamespace {
    51  		namespacedConfig := p.mergedNamespaceConfig(meta.Namespace)
    52  		effectiveProxyConfig = mergeWithPrecedence(namespacedConfig, effectiveProxyConfig)
    53  	}
    54  
    55  	workloadConfig := p.mergedWorkloadConfig(meta.Namespace, meta.Labels)
    56  
    57  	// Check for proxy.istio.io/config annotation and merge it with lower priority than the
    58  	// workload-matching ProxyConfig CRs.
    59  	if v, ok := meta.Annotations[annotation.ProxyConfig.Name]; ok {
    60  		pca, err := proxyConfigFromAnnotation(v)
    61  		if err == nil {
    62  			workloadConfig = mergeWithPrecedence(workloadConfig, pca)
    63  		}
    64  	}
    65  	effectiveProxyConfig = mergeWithPrecedence(workloadConfig, effectiveProxyConfig)
    66  
    67  	return effectiveProxyConfig
    68  }
    69  
    70  func GetProxyConfigs(store ConfigStore, mc *meshconfig.MeshConfig) *ProxyConfigs {
    71  	proxyconfigs := &ProxyConfigs{
    72  		namespaceToProxyConfigs: map[string][]*v1beta1.ProxyConfig{},
    73  		rootNamespace:           mc.GetRootNamespace(),
    74  	}
    75  	resources := store.List(gvk.ProxyConfig, NamespaceAll)
    76  	sortConfigByCreationTime(resources)
    77  	ns := proxyconfigs.namespaceToProxyConfigs
    78  	for _, resource := range resources {
    79  		ns[resource.Namespace] = append(ns[resource.Namespace], resource.Spec.(*v1beta1.ProxyConfig))
    80  	}
    81  	return proxyconfigs
    82  }
    83  
    84  func (p *ProxyConfigs) mergedGlobalConfig() *meshconfig.ProxyConfig {
    85  	return p.mergedNamespaceConfig(p.rootNamespace)
    86  }
    87  
    88  // mergedNamespaceConfig merges ProxyConfig resources matching the given namespace.
    89  func (p *ProxyConfigs) mergedNamespaceConfig(namespace string) *meshconfig.ProxyConfig {
    90  	for _, pc := range p.namespaceToProxyConfigs[namespace] {
    91  		if pc.GetSelector() == nil {
    92  			// return the first match. this is consistent since
    93  			// we sort the resources by creation time beforehand.
    94  			return toMeshConfigProxyConfig(pc)
    95  		}
    96  	}
    97  	return nil
    98  }
    99  
   100  // mergedWorkloadConfig merges ProxyConfig resources matching the given namespace and labels.
   101  func (p *ProxyConfigs) mergedWorkloadConfig(namespace string, l map[string]string) *meshconfig.ProxyConfig {
   102  	for _, pc := range p.namespaceToProxyConfigs[namespace] {
   103  		if len(pc.GetSelector().GetMatchLabels()) == 0 {
   104  			continue
   105  		}
   106  		selector := labels.Instance(pc.GetSelector().GetMatchLabels())
   107  		if selector.SubsetOf(l) {
   108  			// return the first match. this is consistent since
   109  			// we sort the resources by creation time beforehand.
   110  			return toMeshConfigProxyConfig(pc)
   111  		}
   112  	}
   113  	return nil
   114  }
   115  
   116  // mergeWithPrecedence merges the ProxyConfigs together with earlier items having
   117  // the highest priority.
   118  func mergeWithPrecedence(pcs ...*meshconfig.ProxyConfig) *meshconfig.ProxyConfig {
   119  	merged := &meshconfig.ProxyConfig{}
   120  	for i := len(pcs) - 1; i >= 0; i-- {
   121  		if pcs[i] == nil {
   122  			continue
   123  		}
   124  		proxyConfigYaml, err := protomarshal.ToYAML(pcs[i])
   125  		if err != nil {
   126  			continue
   127  		}
   128  		mergedConfig, err := mesh.MergeProxyConfig(proxyConfigYaml, merged)
   129  		if err == nil {
   130  			continue
   131  		}
   132  		merged = mergedConfig
   133  	}
   134  	return merged
   135  }
   136  
   137  func toMeshConfigProxyConfig(pc *v1beta1.ProxyConfig) *meshconfig.ProxyConfig {
   138  	mcpc := &meshconfig.ProxyConfig{}
   139  	if pc.Concurrency != nil {
   140  		mcpc.Concurrency = pc.Concurrency
   141  	}
   142  	if pc.EnvironmentVariables != nil {
   143  		mcpc.ProxyMetadata = pc.EnvironmentVariables
   144  	}
   145  	if pc.Image != nil {
   146  		mcpc.Image = pc.Image
   147  	}
   148  	return mcpc
   149  }
   150  
   151  func proxyConfigFromAnnotation(pcAnnotation string) (*meshconfig.ProxyConfig, error) {
   152  	pc := &meshconfig.ProxyConfig{}
   153  	if err := protomarshal.ApplyYAML(pcAnnotation, pc); err != nil {
   154  		return nil, err
   155  	}
   156  	return pc, nil
   157  }