1
0
Fork 0
forked from barak/tarpoon

Add glide.yaml and vendor deps

This commit is contained in:
Dalton Hubble 2016-12-03 22:43:32 -08:00
parent db918f12ad
commit 5b3d5e81bd
18880 changed files with 5166045 additions and 1 deletions

78
vendor/k8s.io/kubernetes/pkg/api/meta/BUILD generated vendored Normal file
View file

@ -0,0 +1,78 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
"go_test",
"cgo_library",
)
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"errors.go",
"firsthit_restmapper.go",
"help.go",
"interfaces.go",
"meta.go",
"multirestmapper.go",
"priority.go",
"restmapper.go",
"unstructured.go",
],
tags = ["automanaged"],
deps = [
"//pkg/api/meta/metatypes:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/conversion:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/runtime/schema:go_default_library",
"//pkg/types:go_default_library",
"//pkg/util/errors:go_default_library",
"//pkg/util/sets:go_default_library",
"//vendor:github.com/golang/glog",
],
)
go_test(
name = "go_default_test",
srcs = [
"multirestmapper_test.go",
"priority_test.go",
"restmapper_test.go",
],
library = "go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/runtime:go_default_library",
"//pkg/runtime/schema:go_default_library",
],
)
go_test(
name = "go_default_xtest",
srcs = [
"help_test.go",
"meta_test.go",
"scheme_test.go",
],
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/api/meta:go_default_library",
"//pkg/api/meta/metatypes:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/runtime/schema:go_default_library",
"//pkg/types:go_default_library",
"//pkg/util/diff:go_default_library",
"//pkg/util/sets:go_default_library",
"//vendor:github.com/google/gofuzz",
],
)

26
vendor/k8s.io/kubernetes/pkg/api/meta/OWNERS generated vendored Executable file
View file

@ -0,0 +1,26 @@
reviewers:
- thockin
- smarterclayton
- wojtek-t
- deads2k
- brendandburns
- derekwaynecarr
- caesarxuchao
- mikedanese
- liggitt
- nikhiljindal
- gmarek
- kargakis
- janetkuo
- ncdc
- eparis
- dims
- krousey
- markturansky
- fabioy
- resouer
- david-mcmahon
- mfojtik
- jianhuiz
- feihujiang
- ghodss

19
vendor/k8s.io/kubernetes/pkg/api/meta/doc.go generated vendored Normal file
View file

@ -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 // import "k8s.io/kubernetes/pkg/api/meta"

105
vendor/k8s.io/kubernetes/pkg/api/meta/errors.go generated vendored Normal file
View file

@ -0,0 +1,105 @@
/*
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/runtime/schema"
)
// AmbiguousResourceError is returned if the RESTMapper finds multiple matches for a resource
type AmbiguousResourceError struct {
PartialResource schema.GroupVersionResource
MatchingResources []schema.GroupVersionResource
MatchingKinds []schema.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)
}
// AmbiguousKindError is returned if the RESTMapper finds multiple matches for a kind
type AmbiguousKindError struct {
PartialKind schema.GroupVersionKind
MatchingResources []schema.GroupVersionResource
MatchingKinds []schema.GroupVersionKind
}
func (e *AmbiguousKindError) Error() string {
switch {
case len(e.MatchingKinds) > 0 && len(e.MatchingResources) > 0:
return fmt.Sprintf("%v matches multiple resources %v and kinds %v", e.PartialKind, e.MatchingResources, e.MatchingKinds)
case len(e.MatchingKinds) > 0:
return fmt.Sprintf("%v matches multiple kinds %v", e.PartialKind, e.MatchingKinds)
case len(e.MatchingResources) > 0:
return fmt.Sprintf("%v matches multiple resources %v", e.PartialKind, e.MatchingResources)
}
return fmt.Sprintf("%v matches multiple resources or kinds", e.PartialKind)
}
func IsAmbiguousError(err error) bool {
if err == nil {
return false
}
switch err.(type) {
case *AmbiguousResourceError, *AmbiguousKindError:
return true
default:
return false
}
}
// NoResourceMatchError is returned if the RESTMapper can't find any match for a resource
type NoResourceMatchError struct {
PartialResource schema.GroupVersionResource
}
func (e *NoResourceMatchError) Error() string {
return fmt.Sprintf("no matches for %v", e.PartialResource)
}
// NoKindMatchError is returned if the RESTMapper can't find any match for a kind
type NoKindMatchError struct {
PartialKind schema.GroupVersionKind
}
func (e *NoKindMatchError) Error() string {
return fmt.Sprintf("no matches for %v", e.PartialKind)
}
func IsNoMatchError(err error) bool {
if err == nil {
return false
}
switch err.(type) {
case *NoResourceMatchError, *NoKindMatchError:
return true
default:
return false
}
}

View file

@ -0,0 +1,97 @@
/*
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/runtime/schema"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
)
// FirstHitRESTMapper is a wrapper for multiple RESTMappers which returns the
// first successful result for the singular requests
type FirstHitRESTMapper struct {
MultiRESTMapper
}
func (m FirstHitRESTMapper) String() string {
return fmt.Sprintf("FirstHitRESTMapper{\n\t%v\n}", m.MultiRESTMapper)
}
func (m FirstHitRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
errors := []error{}
for _, t := range m.MultiRESTMapper {
ret, err := t.ResourceFor(resource)
if err == nil {
return ret, nil
}
errors = append(errors, err)
}
return schema.GroupVersionResource{}, collapseAggregateErrors(errors)
}
func (m FirstHitRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
errors := []error{}
for _, t := range m.MultiRESTMapper {
ret, err := t.KindFor(resource)
if err == nil {
return ret, nil
}
errors = append(errors, err)
}
return schema.GroupVersionKind{}, collapseAggregateErrors(errors)
}
// 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 FirstHitRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
errors := []error{}
for _, t := range m.MultiRESTMapper {
ret, err := t.RESTMapping(gk, versions...)
if err == nil {
return ret, nil
}
errors = append(errors, err)
}
return nil, collapseAggregateErrors(errors)
}
// collapseAggregateErrors returns the minimal errors. it handles empty as nil, handles one item in a list
// by returning the item, and collapses all NoMatchErrors to a single one (since they should all be the same)
func collapseAggregateErrors(errors []error) error {
if len(errors) == 0 {
return nil
}
if len(errors) == 1 {
return errors[0]
}
allNoMatchErrors := true
for _, err := range errors {
allNoMatchErrors = allNoMatchErrors && IsNoMatchError(err)
}
if allNoMatchErrors {
return errors[0]
}
return utilerrors.NewAggregate(errors)
}

201
vendor/k8s.io/kubernetes/pkg/api/meta/help.go generated vendored Normal file
View file

@ -0,0 +1,201 @@
/*
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 {
// if we're a runtime.Unstructured, check to see if we have an `items` key
// This is a list type for recognition, but other Items type methods will fail on it
// and give you errors.
if unstructured, ok := obj.(*runtime.Unstructured); ok {
_, ok := unstructured.Object["items"]
return ok
}
_, 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())
}
}
// EachListItem invokes fn on each runtime.Object in the list. Any error immediately terminates
// the loop.
func EachListItem(obj runtime.Object, fn func(runtime.Object) error) error {
// TODO: Change to an interface call?
itemsPtr, err := GetItemsPtr(obj)
if err != nil {
return err
}
items, err := conversion.EnforcePtr(itemsPtr)
if err != nil {
return err
}
len := items.Len()
if len == 0 {
return nil
}
takeAddr := false
if elemType := items.Type().Elem(); elemType.Kind() != reflect.Ptr && elemType.Kind() != reflect.Interface {
if !items.Index(0).CanAddr() {
return fmt.Errorf("unable to take address of items in %T for EachListItem", obj)
}
takeAddr = true
}
for i := 0; i < len; i++ {
raw := items.Index(i)
if takeAddr {
raw = raw.Addr()
}
switch item := raw.Interface().(type) {
case *runtime.RawExtension:
if err := fn(item.Object); err != nil {
return err
}
case runtime.Object:
if err := fn(item); err != nil {
return err
}
default:
obj, ok := item.(runtime.Object)
if !ok {
return fmt.Errorf("%v: item[%v]: Expected object, got %#v(%s)", obj, i, raw.Interface(), raw.Kind())
}
if err := fn(obj); err != nil {
return err
}
}
}
return nil
}
// 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)
// check to see if you're directly assignable
if reflect.TypeOf(objects[i]).AssignableTo(dest.Type()) {
dest.Set(reflect.ValueOf(objects[i]))
continue
}
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
}

344
vendor/k8s.io/kubernetes/pkg/api/meta/help_test.go generated vendored Normal file
View file

@ -0,0 +1,344 @@
/*
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_test
import (
"reflect"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/util/diff"
"github.com/google/gofuzz"
)
func TestIsList(t *testing.T) {
tests := []struct {
obj runtime.Object
isList bool
}{
{&api.PodList{}, true},
{&api.Pod{}, false},
}
for _, item := range tests {
if e, a := item.isList, meta.IsListType(item.obj); e != a {
t.Errorf("%v: Expected %v, got %v", reflect.TypeOf(item.obj), e, a)
}
}
}
func TestExtractList(t *testing.T) {
list1 := []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Service{ObjectMeta: api.ObjectMeta{Name: "2"}},
}
list2 := &v1.List{
Items: []runtime.RawExtension{
{Raw: []byte("foo")},
{Raw: []byte("bar")},
{Object: &v1.Pod{ObjectMeta: v1.ObjectMeta{Name: "other"}}},
},
}
list3 := &fakePtrValueList{
Items: []*api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "2"}},
},
}
list4 := &api.PodList{
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "3"}},
},
}
list5 := &v1.PodList{
Items: []v1.Pod{
{ObjectMeta: v1.ObjectMeta{Name: "1"}},
{ObjectMeta: v1.ObjectMeta{Name: "2"}},
{ObjectMeta: v1.ObjectMeta{Name: "3"}},
},
}
testCases := []struct {
in runtime.Object
out []interface{}
equal bool
}{
{
in: &api.List{},
out: []interface{}{},
},
{
in: &v1.List{},
out: []interface{}{},
},
{
in: &v1.PodList{},
out: []interface{}{},
},
{
in: &api.List{Items: list1},
out: []interface{}{list1[0], list1[1]},
},
{
in: list2,
out: []interface{}{&runtime.Unknown{Raw: list2.Items[0].Raw}, &runtime.Unknown{Raw: list2.Items[1].Raw}, list2.Items[2].Object},
equal: true,
},
{
in: list3,
out: []interface{}{list3.Items[0], list3.Items[1]},
},
{
in: list4,
out: []interface{}{&list4.Items[0], &list4.Items[1], &list4.Items[2]},
},
{
in: list5,
out: []interface{}{&list5.Items[0], &list5.Items[1], &list5.Items[2]},
},
}
for i, test := range testCases {
list, err := meta.ExtractList(test.in)
if err != nil {
t.Fatalf("%d: extract: Unexpected error %v", i, err)
}
if e, a := len(test.out), len(list); e != a {
t.Fatalf("%d: extract: Expected %v, got %v", i, e, a)
}
for j, e := range test.out {
if e != list[j] {
if !test.equal {
t.Fatalf("%d: extract: Expected list[%d] to be %#v, but found %#v", i, j, e, list[j])
}
if !reflect.DeepEqual(e, list[j]) {
t.Fatalf("%d: extract: Expected list[%d] to be %#v, but found %#v", i, j, e, list[j])
}
}
}
}
}
func TestEachListItem(t *testing.T) {
list1 := []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Service{ObjectMeta: api.ObjectMeta{Name: "2"}},
}
list2 := &v1.List{
Items: []runtime.RawExtension{
{Raw: []byte("foo")},
{Raw: []byte("bar")},
{Object: &v1.Pod{ObjectMeta: v1.ObjectMeta{Name: "other"}}},
},
}
list3 := &fakePtrValueList{
Items: []*api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "2"}},
},
}
list4 := &api.PodList{
Items: []api.Pod{
{ObjectMeta: api.ObjectMeta{Name: "1"}},
{ObjectMeta: api.ObjectMeta{Name: "2"}},
{ObjectMeta: api.ObjectMeta{Name: "3"}},
},
}
list5 := &v1.PodList{
Items: []v1.Pod{
{ObjectMeta: v1.ObjectMeta{Name: "1"}},
{ObjectMeta: v1.ObjectMeta{Name: "2"}},
{ObjectMeta: v1.ObjectMeta{Name: "3"}},
},
}
testCases := []struct {
in runtime.Object
out []interface{}
}{
{
in: &api.List{},
out: []interface{}{},
},
{
in: &v1.List{},
out: []interface{}{},
},
{
in: &v1.PodList{},
out: []interface{}{},
},
{
in: &api.List{Items: list1},
out: []interface{}{list1[0], list1[1]},
},
{
in: list2,
out: []interface{}{nil, nil, list2.Items[2].Object},
},
{
in: list3,
out: []interface{}{list3.Items[0], list3.Items[1]},
},
{
in: list4,
out: []interface{}{&list4.Items[0], &list4.Items[1], &list4.Items[2]},
},
{
in: list5,
out: []interface{}{&list5.Items[0], &list5.Items[1], &list5.Items[2]},
},
}
for i, test := range testCases {
list := []runtime.Object{}
err := meta.EachListItem(test.in, func(obj runtime.Object) error {
list = append(list, obj)
return nil
})
if err != nil {
t.Fatalf("%d: each: Unexpected error %v", i, err)
}
if e, a := len(test.out), len(list); e != a {
t.Fatalf("%d: each: Expected %v, got %v", i, e, a)
}
for j, e := range test.out {
if e != list[j] {
t.Fatalf("%d: each: Expected list[%d] to be %#v, but found %#v", i, j, e, list[j])
}
}
}
}
type fakePtrInterfaceList struct {
Items *[]runtime.Object
}
func (obj fakePtrInterfaceList) GetObjectKind() schema.ObjectKind {
return schema.EmptyObjectKind
}
func TestExtractListOfInterfacePtrs(t *testing.T) {
pl := &fakePtrInterfaceList{
Items: &[]runtime.Object{},
}
list, err := meta.ExtractList(pl)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if len(list) > 0 {
t.Fatalf("Expected empty list, got %#v", list)
}
}
type fakePtrValueList struct {
Items []*api.Pod
}
func (obj fakePtrValueList) GetObjectKind() schema.ObjectKind {
return schema.EmptyObjectKind
}
func TestSetList(t *testing.T) {
pl := &api.PodList{}
list := []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "2"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "3"}},
}
err := meta.SetList(pl, list)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i].(*api.Pod).Name, pl.Items[i].Name; e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
}
}
func TestSetListToRuntimeObjectArray(t *testing.T) {
pl := &api.List{}
list := []runtime.Object{
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "2"}},
&api.Pod{ObjectMeta: api.ObjectMeta{Name: "3"}},
}
err := meta.SetList(pl, list)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i], pl.Items[i]; e != a {
t.Fatalf("%d: unmatched: %s", i, diff.ObjectDiff(e, a))
}
}
}
func TestSetListToMatchingType(t *testing.T) {
pl := &runtime.UnstructuredList{}
list := []runtime.Object{
&runtime.Unstructured{Object: map[string]interface{}{"foo": 1}},
&runtime.Unstructured{Object: map[string]interface{}{"foo": 2}},
&runtime.Unstructured{Object: map[string]interface{}{"foo": 3}},
}
err := meta.SetList(pl, list)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := len(list), len(pl.Items); e != a {
t.Fatalf("Expected %v, got %v", e, a)
}
for i := range list {
if e, a := list[i], pl.Items[i]; e != a {
t.Fatalf("%d: unmatched: %s", i, diff.ObjectDiff(e, a))
}
}
}
func TestSetExtractListRoundTrip(t *testing.T) {
fuzzer := fuzz.New().NilChance(0).NumElements(1, 5)
for i := 0; i < 5; i++ {
start := &api.PodList{}
fuzzer.Fuzz(&start.Items)
list, err := meta.ExtractList(start)
if err != nil {
t.Errorf("Unexpected error %v", err)
continue
}
got := &api.PodList{}
err = meta.SetList(got, list)
if err != nil {
t.Errorf("Unexpected error %v", err)
continue
}
if e, a := start, got; !reflect.DeepEqual(e, a) {
t.Fatalf("Expected %#v, got %#v", e, a)
}
}
}

185
vendor/k8s.io/kubernetes/pkg/api/meta/interfaces.go generated vendored Normal file
View file

@ -0,0 +1,185 @@
/*
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"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/schema"
"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() metav1.Time
SetCreationTimestamp(timestamp metav1.Time)
GetDeletionTimestamp() *metav1.Time
SetDeletionTimestamp(timestamp *metav1.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)
GetClusterName() string
SetClusterName(clusterName string)
}
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 metav1.List
// Type exposes the type and APIVersion of versioned or internal API objects.
type Type metav1.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 schema.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: split into sub-interfaces
type RESTMapper interface {
// KindFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error)
// KindsFor takes a partial resource and returns the list of potential kinds in priority order
KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error)
// ResourceFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error)
// ResourcesFor takes a partial resource and returns the list of potential resource in priority order
ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error)
// RESTMapping identifies a preferred resource mapping for the provided group kind.
RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error)
// RESTMappings returns all resource mappings for the provided group kind.
RESTMappings(gk schema.GroupKind) ([]*RESTMapping, error)
AliasesForResource(resource string) ([]string, bool)
ResourceSingularizer(resource string) (singular string, err error)
}

568
vendor/k8s.io/kubernetes/pkg/api/meta/meta.go generated vendored Normal file

File diff suppressed because it is too large Load diff

421
vendor/k8s.io/kubernetes/pkg/api/meta/meta_test.go generated vendored Normal file
View file

@ -0,0 +1,421 @@
/*
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_test
import (
"reflect"
"testing"
"github.com/google/gofuzz"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/api/meta/metatypes"
"k8s.io/kubernetes/pkg/api/v1"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/types"
)
func TestAPIObjectMeta(t *testing.T) {
j := &api.Pod{
TypeMeta: metav1.TypeMeta{APIVersion: "/a", Kind: "b"},
ObjectMeta: api.ObjectMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
Finalizers: []string{
"finalizer.1",
"finalizer.2",
},
},
}
var _ meta.Object = &j.ObjectMeta
var _ meta.ObjectMetaAccessor = j
accessor, err := meta.Accessor(j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if accessor != meta.Object(j) {
t.Fatalf("should have returned the same pointer: %#v\n\n%#v", accessor, j)
}
if e, a := "bar", accessor.GetNamespace(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "foo", accessor.GetName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "prefix", accessor.GetGenerateName(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "uid", string(accessor.GetUID()); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "1", accessor.GetResourceVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "some/place/only/we/know", accessor.GetSelfLink(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := []string{"finalizer.1", "finalizer.2"}, accessor.GetFinalizers(); !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor, err := meta.TypeAccessor(j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "b", typeAccessor.GetKind(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
accessor.SetNamespace("baz")
accessor.SetName("bar")
accessor.SetGenerateName("generate")
accessor.SetUID("other")
typeAccessor.SetAPIVersion("c")
typeAccessor.SetKind("d")
accessor.SetResourceVersion("2")
accessor.SetSelfLink("google.com")
accessor.SetFinalizers([]string{"finalizer.3"})
// Prove that accessor changes the original object.
if e, a := "baz", j.Namespace; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "bar", j.Name; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "generate", j.GenerateName; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := types.UID("other"), j.UID; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "c", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "2", j.ResourceVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "google.com", j.SelfLink; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := []string{"finalizer.3"}, j.Finalizers; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor.SetAPIVersion("d")
typeAccessor.SetKind("e")
if e, a := "d", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "e", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGenericTypeMeta(t *testing.T) {
type TypeMeta struct {
Kind string `json:"kind,omitempty"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
GenerateName string `json:"generateName,omitempty"`
UID string `json:"uid,omitempty"`
CreationTimestamp metav1.Time `json:"creationTimestamp,omitempty"`
SelfLink string `json:"selfLink,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
OwnerReferences []api.OwnerReference `json:"ownerReferences,omitempty"`
Finalizers []string `json:"finalizers,omitempty"`
}
j := struct{ TypeMeta }{TypeMeta{APIVersion: "a", Kind: "b"}}
typeAccessor, err := meta.TypeAccessor(&j)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if e, a := "a", typeAccessor.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "b", typeAccessor.GetKind(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor.SetAPIVersion("c")
typeAccessor.SetKind("d")
if e, a := "c", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "d", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
typeAccessor.SetAPIVersion("d")
typeAccessor.SetKind("e")
if e, a := "d", j.APIVersion; e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := "e", j.Kind; e != a {
t.Errorf("expected %v, got %v", e, a)
}
}
type InternalTypeMeta struct {
Kind string `json:"kind,omitempty"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`
GenerateName string `json:"generateName,omitempty"`
UID string `json:"uid,omitempty"`
CreationTimestamp metav1.Time `json:"creationTimestamp,omitempty"`
SelfLink string `json:"selfLink,omitempty"`
ResourceVersion string `json:"resourceVersion,omitempty"`
APIVersion string `json:"apiVersion,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
Finalizers []string `json:"finalizers,omitempty"`
OwnerReferences []api.OwnerReference `json:"ownerReferences,omitempty"`
}
func (m *InternalTypeMeta) GetResourceVersion() string { return m.ResourceVersion }
func (m *InternalTypeMeta) SetResourceVersion(rv string) { m.ResourceVersion = rv }
func (m *InternalTypeMeta) GetSelfLink() string { return m.SelfLink }
func (m *InternalTypeMeta) SetSelfLink(link string) { m.SelfLink = link }
type MyAPIObject struct {
TypeMeta InternalTypeMeta `json:",inline"`
}
func (obj *MyAPIObject) GetListMeta() metav1.List { return &obj.TypeMeta }
func (obj *MyAPIObject) GetObjectKind() schema.ObjectKind { return obj }
func (obj *MyAPIObject) SetGroupVersionKind(gvk schema.GroupVersionKind) {
obj.TypeMeta.APIVersion, obj.TypeMeta.Kind = gvk.ToAPIVersionAndKind()
}
func (obj *MyAPIObject) GroupVersionKind() schema.GroupVersionKind {
return schema.FromAPIVersionAndKind(obj.TypeMeta.APIVersion, obj.TypeMeta.Kind)
}
type MyIncorrectlyMarkedAsAPIObject struct{}
func (obj *MyIncorrectlyMarkedAsAPIObject) GetObjectKind() schema.ObjectKind {
return schema.EmptyObjectKind
}
func TestResourceVersionerOfAPI(t *testing.T) {
type T struct {
runtime.Object
Expected string
}
testCases := map[string]T{
"empty api object": {&MyAPIObject{}, ""},
"api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
"pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
}
versioning := meta.NewAccessor()
for key, testCase := range testCases {
actual, err := versioning.ResourceVersion(testCase.Object)
if err != nil {
t.Errorf("%s: unexpected error %#v", key, err)
}
if actual != testCase.Expected {
t.Errorf("%s: expected %v, got %v", key, testCase.Expected, actual)
}
}
failingCases := map[string]struct {
runtime.Object
Expected string
}{
"not a valid object to try": {&MyIncorrectlyMarkedAsAPIObject{}, "1"},
}
for key, testCase := range failingCases {
_, err := versioning.ResourceVersion(testCase.Object)
if err == nil {
t.Errorf("%s: expected error, got nil", key)
}
}
setCases := map[string]struct {
runtime.Object
Expected string
}{
"pointer to api object with version": {&MyAPIObject{TypeMeta: InternalTypeMeta{ResourceVersion: "1"}}, "1"},
}
for key, testCase := range setCases {
if err := versioning.SetResourceVersion(testCase.Object, "5"); err != nil {
t.Errorf("%s: unexpected error %#v", key, err)
}
actual, err := versioning.ResourceVersion(testCase.Object)
if err != nil {
t.Errorf("%s: unexpected error %#v", key, err)
}
if actual != "5" {
t.Errorf("%s: expected %v, got %v", key, "5", actual)
}
}
}
func TestTypeMetaSelfLinker(t *testing.T) {
table := map[string]struct {
obj runtime.Object
expect string
try string
succeed bool
}{
"normal": {
obj: &MyAPIObject{TypeMeta: InternalTypeMeta{SelfLink: "foobar"}},
expect: "foobar",
try: "newbar",
succeed: true,
},
"fail": {
obj: &MyIncorrectlyMarkedAsAPIObject{},
succeed: false,
},
}
linker := runtime.SelfLinker(meta.NewAccessor())
for name, item := range table {
got, err := linker.SelfLink(item.obj)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
if e, a := item.expect, got; item.succeed && e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
err = linker.SetSelfLink(item.obj, item.try)
if e, a := item.succeed, err == nil; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
if item.succeed {
got, err := linker.SelfLink(item.obj)
if err != nil {
t.Errorf("%v: expected no err, got %v", name, err)
}
if e, a := item.try, got; e != a {
t.Errorf("%v: expected %v, got %v", name, e, a)
}
}
}
}
type MyAPIObject2 struct {
metav1.TypeMeta
v1.ObjectMeta
}
func getObjectMetaAndOwnerRefereneces() (myAPIObject2 MyAPIObject2, metaOwnerReferences []metatypes.OwnerReference) {
fuzz.New().NilChance(.5).NumElements(1, 5).Fuzz(&myAPIObject2)
references := myAPIObject2.ObjectMeta.OwnerReferences
// This is necessary for the test to pass because the getter will return a
// non-nil slice.
metaOwnerReferences = make([]metatypes.OwnerReference, 0)
for i := 0; i < len(references); i++ {
metaOwnerReferences = append(metaOwnerReferences, metatypes.OwnerReference{
Kind: references[i].Kind,
Name: references[i].Name,
UID: references[i].UID,
APIVersion: references[i].APIVersion,
Controller: references[i].Controller,
})
}
if len(references) == 0 {
// This is necessary for the test to pass because the setter will make a
// non-nil slice.
myAPIObject2.ObjectMeta.OwnerReferences = make([]v1.OwnerReference, 0)
}
return myAPIObject2, metaOwnerReferences
}
func testGetOwnerReferences(t *testing.T) {
obj, expected := getObjectMetaAndOwnerRefereneces()
accessor, err := meta.Accessor(&obj)
if err != nil {
t.Error(err)
}
references := accessor.GetOwnerReferences()
if !reflect.DeepEqual(references, expected) {
t.Errorf("expect %#v\n got %#v", expected, references)
}
}
func testSetOwnerReferences(t *testing.T) {
expected, references := getObjectMetaAndOwnerRefereneces()
obj := MyAPIObject2{}
accessor, err := meta.Accessor(&obj)
if err != nil {
t.Error(err)
}
accessor.SetOwnerReferences(references)
if e, a := expected.ObjectMeta.OwnerReferences, obj.ObjectMeta.OwnerReferences; !reflect.DeepEqual(e, a) {
t.Errorf("expect %#v\n got %#v", e, a)
}
}
func TestAccessOwnerReferences(t *testing.T) {
fuzzIter := 5
for i := 0; i < fuzzIter; i++ {
testGetOwnerReferences(t)
testSetOwnerReferences(t)
}
}
// BenchmarkAccessorSetFastPath shows the interface fast path
func BenchmarkAccessorSetFastPath(b *testing.B) {
obj := &api.Pod{
TypeMeta: metav1.TypeMeta{APIVersion: "/a", Kind: "b"},
ObjectMeta: api.ObjectMeta{
Namespace: "bar",
Name: "foo",
GenerateName: "prefix",
UID: "uid",
ResourceVersion: "1",
SelfLink: "some/place/only/we/know",
Labels: map[string]string{"foo": "bar"},
Annotations: map[string]string{"x": "y"},
},
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
acc, err := meta.Accessor(obj)
if err != nil {
b.Fatal(err)
}
acc.SetNamespace("something")
}
b.StopTimer()
}

18
vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/BUILD generated vendored Normal file
View file

@ -0,0 +1,18 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_binary",
"go_library",
"go_test",
"cgo_library",
)
go_library(
name = "go_default_library",
srcs = ["types.go"],
tags = ["automanaged"],
deps = ["//pkg/types:go_default_library"],
)

View file

@ -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
}

View file

@ -0,0 +1,231 @@
/*
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/runtime/schema"
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 schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
allGVRs := []schema.GroupVersionResource{}
for _, t := range m {
gvrs, err := t.ResourcesFor(resource)
// ignore "no match" errors, but any other error percolates back up
if IsNoMatchError(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 schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
allGVKs := []schema.GroupVersionKind{}
for _, t := range m {
gvks, err := t.KindsFor(resource)
// ignore "no match" errors, but any other error percolates back up
if IsNoMatchError(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 schema.GroupVersionResource) (schema.GroupVersionResource, error) {
resources, err := m.ResourcesFor(resource)
if err != nil {
return schema.GroupVersionResource{}, err
}
if len(resources) == 1 {
return resources[0], nil
}
return schema.GroupVersionResource{}, &AmbiguousResourceError{PartialResource: resource, MatchingResources: resources}
}
func (m MultiRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
kinds, err := m.KindsFor(resource)
if err != nil {
return schema.GroupVersionKind{}, err
}
if len(kinds) == 1 {
return kinds[0], nil
}
return schema.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 schema.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 IsNoMatchError(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 {
var kinds []schema.GroupVersionKind
for _, m := range allMappings {
kinds = append(kinds, m.GroupVersionKind)
}
return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
}
if len(errors) > 0 {
return nil, utilerrors.NewAggregate(errors)
}
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")}
}
// RESTMappings returns all possible RESTMappings for the provided group kind, or an error
// if the type is not recognized.
func (m MultiRESTMapper) RESTMappings(gk schema.GroupKind) ([]*RESTMapping, error) {
var allMappings []*RESTMapping
var errors []error
for _, t := range m {
currMappings, err := t.RESTMappings(gk)
// ignore "no match" errors, but any other error percolates back up
if IsNoMatchError(err) {
continue
}
if err != nil {
errors = append(errors, err)
continue
}
allMappings = append(allMappings, currMappings...)
}
if len(errors) > 0 {
return nil, utilerrors.NewAggregate(errors)
}
if len(allMappings) == 0 {
return nil, &NoKindMatchError{PartialKind: gk.WithVersion("")}
}
return allMappings, nil
}
// 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
}

View file

@ -0,0 +1,359 @@
/*
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 (
"errors"
"reflect"
"testing"
"k8s.io/kubernetes/pkg/runtime/schema"
)
func TestMultiRESTMapperResourceFor(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input schema.GroupVersionResource
result schema.GroupVersionResource
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: schema.GroupVersionResource{Resource: "foo"},
result: schema.GroupVersionResource{},
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: schema.GroupVersionResource{},
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: schema.GroupVersionResource{},
err: errors.New("fail on this"),
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.ResourceFor(tc.input)
if e, a := tc.result, actualResult; e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
switch {
case tc.err == nil && actualErr == nil:
case tc.err == nil:
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
case actualErr == nil:
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
case tc.err.Error() != actualErr.Error():
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
func TestMultiRESTMapperResourcesFor(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input schema.GroupVersionResource
result []schema.GroupVersionResource
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: schema.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "unused"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: nil,
err: errors.New("fail on this"),
},
{
name: "union and dedup",
mapper: MultiRESTMapper{
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}}},
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "second"}}},
},
input: schema.GroupVersionResource{Resource: "foo"},
result: []schema.GroupVersionResource{{Resource: "dupe"}, {Resource: "first"}, {Resource: "second"}},
},
{
name: "skip not and continue",
mapper: MultiRESTMapper{
fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}},
fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}}},
},
input: schema.GroupVersionResource{Resource: "foo"},
result: []schema.GroupVersionResource{{Resource: "first"}, {Resource: "second"}},
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.ResourcesFor(tc.input)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
switch {
case tc.err == nil && actualErr == nil:
case tc.err == nil:
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
case actualErr == nil:
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
case tc.err.Error() != actualErr.Error():
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
func TestMultiRESTMapperKindsFor(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input schema.GroupVersionResource
result []schema.GroupVersionKind
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: schema.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: nil,
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: nil,
err: errors.New("fail on this"),
},
{
name: "union and dedup",
mapper: MultiRESTMapper{
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}}},
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "second"}}},
},
input: schema.GroupVersionResource{Resource: "foo"},
result: []schema.GroupVersionKind{{Kind: "dupe"}, {Kind: "first"}, {Kind: "second"}},
},
{
name: "skip not and continue",
mapper: MultiRESTMapper{
fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}},
fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}}},
},
input: schema.GroupVersionResource{Resource: "foo"},
result: []schema.GroupVersionKind{{Kind: "first"}, {Kind: "second"}},
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.KindsFor(tc.input)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
switch {
case tc.err == nil && actualErr == nil:
case tc.err == nil:
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
case actualErr == nil:
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
case tc.err.Error() != actualErr.Error():
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
func TestMultiRESTMapperKindFor(t *testing.T) {
tcs := []struct {
name string
mapper MultiRESTMapper
input schema.GroupVersionResource
result schema.GroupVersionKind
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: schema.GroupVersionResource{Resource: "foo"},
result: schema.GroupVersionKind{},
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "IGNORE_THIS"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: schema.GroupVersionKind{},
err: &NoResourceMatchError{PartialResource: schema.GroupVersionResource{Resource: "foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "unused"}}}},
input: schema.GroupVersionResource{Resource: "foo"},
result: schema.GroupVersionKind{},
err: errors.New("fail on this"),
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.KindFor(tc.input)
if e, a := tc.result, actualResult; e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
switch {
case tc.err == nil && actualErr == nil:
case tc.err == nil:
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
case actualErr == nil:
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
case tc.err.Error() != actualErr.Error():
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
func TestMultiRESTMapperRESTMappings(t *testing.T) {
mapping1, mapping2 := &RESTMapping{}, &RESTMapping{}
tcs := []struct {
name string
mapper MultiRESTMapper
input schema.GroupKind
result []*RESTMapping
err error
}{
{
name: "empty",
mapper: MultiRESTMapper{},
input: schema.GroupKind{Kind: "Foo"},
result: nil,
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
},
{
name: "ignore not found",
mapper: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}},
input: schema.GroupKind{Kind: "Foo"},
result: nil,
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
},
{
name: "accept first failure",
mapper: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}},
input: schema.GroupKind{Kind: "Foo"},
result: nil,
err: errors.New("fail on this"),
},
{
name: "return both",
mapper: MultiRESTMapper{fixedRESTMapper{mappings: []*RESTMapping{mapping1}}, fixedRESTMapper{mappings: []*RESTMapping{mapping2}}},
input: schema.GroupKind{Kind: "Foo"},
result: []*RESTMapping{mapping1, mapping2},
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.RESTMappings(tc.input)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
switch {
case tc.err == nil && actualErr == nil:
case tc.err == nil:
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
case actualErr == nil:
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
case tc.err.Error() != actualErr.Error():
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
type fixedRESTMapper struct {
resourcesFor []schema.GroupVersionResource
kindsFor []schema.GroupVersionKind
resourceFor schema.GroupVersionResource
kindFor schema.GroupVersionKind
mappings []*RESTMapping
err error
}
func (m fixedRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
return "", m.err
}
func (m fixedRESTMapper) ResourcesFor(resource schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
return m.resourcesFor, m.err
}
func (m fixedRESTMapper) KindsFor(resource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
return m.kindsFor, m.err
}
func (m fixedRESTMapper) ResourceFor(resource schema.GroupVersionResource) (schema.GroupVersionResource, error) {
return m.resourceFor, m.err
}
func (m fixedRESTMapper) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
return m.kindFor, m.err
}
func (m fixedRESTMapper) RESTMapping(gk schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
return nil, m.err
}
func (m fixedRESTMapper) RESTMappings(gk schema.GroupKind) (mappings []*RESTMapping, err error) {
return m.mappings, m.err
}
func (m fixedRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) {
return nil, false
}
func (m fixedRESTMapper) ResourceIsValid(resource schema.GroupVersionResource) bool {
return false
}

226
vendor/k8s.io/kubernetes/pkg/api/meta/priority.go generated vendored Normal file
View file

@ -0,0 +1,226 @@
/*
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/runtime/schema"
)
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 []schema.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 []schema.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 schema.GroupVersionResource) (schema.GroupVersionResource, error) {
originalGVRs, err := m.Delegate.ResourcesFor(partiallySpecifiedResource)
if err != nil {
return schema.GroupVersionResource{}, err
}
if len(originalGVRs) == 1 {
return originalGVRs[0], nil
}
remainingGVRs := append([]schema.GroupVersionResource{}, originalGVRs...)
for _, pattern := range m.ResourcePriority {
matchedGVRs := []schema.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 schema.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 schema.GroupVersionResource) (schema.GroupVersionKind, error) {
originalGVKs, err := m.Delegate.KindsFor(partiallySpecifiedResource)
if err != nil {
return schema.GroupVersionKind{}, err
}
if len(originalGVKs) == 1 {
return originalGVKs[0], nil
}
remainingGVKs := append([]schema.GroupVersionKind{}, originalGVKs...)
for _, pattern := range m.KindPriority {
matchedGVKs := []schema.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 schema.GroupVersionKind{}, &AmbiguousResourceError{PartialResource: partiallySpecifiedResource, MatchingKinds: originalGVKs}
}
func resourceMatches(pattern schema.GroupVersionResource, resource schema.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 schema.GroupVersionKind, kind schema.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 schema.GroupKind, versions ...string) (mapping *RESTMapping, err error) {
mappings, err := m.Delegate.RESTMappings(gk)
if err != nil {
return nil, err
}
// any versions the user provides take priority
priorities := m.KindPriority
if len(versions) > 0 {
priorities = make([]schema.GroupVersionKind, 0, len(m.KindPriority)+len(versions))
for _, version := range versions {
gv, err := schema.ParseGroupVersion(version)
if err != nil {
return nil, err
}
priorities = append(priorities, gv.WithKind(AnyKind))
}
priorities = append(priorities, m.KindPriority...)
}
remaining := append([]*RESTMapping{}, mappings...)
for _, pattern := range priorities {
var matching []*RESTMapping
for _, m := range remaining {
if kindMatches(pattern, m.GroupVersionKind) {
matching = append(matching, m)
}
}
switch len(matching) {
case 0:
// if you have no matches, then nothing matched this pattern just move to the next
continue
case 1:
// one match, return
return matching[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
remaining = matching
}
}
if len(remaining) == 1 {
return remaining[0], nil
}
var kinds []schema.GroupVersionKind
for _, m := range mappings {
kinds = append(kinds, m.GroupVersionKind)
}
return nil, &AmbiguousKindError{PartialKind: gk.WithVersion(""), MatchingKinds: kinds}
}
func (m PriorityRESTMapper) RESTMappings(gk schema.GroupKind) ([]*RESTMapping, error) {
return m.Delegate.RESTMappings(gk)
}
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 schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
return m.Delegate.ResourcesFor(partiallySpecifiedResource)
}
func (m PriorityRESTMapper) KindsFor(partiallySpecifiedResource schema.GroupVersionResource) (gvk []schema.GroupVersionKind, err error) {
return m.Delegate.KindsFor(partiallySpecifiedResource)
}

309
vendor/k8s.io/kubernetes/pkg/api/meta/priority_test.go generated vendored Normal file
View file

@ -0,0 +1,309 @@
/*
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 (
"errors"
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/runtime/schema"
)
func TestPriorityRESTMapperResourceForErrorHandling(t *testing.T) {
tcs := []struct {
name string
delegate RESTMapper
resourcePatterns []schema.GroupVersionResource
result schema.GroupVersionResource
err string
}{
{
name: "single hit",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{{Resource: "single-hit"}}},
result: schema.GroupVersionResource{Resource: "single-hit"},
},
{
name: "ambiguous match",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
{Group: "one", Version: "a", Resource: "first"},
{Group: "two", Version: "b", Resource: "second"},
}},
err: "matches multiple resources",
},
{
name: "group selection",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
{Group: "one", Version: "a", Resource: "first"},
{Group: "two", Version: "b", Resource: "second"},
}},
resourcePatterns: []schema.GroupVersionResource{
{Group: "one", Version: AnyVersion, Resource: AnyResource},
},
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
},
{
name: "empty match continues",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
{Group: "one", Version: "a", Resource: "first"},
{Group: "two", Version: "b", Resource: "second"},
}},
resourcePatterns: []schema.GroupVersionResource{
{Group: "fail", Version: AnyVersion, Resource: AnyResource},
{Group: "one", Version: AnyVersion, Resource: AnyResource},
},
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
},
{
name: "group followed by version selection",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
{Group: "one", Version: "a", Resource: "first"},
{Group: "two", Version: "b", Resource: "second"},
{Group: "one", Version: "c", Resource: "third"},
}},
resourcePatterns: []schema.GroupVersionResource{
{Group: "one", Version: AnyVersion, Resource: AnyResource},
{Group: AnyGroup, Version: "a", Resource: AnyResource},
},
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "first"},
},
{
name: "resource selection",
delegate: fixedRESTMapper{resourcesFor: []schema.GroupVersionResource{
{Group: "one", Version: "a", Resource: "first"},
{Group: "one", Version: "a", Resource: "second"},
}},
resourcePatterns: []schema.GroupVersionResource{
{Group: AnyGroup, Version: AnyVersion, Resource: "second"},
},
result: schema.GroupVersionResource{Group: "one", Version: "a", Resource: "second"},
},
}
for _, tc := range tcs {
mapper := PriorityRESTMapper{Delegate: tc.delegate, ResourcePriority: tc.resourcePatterns}
actualResult, actualErr := mapper.ResourceFor(schema.GroupVersionResource{})
if e, a := tc.result, actualResult; e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
if len(tc.err) == 0 && actualErr == nil {
continue
}
if len(tc.err) > 0 && actualErr == nil {
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
continue
}
if !strings.Contains(actualErr.Error(), tc.err) {
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
func TestPriorityRESTMapperKindForErrorHandling(t *testing.T) {
tcs := []struct {
name string
delegate RESTMapper
kindPatterns []schema.GroupVersionKind
result schema.GroupVersionKind
err string
}{
{
name: "single hit",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{{Kind: "single-hit"}}},
result: schema.GroupVersionKind{Kind: "single-hit"},
},
{
name: "ambiguous match",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
{Group: "one", Version: "a", Kind: "first"},
{Group: "two", Version: "b", Kind: "second"},
}},
err: "matches multiple kinds",
},
{
name: "group selection",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
{Group: "one", Version: "a", Kind: "first"},
{Group: "two", Version: "b", Kind: "second"},
}},
kindPatterns: []schema.GroupVersionKind{
{Group: "one", Version: AnyVersion, Kind: AnyKind},
},
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
},
{
name: "empty match continues",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
{Group: "one", Version: "a", Kind: "first"},
{Group: "two", Version: "b", Kind: "second"},
}},
kindPatterns: []schema.GroupVersionKind{
{Group: "fail", Version: AnyVersion, Kind: AnyKind},
{Group: "one", Version: AnyVersion, Kind: AnyKind},
},
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
},
{
name: "group followed by version selection",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
{Group: "one", Version: "a", Kind: "first"},
{Group: "two", Version: "b", Kind: "second"},
{Group: "one", Version: "c", Kind: "third"},
}},
kindPatterns: []schema.GroupVersionKind{
{Group: "one", Version: AnyVersion, Kind: AnyKind},
{Group: AnyGroup, Version: "a", Kind: AnyKind},
},
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "first"},
},
{
name: "kind selection",
delegate: fixedRESTMapper{kindsFor: []schema.GroupVersionKind{
{Group: "one", Version: "a", Kind: "first"},
{Group: "one", Version: "a", Kind: "second"},
}},
kindPatterns: []schema.GroupVersionKind{
{Group: AnyGroup, Version: AnyVersion, Kind: "second"},
},
result: schema.GroupVersionKind{Group: "one", Version: "a", Kind: "second"},
},
}
for _, tc := range tcs {
mapper := PriorityRESTMapper{Delegate: tc.delegate, KindPriority: tc.kindPatterns}
actualResult, actualErr := mapper.KindFor(schema.GroupVersionResource{})
if e, a := tc.result, actualResult; e != a {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
if len(tc.err) == 0 && actualErr == nil {
continue
}
if len(tc.err) > 0 && actualErr == nil {
t.Errorf("%s: missing expected err: %v", tc.name, tc.err)
continue
}
if !strings.Contains(actualErr.Error(), tc.err) {
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}
func TestPriorityRESTMapperRESTMapping(t *testing.T) {
mapping1 := &RESTMapping{
GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1alpha1"},
}
mapping2 := &RESTMapping{
GroupVersionKind: schema.GroupVersionKind{Kind: "Foo", Version: "v1"},
}
mapping3 := &RESTMapping{
GroupVersionKind: schema.GroupVersionKind{Group: "other", Kind: "Foo", Version: "v1"},
}
allMappers := MultiRESTMapper{
fixedRESTMapper{mappings: []*RESTMapping{mapping1}},
fixedRESTMapper{mappings: []*RESTMapping{mapping2}},
fixedRESTMapper{mappings: []*RESTMapping{mapping3}},
}
tcs := []struct {
name string
mapper PriorityRESTMapper
input schema.GroupKind
result *RESTMapping
err error
}{
{
name: "empty",
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{}},
input: schema.GroupKind{Kind: "Foo"},
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
},
{
name: "ignore not found",
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "IGNORE_THIS"}}}}},
input: schema.GroupKind{Kind: "Foo"},
err: &NoKindMatchError{PartialKind: schema.GroupVersionKind{Kind: "Foo"}},
},
{
name: "accept first failure",
mapper: PriorityRESTMapper{Delegate: MultiRESTMapper{fixedRESTMapper{err: errors.New("fail on this")}, fixedRESTMapper{mappings: []*RESTMapping{mapping1}}}},
input: schema.GroupKind{Kind: "Foo"},
err: errors.New("fail on this"),
},
{
name: "return error for ambiguous",
mapper: PriorityRESTMapper{
Delegate: allMappers,
},
input: schema.GroupKind{Kind: "Foo"},
err: &AmbiguousKindError{
PartialKind: schema.GroupVersionKind{Kind: "Foo"},
MatchingKinds: []schema.GroupVersionKind{
{Kind: "Foo", Version: "v1alpha1"},
{Kind: "Foo", Version: "v1"},
{Group: "other", Kind: "Foo", Version: "v1"},
},
},
},
{
name: "accept only item",
mapper: PriorityRESTMapper{
Delegate: fixedRESTMapper{mappings: []*RESTMapping{mapping1}},
},
input: schema.GroupKind{Kind: "Foo"},
result: mapping1,
},
{
name: "return single priority",
mapper: PriorityRESTMapper{
Delegate: allMappers,
KindPriority: []schema.GroupVersionKind{{Version: "v1", Kind: AnyKind}, {Version: "v1alpha1", Kind: AnyKind}},
},
input: schema.GroupKind{Kind: "Foo"},
result: mapping2,
},
{
name: "return out of group match",
mapper: PriorityRESTMapper{
Delegate: allMappers,
KindPriority: []schema.GroupVersionKind{{Group: AnyGroup, Version: "v1", Kind: AnyKind}, {Group: "other", Version: AnyVersion, Kind: AnyKind}},
},
input: schema.GroupKind{Kind: "Foo"},
result: mapping3,
},
}
for _, tc := range tcs {
actualResult, actualErr := tc.mapper.RESTMapping(tc.input)
if e, a := tc.result, actualResult; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %v, got %v", tc.name, e, a)
}
switch {
case tc.err == nil && actualErr == nil:
case tc.err == nil:
t.Errorf("%s: unexpected error: %v", tc.name, actualErr)
case actualErr == nil:
t.Errorf("%s: expected error: %v got nil", tc.name, tc.err)
case tc.err.Error() != actualErr.Error():
t.Errorf("%s: expected %v, got %v", tc.name, tc.err, actualErr)
}
}
}

601
vendor/k8s.io/kubernetes/pkg/api/meta/restmapper.go generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

121
vendor/k8s.io/kubernetes/pkg/api/meta/scheme_test.go generated vendored Normal file
View file

@ -0,0 +1,121 @@
/*
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_test
import (
"fmt"
"reflect"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api/testapi"
metav1 "k8s.io/kubernetes/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/util/sets"
)
// These types do not follow the list convention as documented in
// docs/devel/api-convention.md
var listTypeExceptions = sets.NewString("APIGroupList", "APIResourceList")
func validateListType(target reflect.Type) error {
// exceptions
if listTypeExceptions.Has(target.Name()) {
return nil
}
hasListSuffix := strings.HasSuffix(target.Name(), "List")
hasMetadata := false
hasItems := false
for i := 0; i < target.NumField(); i++ {
field := target.Field(i)
tag := field.Tag.Get("json")
switch {
case strings.HasPrefix(tag, "metadata"):
hasMetadata = true
case tag == "items":
hasItems = true
if field.Type.Kind() != reflect.Slice {
return fmt.Errorf("Expected items to be slice, got %s", field.Type.Kind())
}
}
}
if hasListSuffix && !hasMetadata {
return fmt.Errorf("Expected type %s to contain \"metadata\"", target.Name())
}
if hasListSuffix && !hasItems {
return fmt.Errorf("Expected type %s to contain \"items\"", target.Name())
}
// if a type contains field Items with JSON tag "items", its name should end with List.
if !hasListSuffix && hasItems {
return fmt.Errorf("Type %s has Items, its name is expected to end with \"List\"", target.Name())
}
return nil
}
// TestListTypes verifies that no external type violates the api convention of
// list types.
func TestListTypes(t *testing.T) {
for groupKey, group := range testapi.Groups {
for kind, target := range group.ExternalTypes() {
t.Logf("working on %v in %v", kind, groupKey)
err := validateListType(target)
if err != nil {
t.Error(err)
}
}
}
}
type WithoutMetaDataList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta
Items []interface{} `json:"items"`
}
type WithoutItemsList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
}
type WrongItemsJSONTagList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []interface{} `json:"items,omitempty"`
}
// If a type has Items, its name should end with "List"
type ListWithWrongName struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []interface{} `json:"items"`
}
// TestValidateListType verifies the validateListType function reports error on
// types that violate the api convention.
func TestValidateListType(t *testing.T) {
var testTypes = []interface{}{
WithoutMetaDataList{},
WithoutItemsList{},
WrongItemsJSONTagList{},
ListWithWrongName{},
}
for _, testType := range testTypes {
err := validateListType(reflect.TypeOf(testType))
if err == nil {
t.Errorf("Expected error")
}
}
}

31
vendor/k8s.io/kubernetes/pkg/api/meta/unstructured.go generated vendored Normal file
View file

@ -0,0 +1,31 @@
/*
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 (
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/runtime/schema"
)
// InterfacesForUnstructured returns VersionInterfaces suitable for
// dealing with runtime.Unstructured objects.
func InterfacesForUnstructured(schema.GroupVersion) (*VersionInterfaces, error) {
return &VersionInterfaces{
ObjectConvertor: &runtime.UnstructuredObjectConverter{},
MetadataAccessor: NewAccessor(),
}, nil
}