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