istio.io/istio@v0.0.0-20240520182934-d79c90f27776/cni/pkg/util/podutil.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 "context" 19 "fmt" 20 "net/netip" 21 22 corev1 "k8s.io/api/core/v1" 23 "k8s.io/apimachinery/pkg/api/errors" 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 "k8s.io/apimachinery/pkg/types" 26 "k8s.io/client-go/kubernetes" 27 28 "istio.io/api/annotation" 29 "istio.io/istio/pkg/config/constants" 30 ) 31 32 var annotationPatch = []byte(fmt.Sprintf( 33 `{"metadata":{"annotations":{"%s":"%s"}}}`, 34 constants.AmbientRedirection, 35 constants.AmbientRedirectionEnabled, 36 )) 37 38 var annotationRemovePatch = []byte(fmt.Sprintf( 39 `{"metadata":{"annotations":{"%s":null}}}`, 40 constants.AmbientRedirection, 41 )) 42 43 // PodRedirectionEnabled determines if a pod should or should not be configured 44 // to have traffic redirected thru the node proxy. 45 func PodRedirectionEnabled(namespace *corev1.Namespace, pod *corev1.Pod) bool { 46 if !(namespace.GetLabels()[constants.DataplaneModeLabel] == constants.DataplaneModeAmbient || 47 pod.GetLabels()[constants.DataplaneModeLabel] == constants.DataplaneModeAmbient) { 48 // Neither namespace nor pod has ambient mode enabled 49 return false 50 } 51 if podHasSidecar(pod) { 52 // Ztunnel and sidecar for a single pod is currently not supported; opt out. 53 return false 54 } 55 if pod.GetLabels()[constants.DataplaneModeLabel] == constants.DataplaneModeNone { 56 // Pod explicitly asked to not have ambient redirection enabled 57 return false 58 } 59 return true 60 } 61 62 func podHasSidecar(pod *corev1.Pod) bool { 63 if _, f := pod.GetAnnotations()[annotation.SidecarStatus.Name]; f { 64 return true 65 } 66 return false 67 } 68 69 func IsZtunnelPod(systemNs string, pod *corev1.Pod) bool { 70 return pod.Namespace == systemNs && pod.GetLabels()["app"] == "ztunnel" 71 } 72 73 func AnnotateEnrolledPod(client kubernetes.Interface, pod *metav1.ObjectMeta) error { 74 _, err := client.CoreV1(). 75 Pods(pod.Namespace). 76 Patch( 77 context.Background(), 78 pod.Name, 79 types.MergePatchType, 80 annotationPatch, 81 metav1.PatchOptions{}, 82 // Both "pods" and "pods/status" can mutate the metadata. However, pods/status is lower privilege, so we use that instead. 83 "status", 84 ) 85 return err 86 } 87 88 func AnnotateUnenrollPod(client kubernetes.Interface, pod *metav1.ObjectMeta) error { 89 if pod.Annotations[constants.AmbientRedirection] != constants.AmbientRedirectionEnabled { 90 return nil 91 } 92 // TODO: do not overwrite if already none 93 _, err := client.CoreV1(). 94 Pods(pod.Namespace). 95 Patch( 96 context.Background(), 97 pod.Name, 98 types.MergePatchType, 99 annotationRemovePatch, 100 metav1.PatchOptions{}, 101 // Both "pods" and "pods/status" can mutate the metadata. However, pods/status is lower privilege, so we use that instead. 102 "status", 103 ) 104 if errors.IsNotFound(err) { 105 return nil 106 } 107 return err 108 } 109 110 // Get any IPs currently assigned to the Pod. 111 // 112 // If 'PodIPs' exists, it is preferred (and should be guaranteed to contain the address in 'PodIP'), 113 // otherwise fallback to 'PodIP'. 114 // 115 // Note that very early in the pod's lifecycle (before all the node CNI plugin invocations finish) 116 // K8S may not have received the pod IPs yet, and may not report the pod as having any. 117 func GetPodIPsIfPresent(pod *corev1.Pod) []netip.Addr { 118 var podIPs []netip.Addr 119 if len(pod.Status.PodIPs) != 0 { 120 for _, pip := range pod.Status.PodIPs { 121 ip := netip.MustParseAddr(pip.IP) 122 podIPs = append(podIPs, ip) 123 } 124 } else if len(pod.Status.PodIP) != 0 { 125 ip := netip.MustParseAddr(pod.Status.PodIP) 126 podIPs = append(podIPs, ip) 127 } 128 return podIPs 129 }