1/* 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} 649