1
0
Fork 0
forked from barak/tarpoon

Add glide.yaml and vendor deps

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

89
vendor/k8s.io/kubernetes/pkg/api/validation/BUILD generated vendored Normal file
View file

@ -0,0 +1,89 @@
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",
"events.go",
"schema.go",
"validation.go",
],
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/api/endpoints:go_default_library",
"//pkg/api/meta:go_default_library",
"//pkg/api/pod:go_default_library",
"//pkg/api/resource:go_default_library",
"//pkg/api/service:go_default_library",
"//pkg/api/util:go_default_library",
"//pkg/api/v1:go_default_library",
"//pkg/apimachinery/registered:go_default_library",
"//pkg/apis/meta/v1/validation:go_default_library",
"//pkg/apis/storage/util:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/labels:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/runtime/schema:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//pkg/util/config:go_default_library",
"//pkg/util/errors:go_default_library",
"//pkg/util/intstr:go_default_library",
"//pkg/util/sets:go_default_library",
"//pkg/util/validation:go_default_library",
"//pkg/util/validation/field:go_default_library",
"//pkg/util/yaml:go_default_library",
"//vendor:github.com/emicklei/go-restful/swagger",
"//vendor:github.com/exponent-io/jsonpath",
"//vendor:github.com/golang/glog",
],
)
go_test(
name = "go_default_test",
srcs = [
"events_test.go",
"schema_test.go",
"validation_test.go",
],
data = [
"testdata/v1/invalidPod.yaml",
"testdata/v1/invalidPod1.json",
"testdata/v1/invalidPod2.json",
"testdata/v1/invalidPod3.json",
"testdata/v1/invalidPod4.yaml",
"testdata/v1/validPod.yaml",
"//api/swagger-spec",
],
library = "go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/api:go_default_library",
"//pkg/api/resource:go_default_library",
"//pkg/api/service:go_default_library",
"//pkg/api/testapi:go_default_library",
"//pkg/api/testing:go_default_library",
"//pkg/apimachinery/registered:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/apis/meta/v1:go_default_library",
"//pkg/apis/storage/util:go_default_library",
"//pkg/capabilities:go_default_library",
"//pkg/runtime:go_default_library",
"//pkg/security/apparmor:go_default_library",
"//pkg/util/intstr:go_default_library",
"//pkg/util/sets:go_default_library",
"//pkg/util/validation/field:go_default_library",
"//pkg/util/yaml:go_default_library",
"//vendor:github.com/ghodss/yaml",
],
)

41
vendor/k8s.io/kubernetes/pkg/api/validation/OWNERS generated vendored Executable file
View file

@ -0,0 +1,41 @@
reviewers:
- thockin
- lavalamp
- smarterclayton
- wojtek-t
- bgrant0607
- deads2k
- yujuhong
- brendandburns
- derekwaynecarr
- caesarxuchao
- vishh
- mikedanese
- liggitt
- nikhiljindal
- bprashanth
- gmarek
- erictune
- davidopp
- pmorie
- sttts
- quinton-hoole
- kargakis
- dchen1107
- zmerlynn
- janetkuo
- justinsb
- pwittrock
- roberthbailey
- timstclair
- eparis
- soltysh
- piosz
- jsafrane
- jbeda
- dims
- fejta
- krousey
- rootfs
- markturansky
- vmarmol

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

@ -0,0 +1,19 @@
/*
Copyright 2014 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package validation has functions for validating the correctness of api
// objects and explaining what is wrong with them when they aren't valid.
package validation // import "k8s.io/kubernetes/pkg/api/validation"

80
vendor/k8s.io/kubernetes/pkg/api/validation/events.go generated vendored Normal file
View file

@ -0,0 +1,80 @@
/*
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 validation
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/meta"
apiutil "k8s.io/kubernetes/pkg/api/util"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/util/validation"
"k8s.io/kubernetes/pkg/util/validation/field"
)
// ValidateEvent makes sure that the event makes sense.
func ValidateEvent(event *api.Event) field.ErrorList {
allErrs := field.ErrorList{}
// Make sure event.Namespace and the involvedObject.Namespace agree
if len(event.InvolvedObject.Namespace) == 0 {
// event.Namespace must also be empty (or "default", for compatibility with old clients)
if event.Namespace != api.NamespaceNone && event.Namespace != api.NamespaceDefault {
allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace"))
}
} else {
// event namespace must match
if event.Namespace != event.InvolvedObject.Namespace {
allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match event.namespace"))
}
}
// For kinds we recognize, make sure involvedObject.Namespace is set for namespaced kinds
if namespaced, err := isNamespacedKind(event.InvolvedObject.Kind, event.InvolvedObject.APIVersion); err == nil {
if namespaced && len(event.InvolvedObject.Namespace) == 0 {
allErrs = append(allErrs, field.Required(field.NewPath("involvedObject", "namespace"), fmt.Sprintf("required for kind %s", event.InvolvedObject.Kind)))
}
if !namespaced && len(event.InvolvedObject.Namespace) > 0 {
allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, fmt.Sprintf("not allowed for kind %s", event.InvolvedObject.Kind)))
}
}
for _, msg := range validation.IsDNS1123Subdomain(event.Namespace) {
allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, msg))
}
return allErrs
}
// Check whether the kind in groupVersion is scoped at the root of the api hierarchy
func isNamespacedKind(kind, groupVersion string) (bool, error) {
group := apiutil.GetGroup(groupVersion)
g, err := registered.Group(group)
if err != nil {
return false, err
}
restMapping, err := g.RESTMapper.RESTMapping(schema.GroupKind{Group: group, Kind: kind}, apiutil.GetVersion(groupVersion))
if err != nil {
return false, err
}
scopeName := restMapping.Scope.Name()
if scopeName == meta.RESTScopeNameNamespace {
return true, nil
}
return false, nil
}

View file

@ -0,0 +1,220 @@
/*
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 validation
import (
"testing"
"k8s.io/kubernetes/pkg/api"
)
func TestValidateEvent(t *testing.T) {
table := []struct {
*api.Event
valid bool
}{
{
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test1",
Namespace: "foo",
},
InvolvedObject: api.ObjectReference{
Namespace: "bar",
Kind: "Pod",
},
},
false,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test2",
Namespace: "aoeu-_-aoeu",
},
InvolvedObject: api.ObjectReference{
Namespace: "aoeu-_-aoeu",
Kind: "Pod",
},
},
false,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test3",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
},
true,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test4",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "v1",
Kind: "Namespace",
},
},
true,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test5",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "extensions/v1beta1",
Kind: "NoKind",
Namespace: api.NamespaceDefault,
},
},
true,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test6",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "extensions/v1beta1",
Kind: "Job",
Namespace: "foo",
},
},
false,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test7",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "extensions/v1beta1",
Kind: "Job",
Namespace: api.NamespaceDefault,
},
},
true,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test8",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "other/v1beta1",
Kind: "Job",
Namespace: "foo",
},
},
false,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test9",
Namespace: "foo",
},
InvolvedObject: api.ObjectReference{
APIVersion: "other/v1beta1",
Kind: "Job",
Namespace: "foo",
},
},
true,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test10",
Namespace: api.NamespaceDefault,
},
InvolvedObject: api.ObjectReference{
APIVersion: "extensions",
Kind: "Job",
Namespace: "foo",
},
},
false,
}, {
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test11",
Namespace: "foo",
},
InvolvedObject: api.ObjectReference{
// must register in v1beta1 to be true
APIVersion: "extensions/v1beta1",
Kind: "Job",
Namespace: "foo",
},
},
true,
},
{
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test12",
Namespace: "foo",
},
InvolvedObject: api.ObjectReference{
APIVersion: "other/v1beta1",
Kind: "FooBar",
Namespace: "bar",
},
},
false,
},
{
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test13",
Namespace: "",
},
InvolvedObject: api.ObjectReference{
APIVersion: "other/v1beta1",
Kind: "FooBar",
Namespace: "bar",
},
},
false,
},
{
&api.Event{
ObjectMeta: api.ObjectMeta{
Name: "test14",
Namespace: "foo",
},
InvolvedObject: api.ObjectReference{
APIVersion: "other/v1beta1",
Kind: "FooBar",
Namespace: "",
},
},
false,
},
}
for _, item := range table {
if e, a := item.valid, len(ValidateEvent(item.Event)) == 0; e != a {
t.Errorf("%v: expected %v, got %v", item.Event.Name, e, a)
}
}
}

25
vendor/k8s.io/kubernetes/pkg/api/validation/path/BUILD generated vendored Normal file
View file

@ -0,0 +1,25 @@
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 = ["name.go"],
tags = ["automanaged"],
)
go_test(
name = "go_default_test",
srcs = ["name_test.go"],
library = "go_default_library",
tags = ["automanaged"],
deps = [],
)

View file

@ -0,0 +1,66 @@
/*
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 path
import (
"fmt"
"strings"
)
// NameMayNotBe specifies strings that cannot be used as names specified as path segments (like the REST API or etcd store)
var NameMayNotBe = []string{".", ".."}
// NameMayNotContain specifies substrings that cannot be used in names specified as path segments (like the REST API or etcd store)
var NameMayNotContain = []string{"/", "%"}
// IsValidPathSegmentName validates the name can be safely encoded as a path segment
func IsValidPathSegmentName(name string) []string {
for _, illegalName := range NameMayNotBe {
if name == illegalName {
return []string{fmt.Sprintf(`may not be '%s'`, illegalName)}
}
}
for _, illegalContent := range NameMayNotContain {
if strings.Contains(name, illegalContent) {
return []string{fmt.Sprintf(`may not contain '%s'`, illegalContent)}
}
}
return nil
}
// IsValidPathSegmentPrefix validates the name can be used as a prefix for a name which will be encoded as a path segment
// It does not check for exact matches with disallowed names, since an arbitrary suffix might make the name valid
func IsValidPathSegmentPrefix(name string) []string {
for _, illegalContent := range NameMayNotContain {
if strings.Contains(name, illegalContent) {
return []string{fmt.Sprintf(`may not contain '%s'`, illegalContent)}
}
}
return nil
}
// ValidatePathSegmentName validates the name can be safely encoded as a path segment
func ValidatePathSegmentName(name string, prefix bool) []string {
if prefix {
return IsValidPathSegmentPrefix(name)
} else {
return IsValidPathSegmentName(name)
}
}

View file

@ -0,0 +1,132 @@
/*
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 path
import (
"strings"
"testing"
)
func TestValidatePathSegmentName(t *testing.T) {
testcases := map[string]struct {
Name string
Prefix bool
ExpectedMsg string
}{
"empty": {
Name: "",
Prefix: false,
ExpectedMsg: "",
},
"empty,prefix": {
Name: "",
Prefix: true,
ExpectedMsg: "",
},
"valid": {
Name: "foo.bar.baz",
Prefix: false,
ExpectedMsg: "",
},
"valid,prefix": {
Name: "foo.bar.baz",
Prefix: true,
ExpectedMsg: "",
},
// Make sure mixed case, non DNS subdomain characters are tolerated
"valid complex": {
Name: "sha256:ABCDEF012345@ABCDEF012345",
Prefix: false,
ExpectedMsg: "",
},
// Make sure non-ascii characters are tolerated
"valid extended charset": {
Name: "Iñtërnâtiônàlizætiøn",
Prefix: false,
ExpectedMsg: "",
},
"dot": {
Name: ".",
Prefix: false,
ExpectedMsg: ".",
},
"dot leading": {
Name: ".test",
Prefix: false,
ExpectedMsg: "",
},
"dot,prefix": {
Name: ".",
Prefix: true,
ExpectedMsg: "",
},
"dot dot": {
Name: "..",
Prefix: false,
ExpectedMsg: "..",
},
"dot dot leading": {
Name: "..test",
Prefix: false,
ExpectedMsg: "",
},
"dot dot,prefix": {
Name: "..",
Prefix: true,
ExpectedMsg: "",
},
"slash": {
Name: "foo/bar",
Prefix: false,
ExpectedMsg: "/",
},
"slash,prefix": {
Name: "foo/bar",
Prefix: true,
ExpectedMsg: "/",
},
"percent": {
Name: "foo%bar",
Prefix: false,
ExpectedMsg: "%",
},
"percent,prefix": {
Name: "foo%bar",
Prefix: true,
ExpectedMsg: "%",
},
}
for k, tc := range testcases {
msgs := ValidatePathSegmentName(tc.Name, tc.Prefix)
if len(tc.ExpectedMsg) == 0 && len(msgs) > 0 {
t.Errorf("%s: expected no message, got %v", k, msgs)
}
if len(tc.ExpectedMsg) > 0 && len(msgs) == 0 {
t.Errorf("%s: expected error message, got none", k)
}
if len(tc.ExpectedMsg) > 0 && !strings.Contains(msgs[0], tc.ExpectedMsg) {
t.Errorf("%s: expected message containing %q, got %v", k, tc.ExpectedMsg, msgs[0])
}
}
}

435
vendor/k8s.io/kubernetes/pkg/api/validation/schema.go generated vendored Normal file
View file

@ -0,0 +1,435 @@
/*
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 validation
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"regexp"
"strings"
"github.com/emicklei/go-restful/swagger"
ejson "github.com/exponent-io/jsonpath"
"github.com/golang/glog"
apiutil "k8s.io/kubernetes/pkg/api/util"
"k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/yaml"
)
type InvalidTypeError struct {
ExpectedKind reflect.Kind
ObservedKind reflect.Kind
FieldName string
}
func (i *InvalidTypeError) Error() string {
return fmt.Sprintf("expected type %s, for field %s, got %s", i.ExpectedKind.String(), i.FieldName, i.ObservedKind.String())
}
func NewInvalidTypeError(expected reflect.Kind, observed reflect.Kind, fieldName string) error {
return &InvalidTypeError{expected, observed, fieldName}
}
// TypeNotFoundError is returned when specified type
// can not found in schema
type TypeNotFoundError string
func (tnfe TypeNotFoundError) Error() string {
return fmt.Sprintf("couldn't find type: %s", string(tnfe))
}
// Schema is an interface that knows how to validate an API object serialized to a byte array.
type Schema interface {
ValidateBytes(data []byte) error
}
type NullSchema struct{}
func (NullSchema) ValidateBytes(data []byte) error { return nil }
type NoDoubleKeySchema struct{}
func (NoDoubleKeySchema) ValidateBytes(data []byte) error {
var list []error = nil
if err := validateNoDuplicateKeys(data, "metadata", "labels"); err != nil {
list = append(list, err)
}
if err := validateNoDuplicateKeys(data, "metadata", "annotations"); err != nil {
list = append(list, err)
}
return utilerrors.NewAggregate(list)
}
func validateNoDuplicateKeys(data []byte, path ...string) error {
r := ejson.NewDecoder(bytes.NewReader(data))
// This is Go being unfriendly. The 'path ...string' comes in as a
// []string, and SeekTo takes ...interface{}, so we can't just pass
// the path straight in, we have to copy it. *sigh*
ifacePath := []interface{}{}
for ix := range path {
ifacePath = append(ifacePath, path[ix])
}
found, err := r.SeekTo(ifacePath...)
if err != nil {
return err
}
if !found {
return nil
}
seen := map[string]bool{}
for {
tok, err := r.Token()
if err != nil {
return err
}
switch t := tok.(type) {
case json.Delim:
if t.String() == "}" {
return nil
}
case ejson.KeyString:
if seen[string(t)] {
return fmt.Errorf("duplicate key: %s", string(t))
} else {
seen[string(t)] = true
}
}
}
}
type ConjunctiveSchema []Schema
func (c ConjunctiveSchema) ValidateBytes(data []byte) error {
var list []error = nil
schemas := []Schema(c)
for ix := range schemas {
if err := schemas[ix].ValidateBytes(data); err != nil {
list = append(list, err)
}
}
return utilerrors.NewAggregate(list)
}
type SwaggerSchema struct {
api swagger.ApiDeclaration
delegate Schema // For delegating to other api groups
}
func NewSwaggerSchemaFromBytes(data []byte, factory Schema) (Schema, error) {
schema := &SwaggerSchema{}
err := json.Unmarshal(data, &schema.api)
if err != nil {
return nil, err
}
schema.delegate = factory
return schema, nil
}
// validateList unpacks a list and validate every item in the list.
// It return nil if every item is ok.
// Otherwise it return an error list contain errors of every item.
func (s *SwaggerSchema) validateList(obj map[string]interface{}) []error {
items, exists := obj["items"]
if !exists {
return []error{fmt.Errorf("no items field in %#v", obj)}
}
return s.validateItems(items)
}
func (s *SwaggerSchema) validateItems(items interface{}) []error {
allErrs := []error{}
itemList, ok := items.([]interface{})
if !ok {
return append(allErrs, fmt.Errorf("items isn't a slice"))
}
for i, item := range itemList {
fields, ok := item.(map[string]interface{})
if !ok {
allErrs = append(allErrs, fmt.Errorf("items[%d] isn't a map[string]interface{}", i))
continue
}
groupVersion := fields["apiVersion"]
if groupVersion == nil {
allErrs = append(allErrs, fmt.Errorf("items[%d].apiVersion not set", i))
continue
}
itemVersion, ok := groupVersion.(string)
if !ok {
allErrs = append(allErrs, fmt.Errorf("items[%d].apiVersion isn't string type", i))
continue
}
if len(itemVersion) == 0 {
allErrs = append(allErrs, fmt.Errorf("items[%d].apiVersion is empty", i))
}
kind := fields["kind"]
if kind == nil {
allErrs = append(allErrs, fmt.Errorf("items[%d].kind not set", i))
continue
}
itemKind, ok := kind.(string)
if !ok {
allErrs = append(allErrs, fmt.Errorf("items[%d].kind isn't string type", i))
continue
}
if len(itemKind) == 0 {
allErrs = append(allErrs, fmt.Errorf("items[%d].kind is empty", i))
}
version := apiutil.GetVersion(itemVersion)
errs := s.ValidateObject(item, "", version+"."+itemKind)
if len(errs) >= 1 {
allErrs = append(allErrs, errs...)
}
}
return allErrs
}
func (s *SwaggerSchema) ValidateBytes(data []byte) error {
var obj interface{}
out, err := yaml.ToJSON(data)
if err != nil {
return err
}
data = out
if err := json.Unmarshal(data, &obj); err != nil {
return err
}
fields, ok := obj.(map[string]interface{})
if !ok {
return fmt.Errorf("error in unmarshaling data %s", string(data))
}
groupVersion := fields["apiVersion"]
if groupVersion == nil {
return fmt.Errorf("apiVersion not set")
}
if _, ok := groupVersion.(string); !ok {
return fmt.Errorf("apiVersion isn't string type")
}
kind := fields["kind"]
if kind == nil {
return fmt.Errorf("kind not set")
}
if _, ok := kind.(string); !ok {
return fmt.Errorf("kind isn't string type")
}
if strings.HasSuffix(kind.(string), "List") {
return utilerrors.NewAggregate(s.validateList(fields))
}
version := apiutil.GetVersion(groupVersion.(string))
allErrs := s.ValidateObject(obj, "", version+"."+kind.(string))
if len(allErrs) == 1 {
return allErrs[0]
}
return utilerrors.NewAggregate(allErrs)
}
func (s *SwaggerSchema) ValidateObject(obj interface{}, fieldName, typeName string) []error {
allErrs := []error{}
models := s.api.Models
model, ok := models.At(typeName)
// Verify the api version matches. This is required for nested types with differing api versions because
// s.api only has schema for 1 api version (the parent object type's version).
// e.g. an extensions/v1beta1 Template embedding a /v1 Service requires the schema for the extensions/v1beta1
// api to delegate to the schema for the /v1 api.
// Only do this for !ok objects so that cross ApiVersion vendored types take precedence.
if !ok && s.delegate != nil {
fields, mapOk := obj.(map[string]interface{})
if !mapOk {
return append(allErrs, fmt.Errorf("field %s: expected object of type map[string]interface{}, but the actual type is %T", fieldName, obj))
}
if delegated, err := s.delegateIfDifferentApiVersion(runtime.Unstructured{Object: fields}); delegated {
if err != nil {
allErrs = append(allErrs, err)
}
return allErrs
}
}
if !ok {
return append(allErrs, TypeNotFoundError(typeName))
}
properties := model.Properties
if len(properties.List) == 0 {
// The object does not have any sub-fields.
return nil
}
fields, ok := obj.(map[string]interface{})
if !ok {
return append(allErrs, fmt.Errorf("field %s: expected object of type map[string]interface{}, but the actual type is %T", fieldName, obj))
}
if len(fieldName) > 0 {
fieldName = fieldName + "."
}
// handle required fields
for _, requiredKey := range model.Required {
if _, ok := fields[requiredKey]; !ok {
allErrs = append(allErrs, fmt.Errorf("field %s: is required", requiredKey))
}
}
for key, value := range fields {
details, ok := properties.At(key)
// Special case for runtime.RawExtension and runtime.Objects because they always fail to validate
// This is because the actual values will be of some sub-type (e.g. Deployment) not the expected
// super-type (RawExtension)
if s.isGenericArray(details) {
errs := s.validateItems(value)
if len(errs) > 0 {
allErrs = append(allErrs, errs...)
}
continue
}
if !ok {
allErrs = append(allErrs, fmt.Errorf("found invalid field %s for %s", key, typeName))
continue
}
if details.Type == nil && details.Ref == nil {
allErrs = append(allErrs, fmt.Errorf("could not find the type of %s from object: %v", key, details))
}
var fieldType string
if details.Type != nil {
fieldType = *details.Type
} else {
fieldType = *details.Ref
}
if value == nil {
glog.V(2).Infof("Skipping nil field: %s", key)
continue
}
errs := s.validateField(value, fieldName+key, fieldType, &details)
if len(errs) > 0 {
allErrs = append(allErrs, errs...)
}
}
return allErrs
}
// delegateIfDifferentApiVersion delegates the validation of an object if its ApiGroup does not match the
// current SwaggerSchema.
// First return value is true if the validation was delegated (by a different ApiGroup SwaggerSchema)
// Second return value is the result of the delegated validation if performed.
func (s *SwaggerSchema) delegateIfDifferentApiVersion(obj runtime.Unstructured) (bool, error) {
// Never delegate objects in the same ApiVersion or we will get infinite recursion
if !s.isDifferentApiVersion(obj) {
return false, nil
}
// Convert the object back into bytes so that we can pass it to the ValidateBytes function
m, err := json.Marshal(obj.Object)
if err != nil {
return true, err
}
// Delegate validation of this object to the correct SwaggerSchema for its ApiGroup
return true, s.delegate.ValidateBytes(m)
}
// isDifferentApiVersion Returns true if obj lives in a different ApiVersion than the SwaggerSchema does.
// The SwaggerSchema will not be able to process objects in different ApiVersions unless they are vendored.
func (s *SwaggerSchema) isDifferentApiVersion(obj runtime.Unstructured) bool {
groupVersion := obj.GetAPIVersion()
return len(groupVersion) > 0 && s.api.ApiVersion != groupVersion
}
// isGenericArray Returns true if p is an array of generic Objects - either RawExtension or Object.
func (s *SwaggerSchema) isGenericArray(p swagger.ModelProperty) bool {
return p.DataTypeFields.Type != nil &&
*p.DataTypeFields.Type == "array" &&
p.Items != nil &&
p.Items.Ref != nil &&
(*p.Items.Ref == "runtime.RawExtension" || *p.Items.Ref == "runtime.Object")
}
// This matches type name in the swagger spec, such as "v1.Binding".
var versionRegexp = regexp.MustCompile(`^(v.+|unversioned)\..*`)
func (s *SwaggerSchema) validateField(value interface{}, fieldName, fieldType string, fieldDetails *swagger.ModelProperty) []error {
allErrs := []error{}
if reflect.TypeOf(value) == nil {
return append(allErrs, fmt.Errorf("unexpected nil value for field %v", fieldName))
}
// TODO: caesarxuchao: because we have multiple group/versions and objects
// may reference objects in other group, the commented out way of checking
// if a filedType is a type defined by us is outdated. We use a hacky way
// for now.
// TODO: the type name in the swagger spec is something like "v1.Binding",
// and the "v1" is generated from the package name, not the groupVersion of
// the type. We need to fix go-restful to embed the group name in the type
// name, otherwise we couldn't handle identically named types in different
// groups correctly.
if versionRegexp.MatchString(fieldType) {
// if strings.HasPrefix(fieldType, apiVersion) {
return s.ValidateObject(value, fieldName, fieldType)
}
switch fieldType {
case "string":
// Be loose about what we accept for 'string' since we use IntOrString in a couple of places
_, isString := value.(string)
_, isNumber := value.(float64)
_, isInteger := value.(int)
if !isString && !isNumber && !isInteger {
return append(allErrs, NewInvalidTypeError(reflect.String, reflect.TypeOf(value).Kind(), fieldName))
}
case "array":
arr, ok := value.([]interface{})
if !ok {
return append(allErrs, NewInvalidTypeError(reflect.Array, reflect.TypeOf(value).Kind(), fieldName))
}
var arrType string
if fieldDetails.Items.Ref == nil && fieldDetails.Items.Type == nil {
return append(allErrs, NewInvalidTypeError(reflect.Array, reflect.TypeOf(value).Kind(), fieldName))
}
if fieldDetails.Items.Ref != nil {
arrType = *fieldDetails.Items.Ref
} else {
arrType = *fieldDetails.Items.Type
}
for ix := range arr {
errs := s.validateField(arr[ix], fmt.Sprintf("%s[%d]", fieldName, ix), arrType, nil)
if len(errs) > 0 {
allErrs = append(allErrs, errs...)
}
}
case "uint64":
case "int64":
case "integer":
_, isNumber := value.(float64)
_, isInteger := value.(int)
if !isNumber && !isInteger {
return append(allErrs, NewInvalidTypeError(reflect.Int, reflect.TypeOf(value).Kind(), fieldName))
}
case "float64":
if _, ok := value.(float64); !ok {
return append(allErrs, NewInvalidTypeError(reflect.Float64, reflect.TypeOf(value).Kind(), fieldName))
}
case "boolean":
if _, ok := value.(bool); !ok {
return append(allErrs, NewInvalidTypeError(reflect.Bool, reflect.TypeOf(value).Kind(), fieldName))
}
// API servers before release 1.3 produce swagger spec with `type: "any"` as the fallback type, while newer servers produce spec with `type: "object"`.
// We have both here so that kubectl can work with both old and new api servers.
case "object":
case "any":
default:
return append(allErrs, fmt.Errorf("unexpected type: %v", fieldType))
}
return allErrs
}

View file

@ -0,0 +1,426 @@
/*
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 validation
import (
"encoding/json"
"fmt"
"io/ioutil"
"math/rand"
"strings"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
apitesting "k8s.io/kubernetes/pkg/api/testing"
"k8s.io/kubernetes/pkg/apimachinery/registered"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/runtime"
k8syaml "k8s.io/kubernetes/pkg/util/yaml"
"github.com/ghodss/yaml"
)
func readPod(filename string) ([]byte, error) {
data, err := ioutil.ReadFile("testdata/" + registered.GroupOrDie(api.GroupName).GroupVersion.Version + "/" + filename)
if err != nil {
return nil, err
}
return data, nil
}
func readSwaggerFile() ([]byte, error) {
return readSwaggerApiFile(testapi.Default)
}
func readSwaggerApiFile(group testapi.TestGroup) ([]byte, error) {
// TODO: Figure out a better way of finding these files
var pathToSwaggerSpec string
if group.GroupVersion().Group == "" {
pathToSwaggerSpec = "../../../api/swagger-spec/" + group.GroupVersion().Version + ".json"
} else {
pathToSwaggerSpec = "../../../api/swagger-spec/" + group.GroupVersion().Group + "_" + group.GroupVersion().Version + ".json"
}
return ioutil.ReadFile(pathToSwaggerSpec)
}
// Mock delegating Schema. Not a full fake impl.
type Factory struct {
defaultSchema Schema
extensionsSchema Schema
}
var _ Schema = &Factory{}
// TODO: Consider using a mocking library instead or fully fleshing this out into a fake impl and putting it in some
// generally available location
func (f *Factory) ValidateBytes(data []byte) error {
var obj interface{}
out, err := k8syaml.ToJSON(data)
if err != nil {
return err
}
data = out
if err := json.Unmarshal(data, &obj); err != nil {
return err
}
fields, ok := obj.(map[string]interface{})
if !ok {
return fmt.Errorf("error in unmarshaling data %s", string(data))
}
// Note: This only supports the 2 api versions we expect from the test it is currently supporting.
groupVersion := fields["apiVersion"]
switch groupVersion {
case "v1":
return f.defaultSchema.ValidateBytes(data)
case "extensions/v1beta1":
return f.extensionsSchema.ValidateBytes(data)
default:
return fmt.Errorf("Unsupported API version %s", groupVersion)
}
}
func loadSchemaForTest() (Schema, error) {
data, err := readSwaggerFile()
if err != nil {
return nil, err
}
return NewSwaggerSchemaFromBytes(data, nil)
}
func loadSchemaForTestWithFactory(group testapi.TestGroup, factory Schema) (Schema, error) {
data, err := readSwaggerApiFile(group)
if err != nil {
return nil, err
}
return NewSwaggerSchemaFromBytes(data, factory)
}
func NewFactory() (*Factory, error) {
f := &Factory{}
defaultSchema, err := loadSchemaForTestWithFactory(testapi.Default, f)
if err != nil {
return nil, err
}
f.defaultSchema = defaultSchema
extensionSchema, err := loadSchemaForTestWithFactory(testapi.Extensions, f)
if err != nil {
return nil, err
}
f.extensionsSchema = extensionSchema
return f, nil
}
func TestLoad(t *testing.T) {
_, err := loadSchemaForTest()
if err != nil {
t.Errorf("Failed to load: %v", err)
}
}
func TestValidateOk(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []struct {
obj runtime.Object
typeName string
}{
{obj: &api.Pod{}},
{obj: &api.Service{}},
{obj: &api.ReplicationController{}},
}
seed := rand.Int63()
apiObjectFuzzer := apitesting.FuzzerFor(nil, testapi.Default.InternalGroupVersion(), rand.NewSource(seed))
for i := 0; i < 5; i++ {
for _, test := range tests {
testObj := test.obj
apiObjectFuzzer.Fuzz(testObj)
data, err := runtime.Encode(testapi.Default.Codec(), testObj)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
err = schema.ValidateBytes(data)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
}
}
}
func TestValidateDifferentApiVersions(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
pod := &api.Pod{}
pod.APIVersion = "v1"
pod.Kind = "Pod"
deployment := &extensions.Deployment{}
deployment.APIVersion = "extensions/v1beta1"
deployment.Kind = "Deployment"
list := &api.List{}
list.APIVersion = "v1"
list.Kind = "List"
list.Items = []runtime.Object{pod, deployment}
bytes, err := json.Marshal(list)
if err != nil {
t.Error(err)
}
err = schema.ValidateBytes(bytes)
if err == nil {
t.Error(fmt.Errorf("Expected error when validating different api version and no delegate exists."))
}
f, err := NewFactory()
if err != nil {
t.Error(fmt.Errorf("Failed to create Schema factory %v.", err))
}
err = f.ValidateBytes(bytes)
if err != nil {
t.Error(fmt.Errorf("Failed to validate object with multiple ApiGroups: %v.", err))
}
}
func TestInvalid(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []string{
"invalidPod1.json", // command is a string, instead of []string.
"invalidPod2.json", // hostPort if of type string, instead of int.
"invalidPod3.json", // volumes is not an array of objects.
"invalidPod4.yaml", // string list with empty string.
"invalidPod.yaml", // command is a string, instead of []string.
}
for _, test := range tests {
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s, err: %v", test, err)
}
err = schema.ValidateBytes(pod)
if err == nil {
t.Errorf("unexpected non-error, err: %s for pod: %s", err, pod)
}
}
}
func TestValid(t *testing.T) {
schema, err := loadSchemaForTest()
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []string{
"validPod.yaml",
}
for _, test := range tests {
pod, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s, err: %v", test, err)
}
err = schema.ValidateBytes(pod)
if err != nil {
t.Errorf("unexpected error: %s, for pod %s", err, pod)
}
}
}
func TestVersionRegex(t *testing.T) {
testCases := []struct {
typeName string
match bool
}{
{
typeName: "v1.Binding",
match: true,
},
{
typeName: "v1beta1.Binding",
match: true,
},
{
typeName: "Binding",
match: false,
},
}
for _, test := range testCases {
if versionRegexp.MatchString(test.typeName) && !test.match {
t.Errorf("unexpected error: expect %s not to match the regular expression", test.typeName)
}
if !versionRegexp.MatchString(test.typeName) && test.match {
t.Errorf("unexpected error: expect %s to match the regular expression", test.typeName)
}
}
}
// Tests that validation works fine when spec contains "type": "any" instead of "type": "object"
// Ref: https://github.com/kubernetes/kubernetes/issues/24309
func TestTypeAny(t *testing.T) {
data, err := readSwaggerFile()
if err != nil {
t.Errorf("failed to read swagger file: %v", err)
}
// Replace type: "any" in the spec by type: "object" and verify that the validation still passes.
newData := strings.Replace(string(data), `"type": "object"`, `"type": "any"`, -1)
schema, err := NewSwaggerSchemaFromBytes([]byte(newData), nil)
if err != nil {
t.Fatalf("Failed to load: %v", err)
}
tests := []string{
"validPod.yaml",
}
for _, test := range tests {
podBytes, err := readPod(test)
if err != nil {
t.Errorf("could not read file: %s, err: %v", test, err)
}
// Verify that pod has at least one label (labels are type "any")
var pod api.Pod
err = yaml.Unmarshal(podBytes, &pod)
if err != nil {
t.Errorf("error in unmarshalling pod: %v", err)
}
if len(pod.Labels) == 0 {
t.Errorf("invalid test input: the pod should have at least one label")
}
err = schema.ValidateBytes(podBytes)
if err != nil {
t.Errorf("unexpected error: %s, for pod %s", err, string(podBytes))
}
}
}
func TestValidateDuplicateLabelsFailCases(t *testing.T) {
strs := []string{
`{
"metadata": {
"labels": {
"foo": "bar",
"foo": "baz"
}
}
}`,
`{
"metadata": {
"annotations": {
"foo": "bar",
"foo": "baz"
}
}
}`,
`{
"metadata": {
"labels": {
"foo": "blah"
},
"annotations": {
"foo": "bar",
"foo": "baz"
}
}
}`,
}
schema := NoDoubleKeySchema{}
for _, str := range strs {
err := schema.ValidateBytes([]byte(str))
if err == nil {
t.Errorf("Unexpected non-error %s", str)
}
}
}
func TestValidateDuplicateLabelsPassCases(t *testing.T) {
strs := []string{
`{
"metadata": {
"labels": {
"foo": "bar"
},
"annotations": {
"foo": "baz"
}
}
}`,
`{
"metadata": {}
}`,
`{
"metadata": {
"labels": {}
}
}`,
}
schema := NoDoubleKeySchema{}
for _, str := range strs {
err := schema.ValidateBytes([]byte(str))
if err != nil {
t.Errorf("Unexpected error: %v %s", err, str)
}
}
}
type AlwaysInvalidSchema struct{}
func (AlwaysInvalidSchema) ValidateBytes([]byte) error {
return fmt.Errorf("Always invalid!")
}
func TestConjunctiveSchema(t *testing.T) {
tests := []struct {
schemas []Schema
shouldPass bool
name string
}{
{
schemas: []Schema{NullSchema{}, NullSchema{}},
shouldPass: true,
name: "all pass",
},
{
schemas: []Schema{NullSchema{}, AlwaysInvalidSchema{}},
shouldPass: false,
name: "one fail",
},
{
schemas: []Schema{AlwaysInvalidSchema{}, AlwaysInvalidSchema{}},
shouldPass: false,
name: "all fail",
},
{
schemas: []Schema{},
shouldPass: true,
name: "empty",
},
}
for _, test := range tests {
schema := ConjunctiveSchema(test.schemas)
err := schema.ValidateBytes([]byte{})
if err != nil && test.shouldPass {
t.Errorf("Unexpected error: %v in %s", err, test.name)
}
if err == nil && !test.shouldPass {
t.Errorf("Unexpected non-error: %s", test.name)
}
}
}

View file

@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- args: "this is a bad command"
image: gcr.io/fake_project/fake_image:fake_tag
name: master

View file

@ -0,0 +1,19 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "name",
"labels": {
"name": "redis-master"
}
},
"spec": {
"containers": [
{
"name": "master",
"image": "gcr.io/fake_project/fake_image:fake_tag",
"args": "this is a bad command"
}
]
}
}

View file

@ -0,0 +1,35 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "apache-php",
"labels": {
"name": "apache-php"
}
},
"spec": {
"volumes": [{
"name": "shared-disk"
}],
"containers": [
{
"name": "apache-php",
"image": "gcr.io/fake_project/fake_image:fake_tag",
"ports": [
{
"name": "apache",
"hostPort": "13380",
"containerPort": 80,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"name": "shared-disk",
"mountPath": "/var/www/html"
}
]
}
]
}
}

View file

@ -0,0 +1,35 @@
{
"kind": "Pod",
"apiVersion": "v1",
"metadata": {
"name": "apache-php",
"labels": {
"name": "apache-php"
}
},
"spec": {
"volumes": [
"name": "shared-disk"
],
"containers": [
{
"name": "apache-php",
"image": "gcr.io/fake_project/fake_image:fake_tag",
"ports": [
{
"name": "apache",
"hostPort": 13380,
"containerPort": 80,
"protocol": "TCP"
}
],
"volumeMounts": [
{
"name": "shared-disk",
"mountPath": "/var/www/html"
}
]
}
]
}
}

View file

@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- image: gcr.io/fake_project/fake_image:fake_tag
name: master
args:
-
command:
-

View file

@ -0,0 +1,16 @@
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- args:
- this
- is
- an
- ok
- command
image: gcr.io/fake_project/fake_image:fake_tag
name: master

3753
vendor/k8s.io/kubernetes/pkg/api/validation/validation.go generated vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff