1
16
17 package componentconfigs
18
19 import (
20 "github.com/pkg/errors"
21
22 apierrors "k8s.io/apimachinery/pkg/api/errors"
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/apimachinery/pkg/runtime"
25 "k8s.io/apimachinery/pkg/runtime/schema"
26 "k8s.io/apimachinery/pkg/util/validation/field"
27 clientset "k8s.io/client-go/kubernetes"
28 "k8s.io/klog/v2"
29
30 kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
31 outputapiv1alpha3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/output/v1alpha3"
32 kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
33 "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient"
34 "k8s.io/kubernetes/cmd/kubeadm/app/util/config/strict"
35 )
36
37
38
39 type handler struct {
40
41 GroupVersion schema.GroupVersion
42
43
44 AddToScheme func(*runtime.Scheme) error
45
46
47 CreateEmpty func() kubeadmapi.ComponentConfig
48
49
50
51 fromCluster func(*handler, clientset.Interface, *kubeadmapi.ClusterConfiguration) (kubeadmapi.ComponentConfig, error)
52 }
53
54
55
56
57 func (h *handler) FromDocumentMap(docmap kubeadmapi.DocumentMap) (kubeadmapi.ComponentConfig, error) {
58 for gvk := range docmap {
59 if gvk.Group == h.GroupVersion.Group {
60 cfg := h.CreateEmpty()
61 if err := cfg.Unmarshal(docmap); err != nil {
62 return nil, err
63 }
64
65 cfg.SetUserSupplied(true)
66 return cfg, nil
67 }
68 }
69 return nil, nil
70 }
71
72
73
74 func (h *handler) fromConfigMap(client clientset.Interface, cmName, cmKey string, mustExist bool) (kubeadmapi.ComponentConfig, error) {
75 configMap, err := apiclient.GetConfigMapWithShortRetry(client, metav1.NamespaceSystem, cmName)
76 if err != nil {
77 if !mustExist && (apierrors.IsNotFound(err) || apierrors.IsForbidden(err)) {
78 klog.Warningf("Warning: No %s config is loaded. Continuing without it: %v", h.GroupVersion, err)
79 return nil, nil
80 }
81 return nil, err
82 }
83
84 configData, ok := configMap.Data[cmKey]
85 if !ok {
86 return nil, errors.Errorf("unexpected error when reading %s ConfigMap: %s key value pair missing", cmName, cmKey)
87 }
88
89 gvkmap, err := kubeadmutil.SplitYAMLDocuments([]byte(configData))
90 if err != nil {
91 return nil, err
92 }
93
94
95 generatedConfig := VerifyConfigMapSignature(configMap)
96
97 componentCfg, err := h.FromDocumentMap(gvkmap)
98 if err != nil {
99
100
101 if _, ok := err.(*UnsupportedConfigVersionError); ok && generatedConfig {
102 return nil, nil
103 }
104 return nil, err
105 }
106
107 if componentCfg != nil {
108 componentCfg.SetUserSupplied(!generatedConfig)
109 }
110
111 return componentCfg, nil
112 }
113
114
115 func (h *handler) FromCluster(clientset clientset.Interface, clusterCfg *kubeadmapi.ClusterConfiguration) (kubeadmapi.ComponentConfig, error) {
116 return h.fromCluster(h, clientset, clusterCfg)
117 }
118
119
120 var known = []*handler{
121 &kubeProxyHandler,
122 &kubeletHandler,
123 }
124
125
126 type configBase struct {
127
128 GroupVersion schema.GroupVersion
129
130
131 userSupplied bool
132 }
133
134 func (cb *configBase) IsUserSupplied() bool {
135 return cb.userSupplied
136 }
137
138 func (cb *configBase) SetUserSupplied(userSupplied bool) {
139 cb.userSupplied = userSupplied
140 }
141
142 func (cb *configBase) DeepCopyInto(other *configBase) {
143 *other = *cb
144 }
145
146 func cloneBytes(in []byte) []byte {
147 out := make([]byte, len(in))
148 copy(out, in)
149 return out
150 }
151
152
153
154 func (cb *configBase) Marshal(object runtime.Object) ([]byte, error) {
155 return kubeadmutil.MarshalToYamlForCodecs(object, cb.GroupVersion, Codecs)
156 }
157
158
159
160 func (cb *configBase) Unmarshal(from kubeadmapi.DocumentMap, into runtime.Object) error {
161 for gvk, yaml := range from {
162
163 if gvk.Group != cb.GroupVersion.Group {
164 continue
165 }
166
167 if gvk.Version != cb.GroupVersion.Version {
168 return &UnsupportedConfigVersionError{
169 OldVersion: gvk.GroupVersion(),
170 CurrentVersion: cb.GroupVersion,
171 Document: cloneBytes(yaml),
172 }
173 }
174
175
176 if err := strict.VerifyUnmarshalStrict([]*runtime.Scheme{Scheme}, gvk, yaml); err != nil {
177 klog.Warning(err.Error())
178 }
179
180
181 return runtime.DecodeInto(Codecs.UniversalDecoder(), yaml, into)
182 }
183
184 return nil
185 }
186
187
188 func ensureInitializedComponentConfigs(clusterCfg *kubeadmapi.ClusterConfiguration) {
189 if clusterCfg.ComponentConfigs == nil {
190 clusterCfg.ComponentConfigs = kubeadmapi.ComponentConfigMap{}
191 }
192 }
193
194
195 func Default(clusterCfg *kubeadmapi.ClusterConfiguration, localAPIEndpoint *kubeadmapi.APIEndpoint, nodeRegOpts *kubeadmapi.NodeRegistrationOptions) {
196 ensureInitializedComponentConfigs(clusterCfg)
197
198 for _, handler := range known {
199
200 group := handler.GroupVersion.Group
201 if componentCfg, ok := clusterCfg.ComponentConfigs[group]; ok {
202 componentCfg.Default(clusterCfg, localAPIEndpoint, nodeRegOpts)
203 } else {
204 componentCfg := handler.CreateEmpty()
205 componentCfg.Default(clusterCfg, localAPIEndpoint, nodeRegOpts)
206 clusterCfg.ComponentConfigs[group] = componentCfg
207 }
208 }
209 }
210
211
212 func FetchFromCluster(clusterCfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) error {
213 ensureInitializedComponentConfigs(clusterCfg)
214
215 for _, handler := range known {
216 componentCfg, err := handler.FromCluster(client, clusterCfg)
217 if err != nil {
218 return err
219 }
220
221 if componentCfg != nil {
222 clusterCfg.ComponentConfigs[handler.GroupVersion.Group] = componentCfg
223 }
224 }
225
226 return nil
227 }
228
229
230 func FetchFromDocumentMap(clusterCfg *kubeadmapi.ClusterConfiguration, docmap kubeadmapi.DocumentMap) error {
231 ensureInitializedComponentConfigs(clusterCfg)
232
233 for _, handler := range known {
234 componentCfg, err := handler.FromDocumentMap(docmap)
235 if err != nil {
236 return err
237 }
238
239 if componentCfg != nil {
240 clusterCfg.ComponentConfigs[handler.GroupVersion.Group] = componentCfg
241 }
242 }
243
244 return nil
245 }
246
247
248
249
250
251 func FetchFromClusterWithLocalOverwrites(clusterCfg *kubeadmapi.ClusterConfiguration, client clientset.Interface, docmap kubeadmapi.DocumentMap) error {
252 ensureInitializedComponentConfigs(clusterCfg)
253
254 oldVersionErrs := UnsupportedConfigVersionsErrorMap{}
255
256 for _, handler := range known {
257 componentCfg, err := handler.FromCluster(client, clusterCfg)
258 if err != nil {
259 if vererr, ok := err.(*UnsupportedConfigVersionError); ok {
260 oldVersionErrs[handler.GroupVersion.Group] = vererr
261 } else {
262 return err
263 }
264 } else if componentCfg != nil {
265 clusterCfg.ComponentConfigs[handler.GroupVersion.Group] = componentCfg
266 }
267 }
268
269 for _, handler := range known {
270 componentCfg, err := handler.FromDocumentMap(docmap)
271 if err != nil {
272 if vererr, ok := err.(*UnsupportedConfigVersionError); ok {
273 oldVersionErrs[handler.GroupVersion.Group] = vererr
274 } else {
275 return err
276 }
277 } else if componentCfg != nil {
278 clusterCfg.ComponentConfigs[handler.GroupVersion.Group] = componentCfg
279 delete(oldVersionErrs, handler.GroupVersion.Group)
280 }
281 }
282
283 if len(oldVersionErrs) != 0 {
284 return oldVersionErrs
285 }
286
287 return nil
288 }
289
290
291
292 func GetVersionStates(clusterCfg *kubeadmapi.ClusterConfiguration, client clientset.Interface) ([]outputapiv1alpha3.ComponentConfigVersionState, error) {
293
294
295 scratchClusterCfg := clusterCfg.DeepCopy()
296 scratchClusterCfg.ComponentConfigs = kubeadmapi.ComponentConfigMap{}
297
298 err := FetchFromCluster(scratchClusterCfg, client)
299 if err != nil {
300
301 return nil, err
302 }
303
304 results := []outputapiv1alpha3.ComponentConfigVersionState{}
305 for _, handler := range known {
306 group := handler.GroupVersion.Group
307 if _, ok := scratchClusterCfg.ComponentConfigs[group]; ok {
308
309 results = append(results, outputapiv1alpha3.ComponentConfigVersionState{
310 Group: group,
311 CurrentVersion: handler.GroupVersion.Version,
312 PreferredVersion: handler.GroupVersion.Version,
313 })
314 } else {
315
316
317
318 results = append(results, outputapiv1alpha3.ComponentConfigVersionState{
319 Group: group,
320 PreferredVersion: handler.GroupVersion.Version,
321 })
322 }
323 }
324
325 return results, nil
326 }
327
328
329
330 func Validate(clusterCfg *kubeadmapi.ClusterConfiguration) field.ErrorList {
331 return field.ErrorList{}
332 }
333
View as plain text