blob: 9ca34c9fa9c21fa98a3608bf35e67544a1f17b1f [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package meta
18
19import (
20 "fmt"
21 "reflect"
22
23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 "k8s.io/apimachinery/pkg/conversion"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/apimachinery/pkg/runtime/schema"
27 "k8s.io/apimachinery/pkg/types"
28 "k8s.io/klog/v2"
29)
30
31// errNotList is returned when an object implements the Object style interfaces but not the List style
32// interfaces.
33var errNotList = fmt.Errorf("object does not implement the List interfaces")
34
35var errNotCommon = fmt.Errorf("object does not implement the common interface for accessing the SelfLink")
36
37// CommonAccessor returns a Common interface for the provided object or an error if the object does
38// not provide List.
39func CommonAccessor(obj interface{}) (metav1.Common, error) {
40 switch t := obj.(type) {
41 case List:
42 return t, nil
43 case metav1.ListInterface:
44 return t, nil
45 case ListMetaAccessor:
46 if m := t.GetListMeta(); m != nil {
47 return m, nil
48 }
49 return nil, errNotCommon
50 case metav1.ListMetaAccessor:
51 if m := t.GetListMeta(); m != nil {
52 return m, nil
53 }
54 return nil, errNotCommon
55 case metav1.Object:
56 return t, nil
57 case metav1.ObjectMetaAccessor:
58 if m := t.GetObjectMeta(); m != nil {
59 return m, nil
60 }
61 return nil, errNotCommon
62 default:
63 return nil, errNotCommon
64 }
65}
66
67// ListAccessor returns a List interface for the provided object or an error if the object does
68// not provide List.
69// IMPORTANT: Objects are NOT a superset of lists. Do not use this check to determine whether an
70// object *is* a List.
71func ListAccessor(obj interface{}) (List, error) {
72 switch t := obj.(type) {
73 case List:
74 return t, nil
75 case metav1.ListInterface:
76 return t, nil
77 case ListMetaAccessor:
78 if m := t.GetListMeta(); m != nil {
79 return m, nil
80 }
81 return nil, errNotList
82 case metav1.ListMetaAccessor:
83 if m := t.GetListMeta(); m != nil {
84 return m, nil
85 }
86 return nil, errNotList
87 default:
88 return nil, errNotList
89 }
90}
91
92// errNotObject is returned when an object implements the List style interfaces but not the Object style
93// interfaces.
94var errNotObject = fmt.Errorf("object does not implement the Object interfaces")
95
96// Accessor takes an arbitrary object pointer and returns meta.Interface.
97// obj must be a pointer to an API type. An error is returned if the minimum
98// required fields are missing. Fields that are not required return the default
99// value and are a no-op if set.
100func Accessor(obj interface{}) (metav1.Object, error) {
101 switch t := obj.(type) {
102 case metav1.Object:
103 return t, nil
104 case metav1.ObjectMetaAccessor:
105 if m := t.GetObjectMeta(); m != nil {
106 return m, nil
107 }
108 return nil, errNotObject
109 default:
110 return nil, errNotObject
111 }
112}
113
114// AsPartialObjectMetadata takes the metav1 interface and returns a partial object.
115// TODO: consider making this solely a conversion action.
116func AsPartialObjectMetadata(m metav1.Object) *metav1.PartialObjectMetadata {
117 switch t := m.(type) {
118 case *metav1.ObjectMeta:
119 return &metav1.PartialObjectMetadata{ObjectMeta: *t}
120 default:
121 return &metav1.PartialObjectMetadata{
122 ObjectMeta: metav1.ObjectMeta{
123 Name: m.GetName(),
124 GenerateName: m.GetGenerateName(),
125 Namespace: m.GetNamespace(),
126 SelfLink: m.GetSelfLink(),
127 UID: m.GetUID(),
128 ResourceVersion: m.GetResourceVersion(),
129 Generation: m.GetGeneration(),
130 CreationTimestamp: m.GetCreationTimestamp(),
131 DeletionTimestamp: m.GetDeletionTimestamp(),
132 DeletionGracePeriodSeconds: m.GetDeletionGracePeriodSeconds(),
133 Labels: m.GetLabels(),
134 Annotations: m.GetAnnotations(),
135 OwnerReferences: m.GetOwnerReferences(),
136 Finalizers: m.GetFinalizers(),
137 ClusterName: m.GetClusterName(),
138 ManagedFields: m.GetManagedFields(),
139 },
140 }
141 }
142}
143
144// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
145// and Kind of an in-memory internal object.
146// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
147// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
148// api conventions).
149func TypeAccessor(obj interface{}) (Type, error) {
150 if typed, ok := obj.(runtime.Object); ok {
151 return objectAccessor{typed}, nil
152 }
153 v, err := conversion.EnforcePtr(obj)
154 if err != nil {
155 return nil, err
156 }
157 t := v.Type()
158 if v.Kind() != reflect.Struct {
159 return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
160 }
161
162 typeMeta := v.FieldByName("TypeMeta")
163 if !typeMeta.IsValid() {
164 return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
165 }
166 a := &genericAccessor{}
167 if err := extractFromTypeMeta(typeMeta, a); err != nil {
168 return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
169 }
170 return a, nil
171}
172
173type objectAccessor struct {
174 runtime.Object
175}
176
177func (obj objectAccessor) GetKind() string {
178 return obj.GetObjectKind().GroupVersionKind().Kind
179}
180
181func (obj objectAccessor) SetKind(kind string) {
182 gvk := obj.GetObjectKind().GroupVersionKind()
183 gvk.Kind = kind
184 obj.GetObjectKind().SetGroupVersionKind(gvk)
185}
186
187func (obj objectAccessor) GetAPIVersion() string {
188 return obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
189}
190
191func (obj objectAccessor) SetAPIVersion(version string) {
192 gvk := obj.GetObjectKind().GroupVersionKind()
193 gv, err := schema.ParseGroupVersion(version)
194 if err != nil {
195 gv = schema.GroupVersion{Version: version}
196 }
197 gvk.Group, gvk.Version = gv.Group, gv.Version
198 obj.GetObjectKind().SetGroupVersionKind(gvk)
199}
200
201// NewAccessor returns a MetadataAccessor that can retrieve
202// or manipulate resource version on objects derived from core API
203// metadata concepts.
204func NewAccessor() MetadataAccessor {
205 return resourceAccessor{}
206}
207
208// resourceAccessor implements ResourceVersioner and SelfLinker.
209type resourceAccessor struct{}
210
211func (resourceAccessor) Kind(obj runtime.Object) (string, error) {
212 return objectAccessor{obj}.GetKind(), nil
213}
214
215func (resourceAccessor) SetKind(obj runtime.Object, kind string) error {
216 objectAccessor{obj}.SetKind(kind)
217 return nil
218}
219
220func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) {
221 return objectAccessor{obj}.GetAPIVersion(), nil
222}
223
224func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error {
225 objectAccessor{obj}.SetAPIVersion(version)
226 return nil
227}
228
229func (resourceAccessor) Namespace(obj runtime.Object) (string, error) {
230 accessor, err := Accessor(obj)
231 if err != nil {
232 return "", err
233 }
234 return accessor.GetNamespace(), nil
235}
236
237func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error {
238 accessor, err := Accessor(obj)
239 if err != nil {
240 return err
241 }
242 accessor.SetNamespace(namespace)
243 return nil
244}
245
246func (resourceAccessor) Name(obj runtime.Object) (string, error) {
247 accessor, err := Accessor(obj)
248 if err != nil {
249 return "", err
250 }
251 return accessor.GetName(), nil
252}
253
254func (resourceAccessor) SetName(obj runtime.Object, name string) error {
255 accessor, err := Accessor(obj)
256 if err != nil {
257 return err
258 }
259 accessor.SetName(name)
260 return nil
261}
262
263func (resourceAccessor) GenerateName(obj runtime.Object) (string, error) {
264 accessor, err := Accessor(obj)
265 if err != nil {
266 return "", err
267 }
268 return accessor.GetGenerateName(), nil
269}
270
271func (resourceAccessor) SetGenerateName(obj runtime.Object, name string) error {
272 accessor, err := Accessor(obj)
273 if err != nil {
274 return err
275 }
276 accessor.SetGenerateName(name)
277 return nil
278}
279
280func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
281 accessor, err := Accessor(obj)
282 if err != nil {
283 return "", err
284 }
285 return accessor.GetUID(), nil
286}
287
288func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error {
289 accessor, err := Accessor(obj)
290 if err != nil {
291 return err
292 }
293 accessor.SetUID(uid)
294 return nil
295}
296
297func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) {
298 accessor, err := CommonAccessor(obj)
299 if err != nil {
300 return "", err
301 }
302 return accessor.GetSelfLink(), nil
303}
304
305func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error {
306 accessor, err := CommonAccessor(obj)
307 if err != nil {
308 return err
309 }
310 accessor.SetSelfLink(selfLink)
311 return nil
312}
313
314func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) {
315 accessor, err := Accessor(obj)
316 if err != nil {
317 return nil, err
318 }
319 return accessor.GetLabels(), nil
320}
321
322func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error {
323 accessor, err := Accessor(obj)
324 if err != nil {
325 return err
326 }
327 accessor.SetLabels(labels)
328 return nil
329}
330
331func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) {
332 accessor, err := Accessor(obj)
333 if err != nil {
334 return nil, err
335 }
336 return accessor.GetAnnotations(), nil
337}
338
339func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error {
340 accessor, err := Accessor(obj)
341 if err != nil {
342 return err
343 }
344 accessor.SetAnnotations(annotations)
345 return nil
346}
347
348func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) {
349 accessor, err := CommonAccessor(obj)
350 if err != nil {
351 return "", err
352 }
353 return accessor.GetResourceVersion(), nil
354}
355
356func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error {
357 accessor, err := CommonAccessor(obj)
358 if err != nil {
359 return err
360 }
361 accessor.SetResourceVersion(version)
362 return nil
363}
364
365func (resourceAccessor) Continue(obj runtime.Object) (string, error) {
366 accessor, err := ListAccessor(obj)
367 if err != nil {
368 return "", err
369 }
370 return accessor.GetContinue(), nil
371}
372
373func (resourceAccessor) SetContinue(obj runtime.Object, version string) error {
374 accessor, err := ListAccessor(obj)
375 if err != nil {
376 return err
377 }
378 accessor.SetContinue(version)
379 return nil
380}
381
382// extractFromOwnerReference extracts v to o. v is the OwnerReferences field of an object.
383func extractFromOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
384 if err := runtime.Field(v, "APIVersion", &o.APIVersion); err != nil {
385 return err
386 }
387 if err := runtime.Field(v, "Kind", &o.Kind); err != nil {
388 return err
389 }
390 if err := runtime.Field(v, "Name", &o.Name); err != nil {
391 return err
392 }
393 if err := runtime.Field(v, "UID", &o.UID); err != nil {
394 return err
395 }
396 var controllerPtr *bool
397 if err := runtime.Field(v, "Controller", &controllerPtr); err != nil {
398 return err
399 }
400 if controllerPtr != nil {
401 controller := *controllerPtr
402 o.Controller = &controller
403 }
404 var blockOwnerDeletionPtr *bool
405 if err := runtime.Field(v, "BlockOwnerDeletion", &blockOwnerDeletionPtr); err != nil {
406 return err
407 }
408 if blockOwnerDeletionPtr != nil {
409 block := *blockOwnerDeletionPtr
410 o.BlockOwnerDeletion = &block
411 }
412 return nil
413}
414
415// setOwnerReference sets v to o. v is the OwnerReferences field of an object.
416func setOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
417 if err := runtime.SetField(o.APIVersion, v, "APIVersion"); err != nil {
418 return err
419 }
420 if err := runtime.SetField(o.Kind, v, "Kind"); err != nil {
421 return err
422 }
423 if err := runtime.SetField(o.Name, v, "Name"); err != nil {
424 return err
425 }
426 if err := runtime.SetField(o.UID, v, "UID"); err != nil {
427 return err
428 }
429 if o.Controller != nil {
430 controller := *(o.Controller)
431 if err := runtime.SetField(&controller, v, "Controller"); err != nil {
432 return err
433 }
434 }
435 if o.BlockOwnerDeletion != nil {
436 block := *(o.BlockOwnerDeletion)
437 if err := runtime.SetField(&block, v, "BlockOwnerDeletion"); err != nil {
438 return err
439 }
440 }
441 return nil
442}
443
444// genericAccessor contains pointers to strings that can modify an arbitrary
445// struct and implements the Accessor interface.
446type genericAccessor struct {
447 namespace *string
448 name *string
449 generateName *string
450 uid *types.UID
451 apiVersion *string
452 kind *string
453 resourceVersion *string
454 selfLink *string
455 creationTimestamp *metav1.Time
456 deletionTimestamp **metav1.Time
457 labels *map[string]string
458 annotations *map[string]string
459 ownerReferences reflect.Value
460 finalizers *[]string
461}
462
463func (a genericAccessor) GetNamespace() string {
464 if a.namespace == nil {
465 return ""
466 }
467 return *a.namespace
468}
469
470func (a genericAccessor) SetNamespace(namespace string) {
471 if a.namespace == nil {
472 return
473 }
474 *a.namespace = namespace
475}
476
477func (a genericAccessor) GetName() string {
478 if a.name == nil {
479 return ""
480 }
481 return *a.name
482}
483
484func (a genericAccessor) SetName(name string) {
485 if a.name == nil {
486 return
487 }
488 *a.name = name
489}
490
491func (a genericAccessor) GetGenerateName() string {
492 if a.generateName == nil {
493 return ""
494 }
495 return *a.generateName
496}
497
498func (a genericAccessor) SetGenerateName(generateName string) {
499 if a.generateName == nil {
500 return
501 }
502 *a.generateName = generateName
503}
504
505func (a genericAccessor) GetUID() types.UID {
506 if a.uid == nil {
507 return ""
508 }
509 return *a.uid
510}
511
512func (a genericAccessor) SetUID(uid types.UID) {
513 if a.uid == nil {
514 return
515 }
516 *a.uid = uid
517}
518
519func (a genericAccessor) GetAPIVersion() string {
520 return *a.apiVersion
521}
522
523func (a genericAccessor) SetAPIVersion(version string) {
524 *a.apiVersion = version
525}
526
527func (a genericAccessor) GetKind() string {
528 return *a.kind
529}
530
531func (a genericAccessor) SetKind(kind string) {
532 *a.kind = kind
533}
534
535func (a genericAccessor) GetResourceVersion() string {
536 return *a.resourceVersion
537}
538
539func (a genericAccessor) SetResourceVersion(version string) {
540 *a.resourceVersion = version
541}
542
543func (a genericAccessor) GetSelfLink() string {
544 return *a.selfLink
545}
546
547func (a genericAccessor) SetSelfLink(selfLink string) {
548 *a.selfLink = selfLink
549}
550
551func (a genericAccessor) GetCreationTimestamp() metav1.Time {
552 return *a.creationTimestamp
553}
554
555func (a genericAccessor) SetCreationTimestamp(timestamp metav1.Time) {
556 *a.creationTimestamp = timestamp
557}
558
559func (a genericAccessor) GetDeletionTimestamp() *metav1.Time {
560 return *a.deletionTimestamp
561}
562
563func (a genericAccessor) SetDeletionTimestamp(timestamp *metav1.Time) {
564 *a.deletionTimestamp = timestamp
565}
566
567func (a genericAccessor) GetLabels() map[string]string {
568 if a.labels == nil {
569 return nil
570 }
571 return *a.labels
572}
573
574func (a genericAccessor) SetLabels(labels map[string]string) {
575 *a.labels = labels
576}
577
578func (a genericAccessor) GetAnnotations() map[string]string {
579 if a.annotations == nil {
580 return nil
581 }
582 return *a.annotations
583}
584
585func (a genericAccessor) SetAnnotations(annotations map[string]string) {
586 if a.annotations == nil {
587 emptyAnnotations := make(map[string]string)
588 a.annotations = &emptyAnnotations
589 }
590 *a.annotations = annotations
591}
592
593func (a genericAccessor) GetFinalizers() []string {
594 if a.finalizers == nil {
595 return nil
596 }
597 return *a.finalizers
598}
599
600func (a genericAccessor) SetFinalizers(finalizers []string) {
601 *a.finalizers = finalizers
602}
603
604func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
605 var ret []metav1.OwnerReference
606 s := a.ownerReferences
607 if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
608 klog.Errorf("expect %v to be a pointer to slice", s)
609 return ret
610 }
611 s = s.Elem()
612 // Set the capacity to one element greater to avoid copy if the caller later append an element.
613 ret = make([]metav1.OwnerReference, s.Len(), s.Len()+1)
614 for i := 0; i < s.Len(); i++ {
615 if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil {
616 klog.Errorf("extractFromOwnerReference failed: %v", err)
617 return ret
618 }
619 }
620 return ret
621}
622
623func (a genericAccessor) SetOwnerReferences(references []metav1.OwnerReference) {
624 s := a.ownerReferences
625 if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
626 klog.Errorf("expect %v to be a pointer to slice", s)
627 }
628 s = s.Elem()
629 newReferences := reflect.MakeSlice(s.Type(), len(references), len(references))
630 for i := 0; i < len(references); i++ {
631 if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil {
632 klog.Errorf("setOwnerReference failed: %v", err)
633 return
634 }
635 }
636 s.Set(newReferences)
637}
638
639// extractFromTypeMeta extracts pointers to version and kind fields from an object
640func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error {
641 if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil {
642 return err
643 }
644 if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil {
645 return err
646 }
647 return nil
648}