1
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
35
36
37 "k8s.io/kubernetes/pkg/api/legacyscheme"
38
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
50 )
51
52
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
62
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
82 pod.Spec.NodeName = string(nodeName)
83
84 if pod.Annotations == nil {
85 pod.Annotations = make(map[string]string)
86 }
87
88 pod.Annotations[kubetypes.ConfigHashAnnotationKey] = string(pod.UID)
89
90 if isFile {
91
92
93 helper.AddOrUpdateTolerationInPod(pod, &api.Toleration{
94 Operator: "Exists",
95 Effect: api.TaintEffectNoExecute,
96 })
97 }
98
99
100 pod.Status.Phase = api.PodPending
101 return nil
102 }
103
104 type defaultFunc func(pod *api.Pod) error
105
106
107 var ErrStaticPodTriedToUseClusterTrustBundle = errors.New("static pods may not use ClusterTrustBundle projected volume sources")
108
109
110 func tryDecodeSinglePod(data []byte, defaultFn defaultFunc) (parsed bool, pod *v1.Pod, err error) {
111
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
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
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
167 if !ok {
168 err = fmt.Errorf("invalid pods list: %#v", obj)
169 return false, pods, err
170 }
171
172
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 }
192
View as plain text