k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/pkg/kubelet/config/common.go (about) 1 /* 2 Copyright 2014 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 config 18 19 import ( 20 "crypto/md5" 21 "encoding/hex" 22 "errors" 23 "fmt" 24 "strings" 25 26 v1 "k8s.io/api/core/v1" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/runtime" 29 "k8s.io/apimachinery/pkg/types" 30 utilyaml "k8s.io/apimachinery/pkg/util/yaml" 31 api "k8s.io/kubernetes/pkg/apis/core" 32 "k8s.io/kubernetes/pkg/apis/core/helper" 33 34 // TODO: remove this import if 35 // api.Registry.GroupOrDie(v1.GroupName).GroupVersion.String() is changed 36 // to "v1"? 37 "k8s.io/kubernetes/pkg/api/legacyscheme" 38 // Ensure that core apis are installed 39 _ "k8s.io/kubernetes/pkg/apis/core/install" 40 k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1" 41 "k8s.io/kubernetes/pkg/apis/core/validation" 42 kubetypes "k8s.io/kubernetes/pkg/kubelet/types" 43 "k8s.io/kubernetes/pkg/util/hash" 44 45 "k8s.io/klog/v2" 46 ) 47 48 const ( 49 maxConfigLength = 10 * 1 << 20 // 10MB 50 ) 51 52 // Generate a pod name that is unique among nodes by appending the nodeName. 53 func generatePodName(name string, nodeName types.NodeName) string { 54 return fmt.Sprintf("%s-%s", name, strings.ToLower(string(nodeName))) 55 } 56 57 func applyDefaults(pod *api.Pod, source string, isFile bool, nodeName types.NodeName) error { 58 if len(pod.UID) == 0 { 59 hasher := md5.New() 60 hash.DeepHashObject(hasher, pod) 61 // DeepHashObject resets the hash, so we should write the pod source 62 // information AFTER it. 63 if isFile { 64 fmt.Fprintf(hasher, "host:%s", nodeName) 65 fmt.Fprintf(hasher, "file:%s", source) 66 } else { 67 fmt.Fprintf(hasher, "url:%s", source) 68 } 69 pod.UID = types.UID(hex.EncodeToString(hasher.Sum(nil)[0:])) 70 klog.V(5).InfoS("Generated UID", "pod", klog.KObj(pod), "podUID", pod.UID, "source", source) 71 } 72 73 pod.Name = generatePodName(pod.Name, nodeName) 74 klog.V(5).InfoS("Generated pod name", "pod", klog.KObj(pod), "podUID", pod.UID, "source", source) 75 76 if pod.Namespace == "" { 77 pod.Namespace = metav1.NamespaceDefault 78 } 79 klog.V(5).InfoS("Set namespace for pod", "pod", klog.KObj(pod), "source", source) 80 81 // Set the Host field to indicate this pod is scheduled on the current node. 82 pod.Spec.NodeName = string(nodeName) 83 84 if pod.Annotations == nil { 85 pod.Annotations = make(map[string]string) 86 } 87 // The generated UID is the hash of the file. 88 pod.Annotations[kubetypes.ConfigHashAnnotationKey] = string(pod.UID) 89 90 if isFile { 91 // Applying the default Taint tolerations to static pods, 92 // so they are not evicted when there are node problems. 93 helper.AddOrUpdateTolerationInPod(pod, &api.Toleration{ 94 Operator: "Exists", 95 Effect: api.TaintEffectNoExecute, 96 }) 97 } 98 99 // Set the default status to pending. 100 pod.Status.Phase = api.PodPending 101 return nil 102 } 103 104 type defaultFunc func(pod *api.Pod) error 105 106 // A static pod tried to use a ClusterTrustBundle projected volume source. 107 var ErrStaticPodTriedToUseClusterTrustBundle = errors.New("static pods may not use ClusterTrustBundle projected volume sources") 108 109 // tryDecodeSinglePod takes data and tries to extract valid Pod config information from it. 110 func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v1.Pod, err error) { 111 // JSON is valid YAML, so this should work for everything. 112 json, err := utilyaml.ToJSON(data) 113 if err != nil { 114 return false, nil, err 115 } 116 obj, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), json) 117 if err != nil { 118 return false, pod, err 119 } 120 121 newPod, ok := obj.(*api.Pod) 122 // Check whether the object could be converted to single pod. 123 if !ok { 124 return false, pod, fmt.Errorf("invalid pod: %#v", obj) 125 } 126 127 if newPod.Name == "" { 128 return true, pod, fmt.Errorf("invalid pod: name is needed for the pod") 129 } 130 131 // Apply default values and validate the pod. 132 if err = defaultFn(newPod); err != nil { 133 return true, pod, err 134 } 135 if errs := validation.ValidatePodCreate(newPod, validation.PodValidationOptions{}); len(errs) > 0 { 136 return true, pod, fmt.Errorf("invalid pod: %v", errs) 137 } 138 v1Pod := &v1.Pod{} 139 if err := k8s_api_v1.Convert_core_Pod_To_v1_Pod(newPod, v1Pod, nil); err != nil { 140 klog.ErrorS(err, "Pod failed to convert to v1", "pod", klog.KObj(newPod)) 141 return true, nil, err 142 } 143 144 for _, v := range v1Pod.Spec.Volumes { 145 if v.Projected == nil { 146 continue 147 } 148 149 for _, s := range v.Projected.Sources { 150 if s.ClusterTrustBundle != nil { 151 return true, nil, ErrStaticPodTriedToUseClusterTrustBundle 152 } 153 } 154 } 155 156 return true, v1Pod, nil 157 } 158 159 func tryDecodePodList(data []byte, defaultFn defaultFunc) (parsed bool, pods v1.PodList, err error) { 160 obj, err := runtime.Decode(legacyscheme.Codecs.UniversalDecoder(), data) 161 if err != nil { 162 return false, pods, err 163 } 164 165 newPods, ok := obj.(*api.PodList) 166 // Check whether the object could be converted to list of pods. 167 if !ok { 168 err = fmt.Errorf("invalid pods list: %#v", obj) 169 return false, pods, err 170 } 171 172 // Apply default values and validate pods. 173 for i := range newPods.Items { 174 newPod := &newPods.Items[i] 175 if newPod.Name == "" { 176 return true, pods, fmt.Errorf("invalid pod: name is needed for the pod") 177 } 178 if err = defaultFn(newPod); err != nil { 179 return true, pods, err 180 } 181 if errs := validation.ValidatePodCreate(newPod, validation.PodValidationOptions{}); len(errs) > 0 { 182 err = fmt.Errorf("invalid pod: %v", errs) 183 return true, pods, err 184 } 185 } 186 v1Pods := &v1.PodList{} 187 if err := k8s_api_v1.Convert_core_PodList_To_v1_PodList(newPods, v1Pods, nil); err != nil { 188 return true, pods, err 189 } 190 return true, *v1Pods, err 191 }