blob: 086bce04b0ac05eb5bb0e59389d4cb485fe8f195 [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
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
Zack Williamse940c7a2019-08-21 14:25:39 -070023 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
Zack Williamse940c7a2019-08-21 14:25:39 -070024 "k8s.io/apimachinery/pkg/conversion"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/apimachinery/pkg/runtime/schema"
27 "k8s.io/apimachinery/pkg/types"
David Bainbridge86971522019-09-26 22:09:39 +000028 "k8s.io/klog"
Zack Williamse940c7a2019-08-21 14:25:39 -070029)
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.
David Bainbridge86971522019-09-26 22:09:39 +0000116func AsPartialObjectMetadata(m metav1.Object) *metav1.PartialObjectMetadata {
Zack Williamse940c7a2019-08-21 14:25:39 -0700117 switch t := m.(type) {
118 case *metav1.ObjectMeta:
David Bainbridge86971522019-09-26 22:09:39 +0000119 return &metav1.PartialObjectMetadata{ObjectMeta: *t}
Zack Williamse940c7a2019-08-21 14:25:39 -0700120 default:
David Bainbridge86971522019-09-26 22:09:39 +0000121 return &metav1.PartialObjectMetadata{
Zack Williamse940c7a2019-08-21 14:25:39 -0700122 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(),
David Bainbridge86971522019-09-26 22:09:39 +0000133 Labels: m.GetLabels(),
134 Annotations: m.GetAnnotations(),
135 OwnerReferences: m.GetOwnerReferences(),
136 Finalizers: m.GetFinalizers(),
137 ClusterName: m.GetClusterName(),
138 Initializers: m.GetInitializers(),
139 ManagedFields: m.GetManagedFields(),
Zack Williamse940c7a2019-08-21 14:25:39 -0700140 },
141 }
142 }
143}
144
145// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
146// and Kind of an in-memory internal object.
147// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
148// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
149// api conventions).
150func TypeAccessor(obj interface{}) (Type, error) {
151 if typed, ok := obj.(runtime.Object); ok {
152 return objectAccessor{typed}, nil
153 }
154 v, err := conversion.EnforcePtr(obj)
155 if err != nil {
156 return nil, err
157 }
158 t := v.Type()
159 if v.Kind() != reflect.Struct {
160 return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
161 }
162
163 typeMeta := v.FieldByName("TypeMeta")
164 if !typeMeta.IsValid() {
165 return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
166 }
167 a := &genericAccessor{}
168 if err := extractFromTypeMeta(typeMeta, a); err != nil {
169 return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
170 }
171 return a, nil
172}
173
174type objectAccessor struct {
175 runtime.Object
176}
177
178func (obj objectAccessor) GetKind() string {
179 return obj.GetObjectKind().GroupVersionKind().Kind
180}
181
182func (obj objectAccessor) SetKind(kind string) {
183 gvk := obj.GetObjectKind().GroupVersionKind()
184 gvk.Kind = kind
185 obj.GetObjectKind().SetGroupVersionKind(gvk)
186}
187
188func (obj objectAccessor) GetAPIVersion() string {
189 return obj.GetObjectKind().GroupVersionKind().GroupVersion().String()
190}
191
192func (obj objectAccessor) SetAPIVersion(version string) {
193 gvk := obj.GetObjectKind().GroupVersionKind()
194 gv, err := schema.ParseGroupVersion(version)
195 if err != nil {
196 gv = schema.GroupVersion{Version: version}
197 }
198 gvk.Group, gvk.Version = gv.Group, gv.Version
199 obj.GetObjectKind().SetGroupVersionKind(gvk)
200}
201
202// NewAccessor returns a MetadataAccessor that can retrieve
203// or manipulate resource version on objects derived from core API
204// metadata concepts.
205func NewAccessor() MetadataAccessor {
206 return resourceAccessor{}
207}
208
209// resourceAccessor implements ResourceVersioner and SelfLinker.
210type resourceAccessor struct{}
211
212func (resourceAccessor) Kind(obj runtime.Object) (string, error) {
213 return objectAccessor{obj}.GetKind(), nil
214}
215
216func (resourceAccessor) SetKind(obj runtime.Object, kind string) error {
217 objectAccessor{obj}.SetKind(kind)
218 return nil
219}
220
221func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) {
222 return objectAccessor{obj}.GetAPIVersion(), nil
223}
224
225func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error {
226 objectAccessor{obj}.SetAPIVersion(version)
227 return nil
228}
229
230func (resourceAccessor) Namespace(obj runtime.Object) (string, error) {
231 accessor, err := Accessor(obj)
232 if err != nil {
233 return "", err
234 }
235 return accessor.GetNamespace(), nil
236}
237
238func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error {
239 accessor, err := Accessor(obj)
240 if err != nil {
241 return err
242 }
243 accessor.SetNamespace(namespace)
244 return nil
245}
246
247func (resourceAccessor) Name(obj runtime.Object) (string, error) {
248 accessor, err := Accessor(obj)
249 if err != nil {
250 return "", err
251 }
252 return accessor.GetName(), nil
253}
254
255func (resourceAccessor) SetName(obj runtime.Object, name string) error {
256 accessor, err := Accessor(obj)
257 if err != nil {
258 return err
259 }
260 accessor.SetName(name)
261 return nil
262}
263
264func (resourceAccessor) GenerateName(obj runtime.Object) (string, error) {
265 accessor, err := Accessor(obj)
266 if err != nil {
267 return "", err
268 }
269 return accessor.GetGenerateName(), nil
270}
271
272func (resourceAccessor) SetGenerateName(obj runtime.Object, name string) error {
273 accessor, err := Accessor(obj)
274 if err != nil {
275 return err
276 }
277 accessor.SetGenerateName(name)
278 return nil
279}
280
281func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) {
282 accessor, err := Accessor(obj)
283 if err != nil {
284 return "", err
285 }
286 return accessor.GetUID(), nil
287}
288
289func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error {
290 accessor, err := Accessor(obj)
291 if err != nil {
292 return err
293 }
294 accessor.SetUID(uid)
295 return nil
296}
297
298func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) {
299 accessor, err := CommonAccessor(obj)
300 if err != nil {
301 return "", err
302 }
303 return accessor.GetSelfLink(), nil
304}
305
306func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error {
307 accessor, err := CommonAccessor(obj)
308 if err != nil {
309 return err
310 }
311 accessor.SetSelfLink(selfLink)
312 return nil
313}
314
315func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) {
316 accessor, err := Accessor(obj)
317 if err != nil {
318 return nil, err
319 }
320 return accessor.GetLabels(), nil
321}
322
323func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error {
324 accessor, err := Accessor(obj)
325 if err != nil {
326 return err
327 }
328 accessor.SetLabels(labels)
329 return nil
330}
331
332func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) {
333 accessor, err := Accessor(obj)
334 if err != nil {
335 return nil, err
336 }
337 return accessor.GetAnnotations(), nil
338}
339
340func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error {
341 accessor, err := Accessor(obj)
342 if err != nil {
343 return err
344 }
345 accessor.SetAnnotations(annotations)
346 return nil
347}
348
349func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) {
350 accessor, err := CommonAccessor(obj)
351 if err != nil {
352 return "", err
353 }
354 return accessor.GetResourceVersion(), nil
355}
356
357func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error {
358 accessor, err := CommonAccessor(obj)
359 if err != nil {
360 return err
361 }
362 accessor.SetResourceVersion(version)
363 return nil
364}
365
366func (resourceAccessor) Continue(obj runtime.Object) (string, error) {
367 accessor, err := ListAccessor(obj)
368 if err != nil {
369 return "", err
370 }
371 return accessor.GetContinue(), nil
372}
373
374func (resourceAccessor) SetContinue(obj runtime.Object, version string) error {
375 accessor, err := ListAccessor(obj)
376 if err != nil {
377 return err
378 }
379 accessor.SetContinue(version)
380 return nil
381}
382
383// extractFromOwnerReference extracts v to o. v is the OwnerReferences field of an object.
384func extractFromOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
385 if err := runtime.Field(v, "APIVersion", &o.APIVersion); err != nil {
386 return err
387 }
388 if err := runtime.Field(v, "Kind", &o.Kind); err != nil {
389 return err
390 }
391 if err := runtime.Field(v, "Name", &o.Name); err != nil {
392 return err
393 }
394 if err := runtime.Field(v, "UID", &o.UID); err != nil {
395 return err
396 }
397 var controllerPtr *bool
398 if err := runtime.Field(v, "Controller", &controllerPtr); err != nil {
399 return err
400 }
401 if controllerPtr != nil {
402 controller := *controllerPtr
403 o.Controller = &controller
404 }
405 var blockOwnerDeletionPtr *bool
406 if err := runtime.Field(v, "BlockOwnerDeletion", &blockOwnerDeletionPtr); err != nil {
407 return err
408 }
409 if blockOwnerDeletionPtr != nil {
410 block := *blockOwnerDeletionPtr
411 o.BlockOwnerDeletion = &block
412 }
413 return nil
414}
415
416// setOwnerReference sets v to o. v is the OwnerReferences field of an object.
417func setOwnerReference(v reflect.Value, o *metav1.OwnerReference) error {
418 if err := runtime.SetField(o.APIVersion, v, "APIVersion"); err != nil {
419 return err
420 }
421 if err := runtime.SetField(o.Kind, v, "Kind"); err != nil {
422 return err
423 }
424 if err := runtime.SetField(o.Name, v, "Name"); err != nil {
425 return err
426 }
427 if err := runtime.SetField(o.UID, v, "UID"); err != nil {
428 return err
429 }
430 if o.Controller != nil {
431 controller := *(o.Controller)
432 if err := runtime.SetField(&controller, v, "Controller"); err != nil {
433 return err
434 }
435 }
436 if o.BlockOwnerDeletion != nil {
437 block := *(o.BlockOwnerDeletion)
438 if err := runtime.SetField(&block, v, "BlockOwnerDeletion"); err != nil {
439 return err
440 }
441 }
442 return nil
443}
444
445// genericAccessor contains pointers to strings that can modify an arbitrary
446// struct and implements the Accessor interface.
447type genericAccessor struct {
448 namespace *string
449 name *string
450 generateName *string
451 uid *types.UID
452 apiVersion *string
453 kind *string
454 resourceVersion *string
455 selfLink *string
456 creationTimestamp *metav1.Time
457 deletionTimestamp **metav1.Time
458 labels *map[string]string
459 annotations *map[string]string
460 ownerReferences reflect.Value
461 finalizers *[]string
462}
463
464func (a genericAccessor) GetNamespace() string {
465 if a.namespace == nil {
466 return ""
467 }
468 return *a.namespace
469}
470
471func (a genericAccessor) SetNamespace(namespace string) {
472 if a.namespace == nil {
473 return
474 }
475 *a.namespace = namespace
476}
477
478func (a genericAccessor) GetName() string {
479 if a.name == nil {
480 return ""
481 }
482 return *a.name
483}
484
485func (a genericAccessor) SetName(name string) {
486 if a.name == nil {
487 return
488 }
489 *a.name = name
490}
491
492func (a genericAccessor) GetGenerateName() string {
493 if a.generateName == nil {
494 return ""
495 }
496 return *a.generateName
497}
498
499func (a genericAccessor) SetGenerateName(generateName string) {
500 if a.generateName == nil {
501 return
502 }
503 *a.generateName = generateName
504}
505
506func (a genericAccessor) GetUID() types.UID {
507 if a.uid == nil {
508 return ""
509 }
510 return *a.uid
511}
512
513func (a genericAccessor) SetUID(uid types.UID) {
514 if a.uid == nil {
515 return
516 }
517 *a.uid = uid
518}
519
520func (a genericAccessor) GetAPIVersion() string {
521 return *a.apiVersion
522}
523
524func (a genericAccessor) SetAPIVersion(version string) {
525 *a.apiVersion = version
526}
527
528func (a genericAccessor) GetKind() string {
529 return *a.kind
530}
531
532func (a genericAccessor) SetKind(kind string) {
533 *a.kind = kind
534}
535
536func (a genericAccessor) GetResourceVersion() string {
537 return *a.resourceVersion
538}
539
540func (a genericAccessor) SetResourceVersion(version string) {
541 *a.resourceVersion = version
542}
543
544func (a genericAccessor) GetSelfLink() string {
545 return *a.selfLink
546}
547
548func (a genericAccessor) SetSelfLink(selfLink string) {
549 *a.selfLink = selfLink
550}
551
552func (a genericAccessor) GetCreationTimestamp() metav1.Time {
553 return *a.creationTimestamp
554}
555
556func (a genericAccessor) SetCreationTimestamp(timestamp metav1.Time) {
557 *a.creationTimestamp = timestamp
558}
559
560func (a genericAccessor) GetDeletionTimestamp() *metav1.Time {
561 return *a.deletionTimestamp
562}
563
564func (a genericAccessor) SetDeletionTimestamp(timestamp *metav1.Time) {
565 *a.deletionTimestamp = timestamp
566}
567
568func (a genericAccessor) GetLabels() map[string]string {
569 if a.labels == nil {
570 return nil
571 }
572 return *a.labels
573}
574
575func (a genericAccessor) SetLabels(labels map[string]string) {
576 *a.labels = labels
577}
578
579func (a genericAccessor) GetAnnotations() map[string]string {
580 if a.annotations == nil {
581 return nil
582 }
583 return *a.annotations
584}
585
586func (a genericAccessor) SetAnnotations(annotations map[string]string) {
587 if a.annotations == nil {
588 emptyAnnotations := make(map[string]string)
589 a.annotations = &emptyAnnotations
590 }
591 *a.annotations = annotations
592}
593
594func (a genericAccessor) GetFinalizers() []string {
595 if a.finalizers == nil {
596 return nil
597 }
598 return *a.finalizers
599}
600
601func (a genericAccessor) SetFinalizers(finalizers []string) {
602 *a.finalizers = finalizers
603}
604
605func (a genericAccessor) GetOwnerReferences() []metav1.OwnerReference {
606 var ret []metav1.OwnerReference
607 s := a.ownerReferences
608 if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
David Bainbridge86971522019-09-26 22:09:39 +0000609 klog.Errorf("expect %v to be a pointer to slice", s)
Zack Williamse940c7a2019-08-21 14:25:39 -0700610 return ret
611 }
612 s = s.Elem()
613 // Set the capacity to one element greater to avoid copy if the caller later append an element.
614 ret = make([]metav1.OwnerReference, s.Len(), s.Len()+1)
615 for i := 0; i < s.Len(); i++ {
616 if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil {
David Bainbridge86971522019-09-26 22:09:39 +0000617 klog.Errorf("extractFromOwnerReference failed: %v", err)
Zack Williamse940c7a2019-08-21 14:25:39 -0700618 return ret
619 }
620 }
621 return ret
622}
623
624func (a genericAccessor) SetOwnerReferences(references []metav1.OwnerReference) {
625 s := a.ownerReferences
626 if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice {
David Bainbridge86971522019-09-26 22:09:39 +0000627 klog.Errorf("expect %v to be a pointer to slice", s)
Zack Williamse940c7a2019-08-21 14:25:39 -0700628 }
629 s = s.Elem()
630 newReferences := reflect.MakeSlice(s.Type(), len(references), len(references))
631 for i := 0; i < len(references); i++ {
632 if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil {
David Bainbridge86971522019-09-26 22:09:39 +0000633 klog.Errorf("setOwnerReference failed: %v", err)
Zack Williamse940c7a2019-08-21 14:25:39 -0700634 return
635 }
636 }
637 s.Set(newReferences)
638}
639
640// extractFromTypeMeta extracts pointers to version and kind fields from an object
641func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error {
642 if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil {
643 return err
644 }
645 if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil {
646 return err
647 }
648 return nil
649}