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