istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/config/analysis/analyzers/util/in_mesh.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 util
    16  
    17  import (
    18  	appsv1 "k8s.io/api/apps/v1"
    19  	v1 "k8s.io/api/core/v1"
    20  
    21  	"istio.io/api/label"
    22  	"istio.io/istio/pkg/config/analysis"
    23  	"istio.io/istio/pkg/config/constants"
    24  	"istio.io/istio/pkg/config/resource"
    25  	"istio.io/istio/pkg/config/schema/gvk"
    26  	"istio.io/istio/pkg/slices"
    27  )
    28  
    29  // DeploymentInMesh returns true if deployment is in the service mesh (has sidecar)
    30  func DeploymentInMesh(r *resource.Instance, c analysis.Context) bool {
    31  	d := r.Message.(*appsv1.DeploymentSpec)
    32  	return inMesh(d.Template.Annotations, d.Template.Labels,
    33  		resource.Namespace(r.Metadata.FullName.Namespace.String()), d.Template.Spec.Containers, c)
    34  }
    35  
    36  // PodInMesh returns true if a Pod is in the service mesh (has sidecar)
    37  func PodInMesh(r *resource.Instance, c analysis.Context) bool {
    38  	p := r.Message.(*v1.PodSpec)
    39  	return inMesh(r.Metadata.Annotations, r.Metadata.Labels,
    40  		r.Metadata.FullName.Namespace, append(slices.Clone(p.Containers), p.InitContainers...), c)
    41  }
    42  
    43  // PodInAmbientMode returns true if a Pod is in the service mesh with the ambient mode
    44  func PodInAmbientMode(r *resource.Instance) bool {
    45  	if r == nil {
    46  		return false
    47  	}
    48  
    49  	return r.Metadata.Annotations[constants.AmbientRedirection] == constants.AmbientRedirectionEnabled
    50  }
    51  
    52  // NamespaceInAmbientMode returns true if a Namespace is configured as a ambient namespace.
    53  func NamespaceInAmbientMode(r *resource.Instance) bool {
    54  	if r == nil {
    55  		return false
    56  	}
    57  	// If there is a sidecar injection label, then we assume the namespace is not in ambient mode
    58  	if r.Metadata.Labels[InjectionLabelName] == InjectionLabelEnableValue {
    59  		return false
    60  	}
    61  	if v, ok := r.Metadata.Labels[label.IoIstioRev.Name]; ok && v != "" {
    62  		return false
    63  	}
    64  	return r.Metadata.Labels[constants.DataplaneModeLabel] == constants.DataplaneModeAmbient
    65  }
    66  
    67  func inMesh(annos, labels map[string]string, namespace resource.Namespace, containers []v1.Container, c analysis.Context) bool {
    68  	// If pod has the sidecar container set, then, the pod is in the mesh
    69  	if hasIstioProxy(containers) {
    70  		return true
    71  	}
    72  
    73  	// If Pod has labels, return the injection label value
    74  	if piv, ok := getPodSidecarInjectionStatus(labels); ok {
    75  		return piv
    76  	}
    77  
    78  	// If Pod has annotation, return the injection annotation value
    79  	if piv, ok := getPodSidecarInjectionStatus(annos); ok {
    80  		return piv
    81  	}
    82  
    83  	// In case the annotation is not present but there is a auto-injection label on the namespace,
    84  	// return the auto-injection label status
    85  	if niv, nivok := getNamesSidecarInjectionStatus(namespace, c); nivok {
    86  		return niv
    87  	}
    88  
    89  	return false
    90  }
    91  
    92  // getPodSidecarInjectionStatus returns two booleans: enabled and ok.
    93  // enabled is true when deployment d PodSpec has either the label/annotation 'sidecar.istio.io/inject: "true"'
    94  // ok is true when the PodSpec doesn't have the 'sidecar.istio.io/inject' label/annotation present.
    95  func getPodSidecarInjectionStatus(metadata map[string]string) (enabled bool, ok bool) {
    96  	v, ok := metadata[label.SidecarInject.Name]
    97  	return v == "true", ok
    98  }
    99  
   100  // autoInjectionEnabled returns two booleans: enabled and ok.
   101  // enabled is true when namespace ns has 'istio-injection' label set to 'enabled'
   102  // ok is true when the namespace doesn't have the label 'istio-injection'
   103  func getNamesSidecarInjectionStatus(ns resource.Namespace, c analysis.Context) (enabled bool, ok bool) {
   104  	enabled, ok = false, false
   105  
   106  	namespace := c.Find(gvk.Namespace, resource.NewFullName("", resource.LocalName(ns)))
   107  	if namespace != nil {
   108  		enabled, ok = namespace.Metadata.Labels[InjectionLabelName] == InjectionLabelEnableValue, true
   109  	}
   110  
   111  	return enabled, ok
   112  }
   113  
   114  func hasIstioProxy(containers []v1.Container) bool {
   115  	proxyImage := ""
   116  	for _, container := range containers {
   117  		if container.Name == IstioProxyName {
   118  			proxyImage = container.Image
   119  			break
   120  		}
   121  	}
   122  
   123  	return proxyImage != ""
   124  }