forked from barak/tarpoon
Add glide.yaml and vendor deps
This commit is contained in:
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
78
vendor/k8s.io/kubernetes/pkg/api/meta/BUILD
generated
vendored
Normal 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
26
vendor/k8s.io/kubernetes/pkg/api/meta/OWNERS
generated
vendored
Executable 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
19
vendor/k8s.io/kubernetes/pkg/api/meta/doc.go
generated
vendored
Normal 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
105
vendor/k8s.io/kubernetes/pkg/api/meta/errors.go
generated
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
97
vendor/k8s.io/kubernetes/pkg/api/meta/firsthit_restmapper.go
generated
vendored
Normal file
97
vendor/k8s.io/kubernetes/pkg/api/meta/firsthit_restmapper.go
generated
vendored
Normal 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
201
vendor/k8s.io/kubernetes/pkg/api/meta/help.go
generated
vendored
Normal 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
344
vendor/k8s.io/kubernetes/pkg/api/meta/help_test.go
generated
vendored
Normal 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
185
vendor/k8s.io/kubernetes/pkg/api/meta/interfaces.go
generated
vendored
Normal 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
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
421
vendor/k8s.io/kubernetes/pkg/api/meta/meta_test.go
generated
vendored
Normal 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
18
vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/BUILD
generated
vendored
Normal 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"],
|
||||
)
|
||||
30
vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/types.go
generated
vendored
Normal file
30
vendor/k8s.io/kubernetes/pkg/api/meta/metatypes/types.go
generated
vendored
Normal 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
|
||||
}
|
||||
231
vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper.go
generated
vendored
Normal file
231
vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper.go
generated
vendored
Normal 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
|
||||
}
|
||||
359
vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper_test.go
generated
vendored
Normal file
359
vendor/k8s.io/kubernetes/pkg/api/meta/multirestmapper_test.go
generated
vendored
Normal 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
226
vendor/k8s.io/kubernetes/pkg/api/meta/priority.go
generated
vendored
Normal 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
309
vendor/k8s.io/kubernetes/pkg/api/meta/priority_test.go
generated
vendored
Normal 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
601
vendor/k8s.io/kubernetes/pkg/api/meta/restmapper.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
665
vendor/k8s.io/kubernetes/pkg/api/meta/restmapper_test.go
generated
vendored
Normal file
665
vendor/k8s.io/kubernetes/pkg/api/meta/restmapper_test.go
generated
vendored
Normal file
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
121
vendor/k8s.io/kubernetes/pkg/api/meta/scheme_test.go
generated
vendored
Normal 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
31
vendor/k8s.io/kubernetes/pkg/api/meta/unstructured.go
generated
vendored
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue