diff options
Diffstat (limited to 'src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta')
9 files changed, 1895 insertions, 0 deletions
diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/doc.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/doc.go new file mode 100644 index 0000000..a3b18a5 --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package meta provides functions for retrieving API metadata from objects +// belonging to the Kubernetes API +package meta diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/errors.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/errors.go new file mode 100644 index 0000000..dc4ec07 --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/errors.go @@ -0,0 +1,72 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meta + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api/unversioned" +) + +// AmbiguousResourceError is returned if the RESTMapper finds multiple matches for a resource +type AmbiguousResourceError struct { + PartialResource unversioned.GroupVersionResource + + MatchingResources []unversioned.GroupVersionResource + MatchingKinds []unversioned.GroupVersionKind +} + +func (e *AmbiguousResourceError) Error() string { + switch { + case len(e.MatchingKinds) > 0 && len(e.MatchingResources) > 0: + return fmt.Sprintf("%v matches multiple resources %v and kinds %v", e.PartialResource, e.MatchingResources, e.MatchingKinds) + case len(e.MatchingKinds) > 0: + return fmt.Sprintf("%v matches multiple kinds %v", e.PartialResource, e.MatchingKinds) + case len(e.MatchingResources) > 0: + return fmt.Sprintf("%v matches multiple resources %v", e.PartialResource, e.MatchingResources) + + } + + return fmt.Sprintf("%v matches multiple resources or kinds", e.PartialResource) +} + +func IsAmbiguousResourceError(err error) bool { + if err == nil { + return false + } + + _, ok := err.(*AmbiguousResourceError) + return ok +} + +// NoResourceMatchError is returned if the RESTMapper can't find any match for a resource +type NoResourceMatchError struct { + PartialResource unversioned.GroupVersionResource +} + +func (e *NoResourceMatchError) Error() string { + return fmt.Sprintf("no matches for %v", e.PartialResource) +} + +func IsNoResourceMatchError(err error) bool { + if err == nil { + return false + } + + _, ok := err.(*NoResourceMatchError) + return ok +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/help.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/help.go new file mode 100644 index 0000000..0d733a5 --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/help.go @@ -0,0 +1,134 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meta + +import ( + "fmt" + "reflect" + + "k8s.io/kubernetes/pkg/conversion" + "k8s.io/kubernetes/pkg/runtime" +) + +// IsListType returns true if the provided Object has a slice called Items +func IsListType(obj runtime.Object) bool { + _, err := GetItemsPtr(obj) + return err == nil +} + +// GetItemsPtr returns a pointer to the list object's Items member. +// If 'list' doesn't have an Items member, it's not really a list type +// and an error will be returned. +// This function will either return a pointer to a slice, or an error, but not both. +func GetItemsPtr(list runtime.Object) (interface{}, error) { + v, err := conversion.EnforcePtr(list) + if err != nil { + return nil, err + } + items := v.FieldByName("Items") + if !items.IsValid() { + return nil, fmt.Errorf("no Items field in %#v", list) + } + switch items.Kind() { + case reflect.Interface, reflect.Ptr: + target := reflect.TypeOf(items.Interface()).Elem() + if target.Kind() != reflect.Slice { + return nil, fmt.Errorf("items: Expected slice, got %s", target.Kind()) + } + return items.Interface(), nil + case reflect.Slice: + return items.Addr().Interface(), nil + default: + return nil, fmt.Errorf("items: Expected slice, got %s", items.Kind()) + } +} + +// ExtractList returns obj's Items element as an array of runtime.Objects. +// Returns an error if obj is not a List type (does not have an Items member). +func ExtractList(obj runtime.Object) ([]runtime.Object, error) { + itemsPtr, err := GetItemsPtr(obj) + if err != nil { + return nil, err + } + items, err := conversion.EnforcePtr(itemsPtr) + if err != nil { + return nil, err + } + list := make([]runtime.Object, items.Len()) + for i := range list { + raw := items.Index(i) + switch item := raw.Interface().(type) { + case runtime.RawExtension: + switch { + case item.Object != nil: + list[i] = item.Object + case item.Raw != nil: + // TODO: Set ContentEncoding and ContentType correctly. + list[i] = &runtime.Unknown{Raw: item.Raw} + default: + list[i] = nil + } + case runtime.Object: + list[i] = item + default: + var found bool + if list[i], found = raw.Addr().Interface().(runtime.Object); !found { + return nil, fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind()) + } + } + } + return list, nil +} + +// objectSliceType is the type of a slice of Objects +var objectSliceType = reflect.TypeOf([]runtime.Object{}) + +// SetList sets the given list object's Items member have the elements given in +// objects. +// Returns an error if list is not a List type (does not have an Items member), +// or if any of the objects are not of the right type. +func SetList(list runtime.Object, objects []runtime.Object) error { + itemsPtr, err := GetItemsPtr(list) + if err != nil { + return err + } + items, err := conversion.EnforcePtr(itemsPtr) + if err != nil { + return err + } + if items.Type() == objectSliceType { + items.Set(reflect.ValueOf(objects)) + return nil + } + slice := reflect.MakeSlice(items.Type(), len(objects), len(objects)) + for i := range objects { + dest := slice.Index(i) + src, err := conversion.EnforcePtr(objects[i]) + if err != nil { + return err + } + if src.Type().AssignableTo(dest.Type()) { + dest.Set(src) + } else if src.Type().ConvertibleTo(dest.Type()) { + dest.Set(src.Convert(dest.Type())) + } else { + return fmt.Errorf("item[%d]: can't assign or convert %v into %v", i, src.Type(), dest.Type()) + } + } + items.Set(slice) + return nil +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/interfaces.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/interfaces.go new file mode 100644 index 0000000..34c51e3 --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/interfaces.go @@ -0,0 +1,180 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meta + +import ( + "k8s.io/kubernetes/pkg/api/meta/metatypes" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/types" +) + +// VersionInterfaces contains the interfaces one should use for dealing with types of a particular version. +type VersionInterfaces struct { + runtime.ObjectConvertor + MetadataAccessor +} + +type ObjectMetaAccessor interface { + GetObjectMeta() Object +} + +// Object lets you work with object metadata from any of the versioned or +// internal API objects. Attempting to set or retrieve a field on an object that does +// not support that field (Name, UID, Namespace on lists) will be a no-op and return +// a default value. +type Object interface { + GetNamespace() string + SetNamespace(namespace string) + GetName() string + SetName(name string) + GetGenerateName() string + SetGenerateName(name string) + GetUID() types.UID + SetUID(uid types.UID) + GetResourceVersion() string + SetResourceVersion(version string) + GetSelfLink() string + SetSelfLink(selfLink string) + GetCreationTimestamp() unversioned.Time + SetCreationTimestamp(timestamp unversioned.Time) + GetDeletionTimestamp() *unversioned.Time + SetDeletionTimestamp(timestamp *unversioned.Time) + GetLabels() map[string]string + SetLabels(labels map[string]string) + GetAnnotations() map[string]string + SetAnnotations(annotations map[string]string) + GetFinalizers() []string + SetFinalizers(finalizers []string) + GetOwnerReferences() []metatypes.OwnerReference + SetOwnerReferences([]metatypes.OwnerReference) +} + +var _ Object = &runtime.Unstructured{} + +type ListMetaAccessor interface { + GetListMeta() List +} + +// List lets you work with list metadata from any of the versioned or +// internal API objects. Attempting to set or retrieve a field on an object that does +// not support that field will be a no-op and return a default value. +type List unversioned.List + +// Type exposes the type and APIVersion of versioned or internal API objects. +type Type unversioned.Type + +// MetadataAccessor lets you work with object and list metadata from any of the versioned or +// internal API objects. Attempting to set or retrieve a field on an object that does +// not support that field (Name, UID, Namespace on lists) will be a no-op and return +// a default value. +// +// MetadataAccessor exposes Interface in a way that can be used with multiple objects. +type MetadataAccessor interface { + APIVersion(obj runtime.Object) (string, error) + SetAPIVersion(obj runtime.Object, version string) error + + Kind(obj runtime.Object) (string, error) + SetKind(obj runtime.Object, kind string) error + + Namespace(obj runtime.Object) (string, error) + SetNamespace(obj runtime.Object, namespace string) error + + Name(obj runtime.Object) (string, error) + SetName(obj runtime.Object, name string) error + + GenerateName(obj runtime.Object) (string, error) + SetGenerateName(obj runtime.Object, name string) error + + UID(obj runtime.Object) (types.UID, error) + SetUID(obj runtime.Object, uid types.UID) error + + SelfLink(obj runtime.Object) (string, error) + SetSelfLink(obj runtime.Object, selfLink string) error + + Labels(obj runtime.Object) (map[string]string, error) + SetLabels(obj runtime.Object, labels map[string]string) error + + Annotations(obj runtime.Object) (map[string]string, error) + SetAnnotations(obj runtime.Object, annotations map[string]string) error + + runtime.ResourceVersioner +} + +type RESTScopeName string + +const ( + RESTScopeNameNamespace RESTScopeName = "namespace" + RESTScopeNameRoot RESTScopeName = "root" +) + +// RESTScope contains the information needed to deal with REST resources that are in a resource hierarchy +type RESTScope interface { + // Name of the scope + Name() RESTScopeName + // ParamName is the optional name of the parameter that should be inserted in the resource url + // If empty, no param will be inserted + ParamName() string + // ArgumentName is the optional name that should be used for the variable holding the value. + ArgumentName() string + // ParamDescription is the optional description to use to document the parameter in api documentation + ParamDescription() string +} + +// RESTMapping contains the information needed to deal with objects of a specific +// resource and kind in a RESTful manner. +type RESTMapping struct { + // Resource is a string representing the name of this resource as a REST client would see it + Resource string + + GroupVersionKind unversioned.GroupVersionKind + + // Scope contains the information needed to deal with REST Resources that are in a resource hierarchy + Scope RESTScope + + runtime.ObjectConvertor + MetadataAccessor +} + +// RESTMapper allows clients to map resources to kind, and map kind and version +// to interfaces for manipulating those objects. It is primarily intended for +// consumers of Kubernetes compatible REST APIs as defined in docs/devel/api-conventions.md. +// +// The Kubernetes API provides versioned resources and object kinds which are scoped +// to API groups. In other words, kinds and resources should not be assumed to be +// unique across groups. +// +// TODO(caesarxuchao): Add proper multi-group support so that kinds & resources are +// scoped to groups. See http://issues.k8s.io/12413 and http://issues.k8s.io/10009. +type RESTMapper interface { + // KindFor takes a partial resource and returns back the single match. Returns an error if there are multiple matches + KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) + + // KindsFor takes a partial resource and returns back the list of potential kinds in priority order + KindsFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) + + // ResourceFor takes a partial resource and returns back the single match. Returns an error if there are multiple matches + ResourceFor(input unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) + + // ResourcesFor takes a partial resource and returns back the list of potential resource in priority order + ResourcesFor(input unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) + + RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) + + AliasesForResource(resource string) ([]string, bool) + ResourceSingularizer(resource string) (singular string, err error) +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/meta.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/meta.go new file mode 100644 index 0000000..876aa4f --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/meta.go @@ -0,0 +1,567 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meta + +import ( + "fmt" + "reflect" + + "k8s.io/kubernetes/pkg/api/meta/metatypes" + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/conversion" + "k8s.io/kubernetes/pkg/runtime" + "k8s.io/kubernetes/pkg/types" + + "github.com/golang/glog" +) + +// errNotList is returned when an object implements the Object style interfaces but not the List style +// interfaces. +var errNotList = fmt.Errorf("object does not implement the List interfaces") + +// ListAccessor returns a List interface for the provided object or an error if the object does +// not provide List. +// IMPORTANT: Objects are a superset of lists, so all Objects return List metadata. Do not use this +// check to determine whether an object *is* a List. +// TODO: return bool instead of error +func ListAccessor(obj interface{}) (List, error) { + switch t := obj.(type) { + case List: + return t, nil + case unversioned.List: + return t, nil + case ListMetaAccessor: + if m := t.GetListMeta(); m != nil { + return m, nil + } + return nil, errNotList + case unversioned.ListMetaAccessor: + if m := t.GetListMeta(); m != nil { + return m, nil + } + return nil, errNotList + case Object: + return t, nil + case ObjectMetaAccessor: + if m := t.GetObjectMeta(); m != nil { + return m, nil + } + return nil, errNotList + default: + return nil, errNotList + } +} + +// errNotObject is returned when an object implements the List style interfaces but not the Object style +// interfaces. +var errNotObject = fmt.Errorf("object does not implement the Object interfaces") + +// Accessor takes an arbitrary object pointer and returns meta.Interface. +// obj must be a pointer to an API type. An error is returned if the minimum +// required fields are missing. Fields that are not required return the default +// value and are a no-op if set. +// TODO: return bool instead of error +func Accessor(obj interface{}) (Object, error) { + switch t := obj.(type) { + case Object: + return t, nil + case ObjectMetaAccessor: + if m := t.GetObjectMeta(); m != nil { + return m, nil + } + return nil, errNotObject + case List, unversioned.List, ListMetaAccessor, unversioned.ListMetaAccessor: + return nil, errNotObject + default: + return nil, errNotObject + } +} + +// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion +// and Kind of an in-memory internal object. +// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta +// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube +// api conventions). +func TypeAccessor(obj interface{}) (Type, error) { + if typed, ok := obj.(runtime.Object); ok { + return objectAccessor{typed}, nil + } + v, err := conversion.EnforcePtr(obj) + if err != nil { + return nil, err + } + t := v.Type() + if v.Kind() != reflect.Struct { + return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface()) + } + + typeMeta := v.FieldByName("TypeMeta") + if !typeMeta.IsValid() { + return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t) + } + a := &genericAccessor{} + if err := extractFromTypeMeta(typeMeta, a); err != nil { + return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err) + } + return a, nil +} + +type objectAccessor struct { + runtime.Object +} + +func (obj objectAccessor) GetKind() string { + return obj.GetObjectKind().GroupVersionKind().Kind +} + +func (obj objectAccessor) SetKind(kind string) { + gvk := obj.GetObjectKind().GroupVersionKind() + gvk.Kind = kind + obj.GetObjectKind().SetGroupVersionKind(gvk) +} + +func (obj objectAccessor) GetAPIVersion() string { + return obj.GetObjectKind().GroupVersionKind().GroupVersion().String() +} + +func (obj objectAccessor) SetAPIVersion(version string) { + gvk := obj.GetObjectKind().GroupVersionKind() + gv, err := unversioned.ParseGroupVersion(version) + if err != nil { + gv = unversioned.GroupVersion{Version: version} + } + gvk.Group, gvk.Version = gv.Group, gv.Version + obj.GetObjectKind().SetGroupVersionKind(gvk) +} + +// NewAccessor returns a MetadataAccessor that can retrieve +// or manipulate resource version on objects derived from core API +// metadata concepts. +func NewAccessor() MetadataAccessor { + return resourceAccessor{} +} + +// resourceAccessor implements ResourceVersioner and SelfLinker. +type resourceAccessor struct{} + +func (resourceAccessor) Kind(obj runtime.Object) (string, error) { + return objectAccessor{obj}.GetKind(), nil +} + +func (resourceAccessor) SetKind(obj runtime.Object, kind string) error { + objectAccessor{obj}.SetKind(kind) + return nil +} + +func (resourceAccessor) APIVersion(obj runtime.Object) (string, error) { + return objectAccessor{obj}.GetAPIVersion(), nil +} + +func (resourceAccessor) SetAPIVersion(obj runtime.Object, version string) error { + objectAccessor{obj}.SetAPIVersion(version) + return nil +} + +func (resourceAccessor) Namespace(obj runtime.Object) (string, error) { + accessor, err := Accessor(obj) + if err != nil { + return "", err + } + return accessor.GetNamespace(), nil +} + +func (resourceAccessor) SetNamespace(obj runtime.Object, namespace string) error { + accessor, err := Accessor(obj) + if err != nil { + return err + } + accessor.SetNamespace(namespace) + return nil +} + +func (resourceAccessor) Name(obj runtime.Object) (string, error) { + accessor, err := Accessor(obj) + if err != nil { + return "", err + } + return accessor.GetName(), nil +} + +func (resourceAccessor) SetName(obj runtime.Object, name string) error { + accessor, err := Accessor(obj) + if err != nil { + return err + } + accessor.SetName(name) + return nil +} + +func (resourceAccessor) GenerateName(obj runtime.Object) (string, error) { + accessor, err := Accessor(obj) + if err != nil { + return "", err + } + return accessor.GetGenerateName(), nil +} + +func (resourceAccessor) SetGenerateName(obj runtime.Object, name string) error { + accessor, err := Accessor(obj) + if err != nil { + return err + } + accessor.SetGenerateName(name) + return nil +} + +func (resourceAccessor) UID(obj runtime.Object) (types.UID, error) { + accessor, err := Accessor(obj) + if err != nil { + return "", err + } + return accessor.GetUID(), nil +} + +func (resourceAccessor) SetUID(obj runtime.Object, uid types.UID) error { + accessor, err := Accessor(obj) + if err != nil { + return err + } + accessor.SetUID(uid) + return nil +} + +func (resourceAccessor) SelfLink(obj runtime.Object) (string, error) { + accessor, err := ListAccessor(obj) + if err != nil { + return "", err + } + return accessor.GetSelfLink(), nil +} + +func (resourceAccessor) SetSelfLink(obj runtime.Object, selfLink string) error { + accessor, err := ListAccessor(obj) + if err != nil { + return err + } + accessor.SetSelfLink(selfLink) + return nil +} + +func (resourceAccessor) Labels(obj runtime.Object) (map[string]string, error) { + accessor, err := Accessor(obj) + if err != nil { + return nil, err + } + return accessor.GetLabels(), nil +} + +func (resourceAccessor) SetLabels(obj runtime.Object, labels map[string]string) error { + accessor, err := Accessor(obj) + if err != nil { + return err + } + accessor.SetLabels(labels) + return nil +} + +func (resourceAccessor) Annotations(obj runtime.Object) (map[string]string, error) { + accessor, err := Accessor(obj) + if err != nil { + return nil, err + } + return accessor.GetAnnotations(), nil +} + +func (resourceAccessor) SetAnnotations(obj runtime.Object, annotations map[string]string) error { + accessor, err := Accessor(obj) + if err != nil { + return err + } + accessor.SetAnnotations(annotations) + return nil +} + +func (resourceAccessor) ResourceVersion(obj runtime.Object) (string, error) { + accessor, err := ListAccessor(obj) + if err != nil { + return "", err + } + return accessor.GetResourceVersion(), nil +} + +func (resourceAccessor) SetResourceVersion(obj runtime.Object, version string) error { + accessor, err := ListAccessor(obj) + if err != nil { + return err + } + accessor.SetResourceVersion(version) + return nil +} + +// extractFromOwnerReference extracts v to o. v is the OwnerReferences field of an object. +func extractFromOwnerReference(v reflect.Value, o *metatypes.OwnerReference) error { + if err := runtime.Field(v, "APIVersion", &o.APIVersion); err != nil { + return err + } + if err := runtime.Field(v, "Kind", &o.Kind); err != nil { + return err + } + if err := runtime.Field(v, "Name", &o.Name); err != nil { + return err + } + if err := runtime.Field(v, "UID", &o.UID); err != nil { + return err + } + var controllerPtr *bool + if err := runtime.Field(v, "Controller", &controllerPtr); err != nil { + return err + } + if controllerPtr != nil { + controller := *controllerPtr + o.Controller = &controller + } + return nil +} + +// setOwnerReference sets v to o. v is the OwnerReferences field of an object. +func setOwnerReference(v reflect.Value, o *metatypes.OwnerReference) error { + if err := runtime.SetField(o.APIVersion, v, "APIVersion"); err != nil { + return err + } + if err := runtime.SetField(o.Kind, v, "Kind"); err != nil { + return err + } + if err := runtime.SetField(o.Name, v, "Name"); err != nil { + return err + } + if err := runtime.SetField(o.UID, v, "UID"); err != nil { + return err + } + if o.Controller != nil { + controller := *(o.Controller) + if err := runtime.SetField(&controller, v, "Controller"); err != nil { + return err + } + } + return nil +} + +// genericAccessor contains pointers to strings that can modify an arbitrary +// struct and implements the Accessor interface. +type genericAccessor struct { + namespace *string + name *string + generateName *string + uid *types.UID + apiVersion *string + kind *string + resourceVersion *string + selfLink *string + creationTimestamp *unversioned.Time + deletionTimestamp **unversioned.Time + labels *map[string]string + annotations *map[string]string + ownerReferences reflect.Value + finalizers *[]string +} + +func (a genericAccessor) GetNamespace() string { + if a.namespace == nil { + return "" + } + return *a.namespace +} + +func (a genericAccessor) SetNamespace(namespace string) { + if a.namespace == nil { + return + } + *a.namespace = namespace +} + +func (a genericAccessor) GetName() string { + if a.name == nil { + return "" + } + return *a.name +} + +func (a genericAccessor) SetName(name string) { + if a.name == nil { + return + } + *a.name = name +} + +func (a genericAccessor) GetGenerateName() string { + if a.generateName == nil { + return "" + } + return *a.generateName +} + +func (a genericAccessor) SetGenerateName(generateName string) { + if a.generateName == nil { + return + } + *a.generateName = generateName +} + +func (a genericAccessor) GetUID() types.UID { + if a.uid == nil { + return "" + } + return *a.uid +} + +func (a genericAccessor) SetUID(uid types.UID) { + if a.uid == nil { + return + } + *a.uid = uid +} + +func (a genericAccessor) GetAPIVersion() string { + return *a.apiVersion +} + +func (a genericAccessor) SetAPIVersion(version string) { + *a.apiVersion = version +} + +func (a genericAccessor) GetKind() string { + return *a.kind +} + +func (a genericAccessor) SetKind(kind string) { + *a.kind = kind +} + +func (a genericAccessor) GetResourceVersion() string { + return *a.resourceVersion +} + +func (a genericAccessor) SetResourceVersion(version string) { + *a.resourceVersion = version +} + +func (a genericAccessor) GetSelfLink() string { + return *a.selfLink +} + +func (a genericAccessor) SetSelfLink(selfLink string) { + *a.selfLink = selfLink +} + +func (a genericAccessor) GetCreationTimestamp() unversioned.Time { + return *a.creationTimestamp +} + +func (a genericAccessor) SetCreationTimestamp(timestamp unversioned.Time) { + *a.creationTimestamp = timestamp +} + +func (a genericAccessor) GetDeletionTimestamp() *unversioned.Time { + return *a.deletionTimestamp +} + +func (a genericAccessor) SetDeletionTimestamp(timestamp *unversioned.Time) { + *a.deletionTimestamp = timestamp +} + +func (a genericAccessor) GetLabels() map[string]string { + if a.labels == nil { + return nil + } + return *a.labels +} + +func (a genericAccessor) SetLabels(labels map[string]string) { + *a.labels = labels +} + +func (a genericAccessor) GetAnnotations() map[string]string { + if a.annotations == nil { + return nil + } + return *a.annotations +} + +func (a genericAccessor) SetAnnotations(annotations map[string]string) { + if a.annotations == nil { + emptyAnnotations := make(map[string]string) + a.annotations = &emptyAnnotations + } + *a.annotations = annotations +} + +func (a genericAccessor) GetFinalizers() []string { + if a.finalizers == nil { + return nil + } + return *a.finalizers +} + +func (a genericAccessor) SetFinalizers(finalizers []string) { + *a.finalizers = finalizers +} + +func (a genericAccessor) GetOwnerReferences() []metatypes.OwnerReference { + var ret []metatypes.OwnerReference + s := a.ownerReferences + if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice { + glog.Errorf("expect %v to be a pointer to slice", s) + return ret + } + s = s.Elem() + // Set the capacity to one element greater to avoid copy if the caller later append an element. + ret = make([]metatypes.OwnerReference, s.Len(), s.Len()+1) + for i := 0; i < s.Len(); i++ { + if err := extractFromOwnerReference(s.Index(i), &ret[i]); err != nil { + glog.Errorf("extractFromOwnerReference failed: %v", err) + return ret + } + } + return ret +} + +func (a genericAccessor) SetOwnerReferences(references []metatypes.OwnerReference) { + s := a.ownerReferences + if s.Kind() != reflect.Ptr || s.Elem().Kind() != reflect.Slice { + glog.Errorf("expect %v to be a pointer to slice", s) + } + s = s.Elem() + newReferences := reflect.MakeSlice(s.Type(), len(references), len(references)) + for i := 0; i < len(references); i++ { + if err := setOwnerReference(newReferences.Index(i), &references[i]); err != nil { + glog.Errorf("setOwnerReference failed: %v", err) + return + } + } + s.Set(newReferences) +} + +// extractFromTypeMeta extracts pointers to version and kind fields from an object +func extractFromTypeMeta(v reflect.Value, a *genericAccessor) error { + if err := runtime.FieldPtr(v, "APIVersion", &a.apiVersion); err != nil { + return err + } + if err := runtime.FieldPtr(v, "Kind", &a.kind); err != nil { + return err + } + return nil +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/types.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/types.go new file mode 100644 index 0000000..41e6596 --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/types.go @@ -0,0 +1,30 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// The types defined in this package are used by the meta package to represent +// the in-memory version of objects. We cannot reuse the __internal version of +// API objects because it causes import cycle. +package metatypes + +import "k8s.io/kubernetes/pkg/types" + +type OwnerReference struct { + APIVersion string + Kind string + UID types.UID + Name string + Controller *bool +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper.go new file mode 100644 index 0000000..790795a --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper.go @@ -0,0 +1,200 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meta + +import ( + "fmt" + "strings" + + "k8s.io/kubernetes/pkg/api/unversioned" + utilerrors "k8s.io/kubernetes/pkg/util/errors" + "k8s.io/kubernetes/pkg/util/sets" +) + +// MultiRESTMapper is a wrapper for multiple RESTMappers. +type MultiRESTMapper []RESTMapper + +func (m MultiRESTMapper) String() string { + nested := []string{} + for _, t := range m { + currString := fmt.Sprintf("%v", t) + splitStrings := strings.Split(currString, "\n") + nested = append(nested, strings.Join(splitStrings, "\n\t")) + } + + return fmt.Sprintf("MultiRESTMapper{\n\t%s\n}", strings.Join(nested, "\n\t")) +} + +// ResourceSingularizer converts a REST resource name from plural to singular (e.g., from pods to pod) +// This implementation supports multiple REST schemas and return the first match. +func (m MultiRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { + for _, t := range m { + singular, err = t.ResourceSingularizer(resource) + if err == nil { + return + } + } + return +} + +func (m MultiRESTMapper) ResourcesFor(resource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) { + allGVRs := []unversioned.GroupVersionResource{} + for _, t := range m { + gvrs, err := t.ResourcesFor(resource) + // ignore "no match" errors, but any other error percolates back up + if IsNoResourceMatchError(err) { + continue + } + if err != nil { + return nil, err + } + + // walk the existing values to de-dup + for _, curr := range gvrs { + found := false + for _, existing := range allGVRs { + if curr == existing { + found = true + break + } + } + + if !found { + allGVRs = append(allGVRs, curr) + } + } + } + + if len(allGVRs) == 0 { + return nil, &NoResourceMatchError{PartialResource: resource} + } + + return allGVRs, nil +} + +func (m MultiRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) { + allGVKs := []unversioned.GroupVersionKind{} + for _, t := range m { + gvks, err := t.KindsFor(resource) + // ignore "no match" errors, but any other error percolates back up + if IsNoResourceMatchError(err) { + continue + } + if err != nil { + return nil, err + } + + // walk the existing values to de-dup + for _, curr := range gvks { + found := false + for _, existing := range allGVKs { + if curr == existing { + found = true + break + } + } + + if !found { + allGVKs = append(allGVKs, curr) + } + } + } + + if len(allGVKs) == 0 { + return nil, &NoResourceMatchError{PartialResource: resource} + } + + return allGVKs, nil +} + +func (m MultiRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) { + resources, err := m.ResourcesFor(resource) + if err != nil { + return unversioned.GroupVersionResource{}, err + } + if len(resources) == 1 { + return resources[0], nil + } + + return unversioned.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources} +} + +func (m MultiRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) { + kinds, err := m.KindsFor(resource) + if err != nil { + return unversioned.GroupVersionKind{}, err + } + if len(kinds) == 1 { + return kinds[0], nil + } + + return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds} +} + +// RESTMapping provides the REST mapping for the resource based on the +// kind and version. This implementation supports multiple REST schemas and +// return the first match. +func (m MultiRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) { + allMappings := []*RESTMapping{} + errors := []error{} + + for _, t := range m { + currMapping, err := t.RESTMapping(gk, versions...) + // ignore "no match" errors, but any other error percolates back up + if IsNoResourceMatchError(err) { + continue + } + if err != nil { + errors = append(errors, err) + continue + } + + allMappings = append(allMappings, currMapping) + } + + // if we got exactly one mapping, then use it even if other requested failed + if len(allMappings) == 1 { + return allMappings[0], nil + } + if len(allMappings) > 1 { + return nil, fmt.Errorf("multiple matches found for %v in %v", gk, versions) + } + if len(errors) > 0 { + return nil, utilerrors.NewAggregate(errors) + } + return nil, fmt.Errorf("no match found for %v in %v", gk, versions) +} + +// AliasesForResource finds the first alias response for the provided mappers. +func (m MultiRESTMapper) AliasesForResource(alias string) ([]string, bool) { + seenAliases := sets.NewString() + allAliases := []string{} + handled := false + + for _, t := range m { + if currAliases, currOk := t.AliasesForResource(alias); currOk { + for _, currAlias := range currAliases { + if !seenAliases.Has(currAlias) { + allAliases = append(allAliases, currAlias) + seenAliases.Insert(currAlias) + } + } + handled = true + } + } + return allAliases, handled +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/priority.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/priority.go new file mode 100644 index 0000000..1e44e45 --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/priority.go @@ -0,0 +1,173 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meta + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api/unversioned" +) + +const ( + AnyGroup = "*" + AnyVersion = "*" + AnyResource = "*" + AnyKind = "*" +) + +// PriorityRESTMapper is a wrapper for automatically choosing a particular Resource or Kind +// when multiple matches are possible +type PriorityRESTMapper struct { + // Delegate is the RESTMapper to use to locate all the Kind and Resource matches + Delegate RESTMapper + + // ResourcePriority is a list of priority patterns to apply to matching resources. + // The list of all matching resources is narrowed based on the patterns until only one remains. + // A pattern with no matches is skipped. A pattern with more than one match uses its + // matches as the list to continue matching against. + ResourcePriority []unversioned.GroupVersionResource + + // KindPriority is a list of priority patterns to apply to matching kinds. + // The list of all matching kinds is narrowed based on the patterns until only one remains. + // A pattern with no matches is skipped. A pattern with more than one match uses its + // matches as the list to continue matching against. + KindPriority []unversioned.GroupVersionKind +} + +func (m PriorityRESTMapper) String() string { + return fmt.Sprintf("PriorityRESTMapper{\n\t%v\n\t%v\n\t%v\n}", m.ResourcePriority, m.KindPriority, m.Delegate) +} + +// ResourceFor finds all resources, then passes them through the ResourcePriority patterns to find a single matching hit. +func (m PriorityRESTMapper) ResourceFor(partiallySpecifiedResource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) { + originalGVRs, err := m.Delegate.ResourcesFor(partiallySpecifiedResource) + if err != nil { + return unversioned.GroupVersionResource{}, err + } + if len(originalGVRs) == 1 { + return originalGVRs[0], nil + } + + remainingGVRs := append([]unversioned.GroupVersionResource{}, originalGVRs...) + for _, pattern := range m.ResourcePriority { + matchedGVRs := []unversioned.GroupVersionResource{} + for _, gvr := range remainingGVRs { + if resourceMatches(pattern, gvr) { + matchedGVRs = append(matchedGVRs, gvr) + } + } + + switch len(matchedGVRs) { + case 0: + // if you have no matches, then nothing matched this pattern just move to the next + continue + case 1: + // one match, return + return matchedGVRs[0], nil + default: + // more than one match, use the matched hits as the list moving to the next pattern. + // this way you can have a series of selection criteria + remainingGVRs = matchedGVRs + } + } + + return unversioned.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingResources: originalGVRs} +} + +// KindFor finds all kinds, then passes them through the KindPriority patterns to find a single matching hit. +func (m PriorityRESTMapper) KindFor(partiallySpecifiedResource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) { + originalGVKs, err := m.Delegate.KindsFor(partiallySpecifiedResource) + if err != nil { + return unversioned.GroupVersionKind{}, err + } + if len(originalGVKs) == 1 { + return originalGVKs[0], nil + } + + remainingGVKs := append([]unversioned.GroupVersionKind{}, originalGVKs...) + for _, pattern := range m.KindPriority { + matchedGVKs := []unversioned.GroupVersionKind{} + for _, gvr := range remainingGVKs { + if kindMatches(pattern, gvr) { + matchedGVKs = append(matchedGVKs, gvr) + } + } + + switch len(matchedGVKs) { + case 0: + // if you have no matches, then nothing matched this pattern just move to the next + continue + case 1: + // one match, return + return matchedGVKs[0], nil + default: + // more than one match, use the matched hits as the list moving to the next pattern. + // this way you can have a series of selection criteria + remainingGVKs = matchedGVKs + } + } + + return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs} +} + +func resourceMatches(pattern unversioned.GroupVersionResource, resource unversioned.GroupVersionResource) bool { + if pattern.Group != AnyGroup && pattern.Group != resource.Group { + return false + } + if pattern.Version != AnyVersion && pattern.Version != resource.Version { + return false + } + if pattern.Resource != AnyResource && pattern.Resource != resource.Resource { + return false + } + + return true +} + +func kindMatches(pattern unversioned.GroupVersionKind, kind unversioned.GroupVersionKind) bool { + if pattern.Group != AnyGroup && pattern.Group != kind.Group { + return false + } + if pattern.Version != AnyVersion && pattern.Version != kind.Version { + return false + } + if pattern.Kind != AnyKind && pattern.Kind != kind.Kind { + return false + } + + return true +} + +func (m PriorityRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (mapping *RESTMapping, err error) { + return m.Delegate.RESTMapping(gk, versions...) +} + +func (m PriorityRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) { + return m.Delegate.AliasesForResource(alias) +} + +func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) { + return m.Delegate.ResourceSingularizer(resource) +} + +func (m PriorityRESTMapper) ResourcesFor(partiallySpecifiedResource unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) { + return m.Delegate.ResourcesFor(partiallySpecifiedResource) +} + +func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource unversioned.GroupVersionResource) (gvk []unversioned.GroupVersionKind, err error) { + return m.Delegate.KindsFor(partiallySpecifiedResource) +} diff --git a/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/restmapper.go b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/restmapper.go new file mode 100644 index 0000000..bf2567e --- /dev/null +++ b/src/kube2msb/vendor/k8s.io/kubernetes/pkg/api/meta/restmapper.go @@ -0,0 +1,520 @@ +/* +Copyright 2014 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// TODO: move everything in this file to pkg/api/rest +package meta + +import ( + "fmt" + "sort" + "strings" + + "k8s.io/kubernetes/pkg/api/unversioned" + "k8s.io/kubernetes/pkg/runtime" +) + +// Implements RESTScope interface +type restScope struct { + name RESTScopeName + paramName string + argumentName string + paramDescription string +} + +func (r *restScope) Name() RESTScopeName { + return r.name +} +func (r *restScope) ParamName() string { + return r.paramName +} +func (r *restScope) ArgumentName() string { + return r.argumentName +} +func (r *restScope) ParamDescription() string { + return r.paramDescription +} + +var RESTScopeNamespace = &restScope{ + name: RESTScopeNameNamespace, + paramName: "namespaces", + argumentName: "namespace", + paramDescription: "object name and auth scope, such as for teams and projects", +} + +var RESTScopeRoot = &restScope{ + name: RESTScopeNameRoot, +} + +// DefaultRESTMapper exposes mappings between the types defined in a +// runtime.Scheme. It assumes that all types defined the provided scheme +// can be mapped with the provided MetadataAccessor and Codec interfaces. +// +// The resource name of a Kind is defined as the lowercase, +// English-plural version of the Kind string. +// When converting from resource to Kind, the singular version of the +// resource name is also accepted for convenience. +// +// TODO: Only accept plural for some operations for increased control? +// (`get pod bar` vs `get pods bar`) +type DefaultRESTMapper struct { + defaultGroupVersions []unversioned.GroupVersion + + resourceToKind map[unversioned.GroupVersionResource]unversioned.GroupVersionKind + kindToPluralResource map[unversioned.GroupVersionKind]unversioned.GroupVersionResource + kindToScope map[unversioned.GroupVersionKind]RESTScope + singularToPlural map[unversioned.GroupVersionResource]unversioned.GroupVersionResource + pluralToSingular map[unversioned.GroupVersionResource]unversioned.GroupVersionResource + + interfacesFunc VersionInterfacesFunc + + // aliasToResource is used for mapping aliases to resources + aliasToResource map[string][]string +} + +func (m *DefaultRESTMapper) String() string { + return fmt.Sprintf("DefaultRESTMapper{kindToPluralResource=%v}", m.kindToPluralResource) +} + +var _ RESTMapper = &DefaultRESTMapper{} + +// VersionInterfacesFunc returns the appropriate typer, and metadata accessor for a +// given api version, or an error if no such api version exists. +type VersionInterfacesFunc func(version unversioned.GroupVersion) (*VersionInterfaces, error) + +// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion +// to a resource name and back based on the objects in a runtime.Scheme +// and the Kubernetes API conventions. Takes a group name, a priority list of the versions +// to search when an object has no default version (set empty to return an error), +// and a function that retrieves the correct metadata for a given version. +func NewDefaultRESTMapper(defaultGroupVersions []unversioned.GroupVersion, f VersionInterfacesFunc) *DefaultRESTMapper { + resourceToKind := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionKind) + kindToPluralResource := make(map[unversioned.GroupVersionKind]unversioned.GroupVersionResource) + kindToScope := make(map[unversioned.GroupVersionKind]RESTScope) + singularToPlural := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionResource) + pluralToSingular := make(map[unversioned.GroupVersionResource]unversioned.GroupVersionResource) + aliasToResource := make(map[string][]string) + // TODO: verify name mappings work correctly when versions differ + + return &DefaultRESTMapper{ + resourceToKind: resourceToKind, + kindToPluralResource: kindToPluralResource, + kindToScope: kindToScope, + defaultGroupVersions: defaultGroupVersions, + singularToPlural: singularToPlural, + pluralToSingular: pluralToSingular, + aliasToResource: aliasToResource, + interfacesFunc: f, + } +} + +func (m *DefaultRESTMapper) Add(kind unversioned.GroupVersionKind, scope RESTScope) { + plural, singular := KindToResource(kind) + + m.singularToPlural[singular] = plural + m.pluralToSingular[plural] = singular + + m.resourceToKind[singular] = kind + m.resourceToKind[plural] = kind + + m.kindToPluralResource[kind] = plural + m.kindToScope[kind] = scope +} + +// unpluralizedSuffixes is a list of resource suffixes that are the same plural and singular +// This is only is only necessary because some bits of code are lazy and don't actually use the RESTMapper like they should. +// TODO eliminate this so that different callers can correctly map to resources. This probably means updating all +// callers to use the RESTMapper they mean. +var unpluralizedSuffixes = []string{ + "endpoints", +} + +// KindToResource converts Kind to a resource name. +// Broken. This method only "sort of" works when used outside of this package. It assumes that Kinds and Resources match +// and they aren't guaranteed to do so. +func KindToResource(kind unversioned.GroupVersionKind) ( /*plural*/ unversioned.GroupVersionResource /*singular*/, unversioned.GroupVersionResource) { + kindName := kind.Kind + if len(kindName) == 0 { + return unversioned.GroupVersionResource{}, unversioned.GroupVersionResource{} + } + singularName := strings.ToLower(kindName) + singular := kind.GroupVersion().WithResource(singularName) + + for _, skip := range unpluralizedSuffixes { + if strings.HasSuffix(singularName, skip) { + return singular, singular + } + } + + switch string(singularName[len(singularName)-1]) { + case "s": + return kind.GroupVersion().WithResource(singularName + "es"), singular + case "y": + return kind.GroupVersion().WithResource(strings.TrimSuffix(singularName, "y") + "ies"), singular + } + + return kind.GroupVersion().WithResource(singularName + "s"), singular +} + +// ResourceSingularizer implements RESTMapper +// It converts a resource name from plural to singular (e.g., from pods to pod) +func (m *DefaultRESTMapper) ResourceSingularizer(resourceType string) (string, error) { + partialResource := unversioned.GroupVersionResource{Resource: resourceType} + resources, err := m.ResourcesFor(partialResource) + if err != nil { + return resourceType, err + } + + singular := unversioned.GroupVersionResource{} + for _, curr := range resources { + currSingular, ok := m.pluralToSingular[curr] + if !ok { + continue + } + if singular.IsEmpty() { + singular = currSingular + continue + } + + if currSingular.Resource != singular.Resource { + return resourceType, fmt.Errorf("multiple possibile singular resources (%v) found for %v", resources, resourceType) + } + } + + if singular.IsEmpty() { + return resourceType, fmt.Errorf("no singular of resource %v has been defined", resourceType) + } + + return singular.Resource, nil +} + +// coerceResourceForMatching makes the resource lower case and converts internal versions to unspecified (legacy behavior) +func coerceResourceForMatching(resource unversioned.GroupVersionResource) unversioned.GroupVersionResource { + resource.Resource = strings.ToLower(resource.Resource) + if resource.Version == runtime.APIVersionInternal { + resource.Version = "" + } + + return resource +} + +func (m *DefaultRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) ([]unversioned.GroupVersionResource, error) { + resource := coerceResourceForMatching(input) + + hasResource := len(resource.Resource) > 0 + hasGroup := len(resource.Group) > 0 + hasVersion := len(resource.Version) > 0 + + if !hasResource { + return nil, fmt.Errorf("a resource must be present, got: %v", resource) + } + + ret := []unversioned.GroupVersionResource{} + switch { + // fully qualified. Find the exact match + case hasGroup && hasVersion: + for plural, singular := range m.pluralToSingular { + if singular == resource { + ret = append(ret, plural) + break + } + if plural == resource { + ret = append(ret, plural) + break + } + } + + case hasGroup: + requestedGroupResource := resource.GroupResource() + for plural, singular := range m.pluralToSingular { + if singular.GroupResource() == requestedGroupResource { + ret = append(ret, plural) + } + if plural.GroupResource() == requestedGroupResource { + ret = append(ret, plural) + } + } + + case hasVersion: + for plural, singular := range m.pluralToSingular { + if singular.Version == resource.Version && singular.Resource == resource.Resource { + ret = append(ret, plural) + } + if plural.Version == resource.Version && plural.Resource == resource.Resource { + ret = append(ret, plural) + } + } + + default: + for plural, singular := range m.pluralToSingular { + if singular.Resource == resource.Resource { + ret = append(ret, plural) + } + if plural.Resource == resource.Resource { + ret = append(ret, plural) + } + } + } + + if len(ret) == 0 { + return nil, &NoResourceMatchError{PartialResource: resource} + } + + sort.Sort(resourceByPreferredGroupVersion{ret, m.defaultGroupVersions}) + return ret, nil +} + +func (m *DefaultRESTMapper) ResourceFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionResource, error) { + resources, err := m.ResourcesFor(resource) + if err != nil { + return unversioned.GroupVersionResource{}, err + } + if len(resources) == 1 { + return resources[0], nil + } + + return unversioned.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources} +} + +func (m *DefaultRESTMapper) KindsFor(input unversioned.GroupVersionResource) ([]unversioned.GroupVersionKind, error) { + resource := coerceResourceForMatching(input) + + hasResource := len(resource.Resource) > 0 + hasGroup := len(resource.Group) > 0 + hasVersion := len(resource.Version) > 0 + + if !hasResource { + return nil, fmt.Errorf("a resource must be present, got: %v", resource) + } + + ret := []unversioned.GroupVersionKind{} + switch { + // fully qualified. Find the exact match + case hasGroup && hasVersion: + kind, exists := m.resourceToKind[resource] + if exists { + ret = append(ret, kind) + } + + case hasGroup: + requestedGroupResource := resource.GroupResource() + for currResource, currKind := range m.resourceToKind { + if currResource.GroupResource() == requestedGroupResource { + ret = append(ret, currKind) + } + } + + case hasVersion: + for currResource, currKind := range m.resourceToKind { + if currResource.Version == resource.Version && currResource.Resource == resource.Resource { + ret = append(ret, currKind) + } + } + + default: + for currResource, currKind := range m.resourceToKind { + if currResource.Resource == resource.Resource { + ret = append(ret, currKind) + } + } + } + + if len(ret) == 0 { + return nil, &NoResourceMatchError{PartialResource: input} + } + + sort.Sort(kindByPreferredGroupVersion{ret, m.defaultGroupVersions}) + return ret, nil +} + +func (m *DefaultRESTMapper) KindFor(resource unversioned.GroupVersionResource) (unversioned.GroupVersionKind, error) { + kinds, err := m.KindsFor(resource) + if err != nil { + return unversioned.GroupVersionKind{}, err + } + if len(kinds) == 1 { + return kinds[0], nil + } + + return unversioned.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: resource, MatchingKinds: kinds} +} + +type kindByPreferredGroupVersion struct { + list []unversioned.GroupVersionKind + sortOrder []unversioned.GroupVersion +} + +func (o kindByPreferredGroupVersion) Len() int { return len(o.list) } +func (o kindByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] } +func (o kindByPreferredGroupVersion) Less(i, j int) bool { + lhs := o.list[i] + rhs := o.list[j] + if lhs == rhs { + return false + } + + if lhs.GroupVersion() == rhs.GroupVersion() { + return lhs.Kind < rhs.Kind + } + + // otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order + lhsIndex := -1 + rhsIndex := -1 + + for i := range o.sortOrder { + if o.sortOrder[i] == lhs.GroupVersion() { + lhsIndex = i + } + if o.sortOrder[i] == rhs.GroupVersion() { + rhsIndex = i + } + } + + if rhsIndex == -1 { + return true + } + + return lhsIndex < rhsIndex +} + +type resourceByPreferredGroupVersion struct { + list []unversioned.GroupVersionResource + sortOrder []unversioned.GroupVersion +} + +func (o resourceByPreferredGroupVersion) Len() int { return len(o.list) } +func (o resourceByPreferredGroupVersion) Swap(i, j int) { o.list[i], o.list[j] = o.list[j], o.list[i] } +func (o resourceByPreferredGroupVersion) Less(i, j int) bool { + lhs := o.list[i] + rhs := o.list[j] + if lhs == rhs { + return false + } + + if lhs.GroupVersion() == rhs.GroupVersion() { + return lhs.Resource < rhs.Resource + } + + // otherwise, the difference is in the GroupVersion, so we need to sort with respect to the preferred order + lhsIndex := -1 + rhsIndex := -1 + + for i := range o.sortOrder { + if o.sortOrder[i] == lhs.GroupVersion() { + lhsIndex = i + } + if o.sortOrder[i] == rhs.GroupVersion() { + rhsIndex = i + } + } + + if rhsIndex == -1 { + return true + } + + return lhsIndex < rhsIndex +} + +// RESTMapping returns a struct representing the resource path and conversion interfaces a +// RESTClient should use to operate on the provided group/kind in order of versions. If a version search +// order is not provided, the search order provided to DefaultRESTMapper will be used to resolve which +// version should be used to access the named group/kind. +func (m *DefaultRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (*RESTMapping, error) { + // Pick an appropriate version + var gvk *unversioned.GroupVersionKind + hadVersion := false + for _, version := range versions { + if len(version) == 0 || version == runtime.APIVersionInternal { + continue + } + + currGVK := gk.WithVersion(version) + hadVersion = true + if _, ok := m.kindToPluralResource[currGVK]; ok { + gvk = &currGVK + break + } + } + // Use the default preferred versions + if !hadVersion && (gvk == nil) { + for _, gv := range m.defaultGroupVersions { + if gv.Group != gk.Group { + continue + } + + currGVK := gk.WithVersion(gv.Version) + if _, ok := m.kindToPluralResource[currGVK]; ok { + gvk = &currGVK + break + } + } + } + if gvk == nil { + return nil, fmt.Errorf("no kind named %q is registered in versions %q", gk, versions) + } + + // Ensure we have a REST mapping + resource, ok := m.kindToPluralResource[*gvk] + if !ok { + found := []unversioned.GroupVersion{} + for _, gv := range m.defaultGroupVersions { + if _, ok := m.kindToPluralResource[*gvk]; ok { + found = append(found, gv) + } + } + if len(found) > 0 { + return nil, fmt.Errorf("object with kind %q exists in versions %v, not %v", gvk.Kind, found, gvk.GroupVersion().String()) + } + return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported object", gvk.GroupVersion().String(), gvk.Kind) + } + + // Ensure we have a REST scope + scope, ok := m.kindToScope[*gvk] + if !ok { + return nil, fmt.Errorf("the provided version %q and kind %q cannot be mapped to a supported scope", gvk.GroupVersion().String(), gvk.Kind) + } + + interfaces, err := m.interfacesFunc(gvk.GroupVersion()) + if err != nil { + return nil, fmt.Errorf("the provided version %q has no relevant versions", gvk.GroupVersion().String()) + } + + retVal := &RESTMapping{ + Resource: resource.Resource, + GroupVersionKind: *gvk, + Scope: scope, + + ObjectConvertor: interfaces.ObjectConvertor, + MetadataAccessor: interfaces.MetadataAccessor, + } + + return retVal, nil +} + +// AddResourceAlias maps aliases to resources +func (m *DefaultRESTMapper) AddResourceAlias(alias string, resources ...string) { + if len(resources) == 0 { + return + } + m.aliasToResource[alias] = resources +} + +// AliasesForResource returns whether a resource has an alias or not +func (m *DefaultRESTMapper) AliasesForResource(alias string) ([]string, bool) { + if res, ok := m.aliasToResource[alias]; ok { + return res, true + } + return nil, false +} |