k8s.io/kubernetes@v1.29.3/pkg/kubelet/kuberuntime/labels.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package kuberuntime 18 19 import ( 20 "encoding/json" 21 "strconv" 22 23 v1 "k8s.io/api/core/v1" 24 kubetypes "k8s.io/apimachinery/pkg/types" 25 utilfeature "k8s.io/apiserver/pkg/util/feature" 26 "k8s.io/klog/v2" 27 "k8s.io/kubelet/pkg/types" 28 "k8s.io/kubernetes/pkg/features" 29 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container" 30 ) 31 32 const ( 33 // TODO: change those label names to follow kubernetes's format 34 podDeletionGracePeriodLabel = "io.kubernetes.pod.deletionGracePeriod" 35 podTerminationGracePeriodLabel = "io.kubernetes.pod.terminationGracePeriod" 36 37 containerHashLabel = "io.kubernetes.container.hash" 38 containerHashWithoutResourcesLabel = "io.kubernetes.container.hashWithoutResources" 39 containerRestartCountLabel = "io.kubernetes.container.restartCount" 40 containerTerminationMessagePathLabel = "io.kubernetes.container.terminationMessagePath" 41 containerTerminationMessagePolicyLabel = "io.kubernetes.container.terminationMessagePolicy" 42 containerPreStopHandlerLabel = "io.kubernetes.container.preStopHandler" 43 containerPortsLabel = "io.kubernetes.container.ports" 44 ) 45 46 type labeledPodSandboxInfo struct { 47 // Labels from v1.Pod 48 Labels map[string]string 49 PodName string 50 PodNamespace string 51 PodUID kubetypes.UID 52 } 53 54 type annotatedPodSandboxInfo struct { 55 // Annotations from v1.Pod 56 Annotations map[string]string 57 } 58 59 type labeledContainerInfo struct { 60 ContainerName string 61 PodName string 62 PodNamespace string 63 PodUID kubetypes.UID 64 } 65 66 type annotatedContainerInfo struct { 67 Hash uint64 68 HashWithoutResources uint64 69 RestartCount int 70 PodDeletionGracePeriod *int64 71 PodTerminationGracePeriod *int64 72 TerminationMessagePath string 73 TerminationMessagePolicy v1.TerminationMessagePolicy 74 PreStopHandler *v1.LifecycleHandler 75 ContainerPorts []v1.ContainerPort 76 } 77 78 // newPodLabels creates pod labels from v1.Pod. 79 func newPodLabels(pod *v1.Pod) map[string]string { 80 labels := map[string]string{} 81 82 // Get labels from v1.Pod 83 for k, v := range pod.Labels { 84 labels[k] = v 85 } 86 87 labels[types.KubernetesPodNameLabel] = pod.Name 88 labels[types.KubernetesPodNamespaceLabel] = pod.Namespace 89 labels[types.KubernetesPodUIDLabel] = string(pod.UID) 90 91 return labels 92 } 93 94 // newPodAnnotations creates pod annotations from v1.Pod. 95 func newPodAnnotations(pod *v1.Pod) map[string]string { 96 return pod.Annotations 97 } 98 99 // newContainerLabels creates container labels from v1.Container and v1.Pod. 100 func newContainerLabels(container *v1.Container, pod *v1.Pod) map[string]string { 101 labels := map[string]string{} 102 labels[types.KubernetesPodNameLabel] = pod.Name 103 labels[types.KubernetesPodNamespaceLabel] = pod.Namespace 104 labels[types.KubernetesPodUIDLabel] = string(pod.UID) 105 labels[types.KubernetesContainerNameLabel] = container.Name 106 107 return labels 108 } 109 110 // newContainerAnnotations creates container annotations from v1.Container and v1.Pod. 111 func newContainerAnnotations(container *v1.Container, pod *v1.Pod, restartCount int, opts *kubecontainer.RunContainerOptions) map[string]string { 112 annotations := map[string]string{} 113 114 // Kubelet always overrides device plugin annotations if they are conflicting 115 for _, a := range opts.Annotations { 116 annotations[a.Name] = a.Value 117 } 118 119 annotations[containerHashLabel] = strconv.FormatUint(kubecontainer.HashContainer(container), 16) 120 if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) { 121 annotations[containerHashWithoutResourcesLabel] = strconv.FormatUint(kubecontainer.HashContainerWithoutResources(container), 16) 122 } 123 annotations[containerRestartCountLabel] = strconv.Itoa(restartCount) 124 annotations[containerTerminationMessagePathLabel] = container.TerminationMessagePath 125 annotations[containerTerminationMessagePolicyLabel] = string(container.TerminationMessagePolicy) 126 127 if pod.DeletionGracePeriodSeconds != nil { 128 annotations[podDeletionGracePeriodLabel] = strconv.FormatInt(*pod.DeletionGracePeriodSeconds, 10) 129 } 130 if pod.Spec.TerminationGracePeriodSeconds != nil { 131 annotations[podTerminationGracePeriodLabel] = strconv.FormatInt(*pod.Spec.TerminationGracePeriodSeconds, 10) 132 } 133 134 if container.Lifecycle != nil && container.Lifecycle.PreStop != nil { 135 // Using json encoding so that the PreStop handler object is readable after writing as a label 136 rawPreStop, err := json.Marshal(container.Lifecycle.PreStop) 137 if err != nil { 138 klog.ErrorS(err, "Unable to marshal lifecycle PreStop handler for container", "containerName", container.Name, "pod", klog.KObj(pod)) 139 } else { 140 annotations[containerPreStopHandlerLabel] = string(rawPreStop) 141 } 142 } 143 144 if len(container.Ports) > 0 { 145 rawContainerPorts, err := json.Marshal(container.Ports) 146 if err != nil { 147 klog.ErrorS(err, "Unable to marshal container ports for container", "containerName", container.Name, "pod", klog.KObj(pod)) 148 } else { 149 annotations[containerPortsLabel] = string(rawContainerPorts) 150 } 151 } 152 153 return annotations 154 } 155 156 // getPodSandboxInfoFromLabels gets labeledPodSandboxInfo from labels. 157 func getPodSandboxInfoFromLabels(labels map[string]string) *labeledPodSandboxInfo { 158 podSandboxInfo := &labeledPodSandboxInfo{ 159 Labels: make(map[string]string), 160 PodName: getStringValueFromLabel(labels, types.KubernetesPodNameLabel), 161 PodNamespace: getStringValueFromLabel(labels, types.KubernetesPodNamespaceLabel), 162 PodUID: kubetypes.UID(getStringValueFromLabel(labels, types.KubernetesPodUIDLabel)), 163 } 164 165 // Remain only labels from v1.Pod 166 for k, v := range labels { 167 if k != types.KubernetesPodNameLabel && k != types.KubernetesPodNamespaceLabel && k != types.KubernetesPodUIDLabel { 168 podSandboxInfo.Labels[k] = v 169 } 170 } 171 172 return podSandboxInfo 173 } 174 175 // getPodSandboxInfoFromAnnotations gets annotatedPodSandboxInfo from annotations. 176 func getPodSandboxInfoFromAnnotations(annotations map[string]string) *annotatedPodSandboxInfo { 177 return &annotatedPodSandboxInfo{ 178 Annotations: annotations, 179 } 180 } 181 182 // getContainerInfoFromLabels gets labeledContainerInfo from labels. 183 func getContainerInfoFromLabels(labels map[string]string) *labeledContainerInfo { 184 return &labeledContainerInfo{ 185 PodName: getStringValueFromLabel(labels, types.KubernetesPodNameLabel), 186 PodNamespace: getStringValueFromLabel(labels, types.KubernetesPodNamespaceLabel), 187 PodUID: kubetypes.UID(getStringValueFromLabel(labels, types.KubernetesPodUIDLabel)), 188 ContainerName: getStringValueFromLabel(labels, types.KubernetesContainerNameLabel), 189 } 190 } 191 192 // getContainerInfoFromAnnotations gets annotatedContainerInfo from annotations. 193 func getContainerInfoFromAnnotations(annotations map[string]string) *annotatedContainerInfo { 194 var err error 195 containerInfo := &annotatedContainerInfo{ 196 TerminationMessagePath: getStringValueFromLabel(annotations, containerTerminationMessagePathLabel), 197 TerminationMessagePolicy: v1.TerminationMessagePolicy(getStringValueFromLabel(annotations, containerTerminationMessagePolicyLabel)), 198 } 199 200 if containerInfo.Hash, err = getUint64ValueFromLabel(annotations, containerHashLabel); err != nil { 201 klog.ErrorS(err, "Unable to get label value from annotations", "label", containerHashLabel, "annotations", annotations) 202 } 203 if utilfeature.DefaultFeatureGate.Enabled(features.InPlacePodVerticalScaling) { 204 if containerInfo.HashWithoutResources, err = getUint64ValueFromLabel(annotations, containerHashWithoutResourcesLabel); err != nil { 205 klog.ErrorS(err, "Unable to get label value from annotations", "label", containerHashWithoutResourcesLabel, "annotations", annotations) 206 } 207 } 208 if containerInfo.RestartCount, err = getIntValueFromLabel(annotations, containerRestartCountLabel); err != nil { 209 klog.ErrorS(err, "Unable to get label value from annotations", "label", containerRestartCountLabel, "annotations", annotations) 210 } 211 if containerInfo.PodDeletionGracePeriod, err = getInt64PointerFromLabel(annotations, podDeletionGracePeriodLabel); err != nil { 212 klog.ErrorS(err, "Unable to get label value from annotations", "label", podDeletionGracePeriodLabel, "annotations", annotations) 213 } 214 if containerInfo.PodTerminationGracePeriod, err = getInt64PointerFromLabel(annotations, podTerminationGracePeriodLabel); err != nil { 215 klog.ErrorS(err, "Unable to get label value from annotations", "label", podTerminationGracePeriodLabel, "annotations", annotations) 216 } 217 218 preStopHandler := &v1.LifecycleHandler{} 219 if found, err := getJSONObjectFromLabel(annotations, containerPreStopHandlerLabel, preStopHandler); err != nil { 220 klog.ErrorS(err, "Unable to get label value from annotations", "label", containerPreStopHandlerLabel, "annotations", annotations) 221 } else if found { 222 containerInfo.PreStopHandler = preStopHandler 223 } 224 225 containerPorts := []v1.ContainerPort{} 226 if found, err := getJSONObjectFromLabel(annotations, containerPortsLabel, &containerPorts); err != nil { 227 klog.ErrorS(err, "Unable to get label value from annotations", "label", containerPortsLabel, "annotations", annotations) 228 } else if found { 229 containerInfo.ContainerPorts = containerPorts 230 } 231 232 return containerInfo 233 } 234 235 func getStringValueFromLabel(labels map[string]string, label string) string { 236 if value, found := labels[label]; found { 237 return value 238 } 239 // Do not report error, because there should be many old containers without label now. 240 klog.V(3).InfoS("Container doesn't have requested label, it may be an old or invalid container", "label", label) 241 // Return empty string "" for these containers, the caller will get value by other ways. 242 return "" 243 } 244 245 func getIntValueFromLabel(labels map[string]string, label string) (int, error) { 246 if strValue, found := labels[label]; found { 247 intValue, err := strconv.Atoi(strValue) 248 if err != nil { 249 // This really should not happen. Just set value to 0 to handle this abnormal case 250 return 0, err 251 } 252 return intValue, nil 253 } 254 // Do not report error, because there should be many old containers without label now. 255 klog.V(3).InfoS("Container doesn't have requested label, it may be an old or invalid container", "label", label) 256 // Just set the value to 0 257 return 0, nil 258 } 259 260 func getUint64ValueFromLabel(labels map[string]string, label string) (uint64, error) { 261 if strValue, found := labels[label]; found { 262 intValue, err := strconv.ParseUint(strValue, 16, 64) 263 if err != nil { 264 // This really should not happen. Just set value to 0 to handle this abnormal case 265 return 0, err 266 } 267 return intValue, nil 268 } 269 // Do not report error, because there should be many old containers without label now. 270 klog.V(3).InfoS("Container doesn't have requested label, it may be an old or invalid container", "label", label) 271 // Just set the value to 0 272 return 0, nil 273 } 274 275 func getInt64PointerFromLabel(labels map[string]string, label string) (*int64, error) { 276 if strValue, found := labels[label]; found { 277 int64Value, err := strconv.ParseInt(strValue, 10, 64) 278 if err != nil { 279 return nil, err 280 } 281 return &int64Value, nil 282 } 283 // If the label is not found, return pointer nil. 284 return nil, nil 285 } 286 287 // getJSONObjectFromLabel returns a bool value indicating whether an object is found. 288 func getJSONObjectFromLabel(labels map[string]string, label string, value interface{}) (bool, error) { 289 if strValue, found := labels[label]; found { 290 err := json.Unmarshal([]byte(strValue), value) 291 return found, err 292 } 293 // If the label is not found, return not found. 294 return false, nil 295 }