add prune and remove unused packages

This commit is contained in:
Michelle Au
2019-03-08 14:54:43 -08:00
parent f59b58d164
commit 8c0accad66
17240 changed files with 27 additions and 4750030 deletions

View File

@@ -1,49 +0,0 @@
/*
Copyright 2017 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 proto_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/config"
. "github.com/onsi/ginkgo/types"
. "github.com/onsi/gomega"
"fmt"
"testing"
)
func TestOpenapi(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t, "Openapi Suite", []Reporter{newlineReporter{}})
}
// Print a newline after the default newlineReporter due to issue
// https://github.com/jstemmer/go-junit-report/issues/31
type newlineReporter struct{}
func (newlineReporter) SpecSuiteWillBegin(config GinkgoConfigType, summary *SuiteSummary) {}
func (newlineReporter) BeforeSuiteDidRun(setupSummary *SetupSummary) {}
func (newlineReporter) AfterSuiteDidRun(setupSummary *SetupSummary) {}
func (newlineReporter) SpecWillRun(specSummary *SpecSummary) {}
func (newlineReporter) SpecDidComplete(specSummary *SpecSummary) {}
// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:"
func (newlineReporter) SpecSuiteDidEnd(summary *SuiteSummary) { fmt.Printf("\n") }

View File

@@ -1,265 +0,0 @@
/*
Copyright 2017 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 proto_test
import (
"path/filepath"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/util/proto/testing"
)
var fakeSchema = testing.Fake{Path: filepath.Join("testdata", "swagger.json")}
var fakeSchemaNext = testing.Fake{Path: filepath.Join("testdata", "swagger_next.json")}
var _ = Describe("Reading apps/v1beta1/Deployment from v1.8 openAPIData", func() {
var models proto.Models
BeforeEach(func() {
s, err := fakeSchema.OpenAPISchema()
Expect(err).To(BeNil())
models, err = proto.NewOpenAPIData(s)
Expect(err).To(BeNil())
})
model := "io.k8s.api.apps.v1beta1.Deployment"
var schema proto.Schema
It("should lookup the Schema by its model name", func() {
schema = models.LookupModel(model)
Expect(schema).ToNot(BeNil())
})
var deployment *proto.Kind
It("should be a Kind", func() {
deployment = schema.(*proto.Kind)
Expect(deployment).ToNot(BeNil())
})
It("should have a path", func() {
Expect(deployment.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment"}))
})
It("should have a kind key of type string", func() {
Expect(deployment.Fields).To(HaveKey("kind"))
key := deployment.Fields["kind"].(*proto.Primitive)
Expect(key).ToNot(BeNil())
Expect(key.Type).To(Equal("string"))
Expect(key.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment", ".kind"}))
})
It("should have a apiVersion key of type string", func() {
Expect(deployment.Fields).To(HaveKey("apiVersion"))
key := deployment.Fields["apiVersion"].(*proto.Primitive)
Expect(key).ToNot(BeNil())
Expect(key.Type).To(Equal("string"))
Expect(key.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.Deployment", ".apiVersion"}))
})
It("should have a metadata key of type Reference", func() {
Expect(deployment.Fields).To(HaveKey("metadata"))
key := deployment.Fields["metadata"].(proto.Reference)
Expect(key).ToNot(BeNil())
Expect(key.Reference()).To(Equal("io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta"))
subSchema := key.SubSchema().(*proto.Kind)
Expect(subSchema).ToNot(BeNil())
})
var status *proto.Kind
It("should have a status key of type Reference", func() {
Expect(deployment.Fields).To(HaveKey("status"))
key := deployment.Fields["status"].(proto.Reference)
Expect(key).ToNot(BeNil())
Expect(key.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentStatus"))
status = key.SubSchema().(*proto.Kind)
Expect(status).ToNot(BeNil())
})
It("should have a valid DeploymentStatus", func() {
By("having availableReplicas key")
Expect(status.Fields).To(HaveKey("availableReplicas"))
replicas := status.Fields["availableReplicas"].(*proto.Primitive)
Expect(replicas).ToNot(BeNil())
Expect(replicas.Type).To(Equal("integer"))
By("having conditions key")
Expect(status.Fields).To(HaveKey("conditions"))
conditions := status.Fields["conditions"].(*proto.Array)
Expect(conditions).ToNot(BeNil())
Expect(conditions.GetName()).To(Equal(`Array of Reference to "io.k8s.api.apps.v1beta1.DeploymentCondition"`))
Expect(conditions.GetExtensions()).To(Equal(map[string]interface{}{
"x-kubernetes-patch-merge-key": "type",
"x-kubernetes-patch-strategy": "merge",
}))
condition := conditions.SubType.(proto.Reference)
Expect(condition.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentCondition"))
})
var spec *proto.Kind
It("should have a spec key of type Reference", func() {
Expect(deployment.Fields).To(HaveKey("spec"))
key := deployment.Fields["spec"].(proto.Reference)
Expect(key).ToNot(BeNil())
Expect(key.Reference()).To(Equal("io.k8s.api.apps.v1beta1.DeploymentSpec"))
spec = key.SubSchema().(*proto.Kind)
Expect(spec).ToNot(BeNil())
})
It("should have a spec with no gvk", func() {
_, found := spec.GetExtensions()["x-kubernetes-group-version-kind"]
Expect(found).To(BeFalse())
})
It("should have a spec with a PodTemplateSpec sub-field", func() {
Expect(spec.Fields).To(HaveKey("template"))
key := spec.Fields["template"].(proto.Reference)
Expect(key).ToNot(BeNil())
Expect(key.Reference()).To(Equal("io.k8s.api.core.v1.PodTemplateSpec"))
})
})
var _ = Describe("Reading apps/v1beta1/Deployment from v1.11 openAPIData", func() {
var models proto.Models
BeforeEach(func() {
s, err := fakeSchemaNext.OpenAPISchema()
Expect(err).To(BeNil())
models, err = proto.NewOpenAPIData(s)
Expect(err).To(BeNil())
})
model := "io.k8s.api.apps.v1beta1.Deployment"
var schema proto.Schema
It("should lookup the Schema by its model name", func() {
schema = models.LookupModel(model)
Expect(schema).ToNot(BeNil())
})
var deployment *proto.Kind
It("should be a Kind", func() {
deployment = schema.(*proto.Kind)
Expect(deployment).ToNot(BeNil())
})
})
var _ = Describe("Reading apps/v1beta1/ControllerRevision from v1.11 openAPIData", func() {
var models proto.Models
BeforeEach(func() {
s, err := fakeSchemaNext.OpenAPISchema()
Expect(err).To(BeNil())
models, err = proto.NewOpenAPIData(s)
Expect(err).To(BeNil())
})
model := "io.k8s.api.apps.v1beta1.ControllerRevision"
var schema proto.Schema
It("should lookup the Schema by its model name", func() {
schema = models.LookupModel(model)
Expect(schema).ToNot(BeNil())
})
var cr *proto.Kind
It("data property should be map[string]Arbitrary", func() {
cr = schema.(*proto.Kind)
Expect(cr).ToNot(BeNil())
Expect(cr.Fields).To(HaveKey("data"))
data := cr.Fields["data"].(*proto.Map)
Expect(data).ToNot(BeNil())
Expect(data.GetName()).To(Equal("Map of Arbitrary value (primitive, object or array)"))
Expect(data.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.ControllerRevision", ".data"}))
arbitrary := data.SubType.(*proto.Arbitrary)
Expect(arbitrary).ToNot(BeNil())
Expect(arbitrary.GetName()).To(Equal("Arbitrary value (primitive, object or array)"))
Expect(arbitrary.GetPath().Get()).To(Equal([]string{"io.k8s.api.apps.v1beta1.ControllerRevision", ".data"}))
})
})
var _ = Describe("Reading authorization.k8s.io/v1/SubjectAccessReview from openAPIData", func() {
var models proto.Models
BeforeEach(func() {
s, err := fakeSchema.OpenAPISchema()
Expect(err).To(BeNil())
models, err = proto.NewOpenAPIData(s)
Expect(err).To(BeNil())
})
model := "io.k8s.api.authorization.v1.LocalSubjectAccessReview"
var schema proto.Schema
It("should lookup the Schema by its model", func() {
schema = models.LookupModel(model)
Expect(schema).ToNot(BeNil())
})
var sarspec *proto.Kind
It("should be a Kind and have a spec", func() {
sar := schema.(*proto.Kind)
Expect(sar).ToNot(BeNil())
Expect(sar.Fields).To(HaveKey("spec"))
specRef := sar.Fields["spec"].(proto.Reference)
Expect(specRef).ToNot(BeNil())
Expect(specRef.Reference()).To(Equal("io.k8s.api.authorization.v1.SubjectAccessReviewSpec"))
sarspec = specRef.SubSchema().(*proto.Kind)
Expect(sarspec).ToNot(BeNil())
})
It("should have a valid SubjectAccessReviewSpec", func() {
Expect(sarspec.Fields).To(HaveKey("extra"))
extra := sarspec.Fields["extra"].(*proto.Map)
Expect(extra).ToNot(BeNil())
Expect(extra.GetName()).To(Equal("Map of Array of string"))
Expect(extra.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"}))
array := extra.SubType.(*proto.Array)
Expect(array).ToNot(BeNil())
Expect(array.GetName()).To(Equal("Array of string"))
Expect(array.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"}))
str := array.SubType.(*proto.Primitive)
Expect(str).ToNot(BeNil())
Expect(str.Type).To(Equal("string"))
Expect(str.GetName()).To(Equal("string"))
Expect(str.GetPath().Get()).To(Equal([]string{"io.k8s.api.authorization.v1.SubjectAccessReviewSpec", ".extra"}))
})
})
var _ = Describe("Path", func() {
It("can be created by NewPath", func() {
path := proto.NewPath("key")
Expect(path.String()).To(Equal("key"))
})
It("can create and print complex paths", func() {
key := proto.NewPath("key")
array := key.ArrayPath(12)
field := array.FieldPath("subKey")
Expect(field.String()).To(Equal("key[12].subKey"))
})
It("has a length", func() {
key := proto.NewPath("key")
array := key.ArrayPath(12)
field := array.FieldPath("subKey")
Expect(field.Len()).To(Equal(3))
})
It("can look like an array", func() {
key := proto.NewPath("key")
array := key.ArrayPath(12)
field := array.FieldPath("subKey")
Expect(field.Get()).To(Equal([]string{"key", "[12]", ".subKey"}))
})
})

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,68 +0,0 @@
/*
Copyright 2017 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 testing
import (
"io/ioutil"
"os"
"sync"
yaml "gopkg.in/yaml.v2"
"github.com/googleapis/gnostic/OpenAPIv2"
"github.com/googleapis/gnostic/compiler"
)
// Fake opens and returns a openapi swagger from a file Path. It will
// parse only once and then return the same copy everytime.
type Fake struct {
Path string
once sync.Once
document *openapi_v2.Document
err error
}
// OpenAPISchema returns the openapi document and a potential error.
func (f *Fake) OpenAPISchema() (*openapi_v2.Document, error) {
f.once.Do(func() {
_, err := os.Stat(f.Path)
if err != nil {
f.err = err
return
}
spec, err := ioutil.ReadFile(f.Path)
if err != nil {
f.err = err
return
}
var info yaml.MapSlice
err = yaml.Unmarshal(spec, &info)
if err != nil {
f.err = err
return
}
f.document, f.err = openapi_v2.NewDocument(info, compiler.NewContext("$root", nil))
})
return f.document, f.err
}
type Empty struct{}
func (Empty) OpenAPISchema() (*openapi_v2.Document, error) {
return nil, nil
}

View File

@@ -1,79 +0,0 @@
/*
Copyright 2017 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"
)
type errors struct {
errors []error
}
func (e *errors) Errors() []error {
return e.errors
}
func (e *errors) AppendErrors(err ...error) {
e.errors = append(e.errors, err...)
}
type ValidationError struct {
Path string
Err error
}
func (e ValidationError) Error() string {
return fmt.Sprintf("ValidationError(%s): %v", e.Path, e.Err)
}
type InvalidTypeError struct {
Path string
Expected string
Actual string
}
func (e InvalidTypeError) Error() string {
return fmt.Sprintf("invalid type for %s: got %q, expected %q", e.Path, e.Actual, e.Expected)
}
type MissingRequiredFieldError struct {
Path string
Field string
}
func (e MissingRequiredFieldError) Error() string {
return fmt.Sprintf("missing required field %q in %s", e.Field, e.Path)
}
type UnknownFieldError struct {
Path string
Field string
}
func (e UnknownFieldError) Error() string {
return fmt.Sprintf("unknown field %q in %s", e.Field, e.Path)
}
type InvalidObjectTypeError struct {
Path string
Type string
}
func (e InvalidObjectTypeError) Error() string {
return fmt.Sprintf("unknown object type %q in %s", e.Type, e.Path)
}

View File

@@ -1,298 +0,0 @@
/*
Copyright 2017 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 (
"reflect"
"sort"
"k8s.io/kube-openapi/pkg/util/proto"
)
type validationItem interface {
proto.SchemaVisitor
Errors() []error
Path() *proto.Path
}
type baseItem struct {
errors errors
path proto.Path
}
// Errors returns the list of errors found for this item.
func (item *baseItem) Errors() []error {
return item.errors.Errors()
}
// AddValidationError wraps the given error into a ValidationError and
// attaches it to this item.
func (item *baseItem) AddValidationError(err error) {
item.errors.AppendErrors(ValidationError{Path: item.path.String(), Err: err})
}
// AddError adds a regular (non-validation related) error to the list.
func (item *baseItem) AddError(err error) {
item.errors.AppendErrors(err)
}
// CopyErrors adds a list of errors to this item. This is useful to copy
// errors from subitems.
func (item *baseItem) CopyErrors(errs []error) {
item.errors.AppendErrors(errs...)
}
// Path returns the path of this item, helps print useful errors.
func (item *baseItem) Path() *proto.Path {
return &item.path
}
// mapItem represents a map entry in the yaml.
type mapItem struct {
baseItem
Map map[string]interface{}
}
func (item *mapItem) sortedKeys() []string {
sortedKeys := []string{}
for key := range item.Map {
sortedKeys = append(sortedKeys, key)
}
sort.Strings(sortedKeys)
return sortedKeys
}
var _ validationItem = &mapItem{}
func (item *mapItem) VisitPrimitive(schema *proto.Primitive) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: schema.Type, Actual: "map"})
}
func (item *mapItem) VisitArray(schema *proto.Array) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "array", Actual: "map"})
}
func (item *mapItem) VisitMap(schema *proto.Map) {
for _, key := range item.sortedKeys() {
subItem, err := itemFactory(item.Path().FieldPath(key), item.Map[key])
if err != nil {
item.AddError(err)
continue
}
schema.SubType.Accept(subItem)
item.CopyErrors(subItem.Errors())
}
}
func (item *mapItem) VisitKind(schema *proto.Kind) {
// Verify each sub-field.
for _, key := range item.sortedKeys() {
if item.Map[key] == nil {
continue
}
subItem, err := itemFactory(item.Path().FieldPath(key), item.Map[key])
if err != nil {
item.AddError(err)
continue
}
if _, ok := schema.Fields[key]; !ok {
item.AddValidationError(UnknownFieldError{Path: schema.GetPath().String(), Field: key})
continue
}
schema.Fields[key].Accept(subItem)
item.CopyErrors(subItem.Errors())
}
// Verify that all required fields are present.
for _, required := range schema.RequiredFields {
if v, ok := item.Map[required]; !ok || v == nil {
item.AddValidationError(MissingRequiredFieldError{Path: schema.GetPath().String(), Field: required})
}
}
}
func (item *mapItem) VisitArbitrary(schema *proto.Arbitrary) {
}
func (item *mapItem) VisitReference(schema proto.Reference) {
// passthrough
schema.SubSchema().Accept(item)
}
// arrayItem represents a yaml array.
type arrayItem struct {
baseItem
Array []interface{}
}
var _ validationItem = &arrayItem{}
func (item *arrayItem) VisitPrimitive(schema *proto.Primitive) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: schema.Type, Actual: "array"})
}
func (item *arrayItem) VisitArray(schema *proto.Array) {
for i, v := range item.Array {
path := item.Path().ArrayPath(i)
if v == nil {
item.AddValidationError(InvalidObjectTypeError{Type: "nil", Path: path.String()})
continue
}
subItem, err := itemFactory(path, v)
if err != nil {
item.AddError(err)
continue
}
schema.SubType.Accept(subItem)
item.CopyErrors(subItem.Errors())
}
}
func (item *arrayItem) VisitMap(schema *proto.Map) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: "array"})
}
func (item *arrayItem) VisitKind(schema *proto.Kind) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: "array"})
}
func (item *arrayItem) VisitArbitrary(schema *proto.Arbitrary) {
}
func (item *arrayItem) VisitReference(schema proto.Reference) {
// passthrough
schema.SubSchema().Accept(item)
}
// primitiveItem represents a yaml value.
type primitiveItem struct {
baseItem
Value interface{}
Kind string
}
var _ validationItem = &primitiveItem{}
func (item *primitiveItem) VisitPrimitive(schema *proto.Primitive) {
// Some types of primitives can match more than one (a number
// can be a string, but not the other way around). Return from
// the switch if we have a valid possible type conversion
// NOTE(apelisse): This logic is blindly copied from the
// existing swagger logic, and I'm not sure I agree with it.
switch schema.Type {
case proto.Boolean:
switch item.Kind {
case proto.Boolean:
return
}
case proto.Integer:
switch item.Kind {
case proto.Integer, proto.Number:
return
}
case proto.Number:
switch item.Kind {
case proto.Number:
return
}
case proto.String:
return
}
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: schema.Type, Actual: item.Kind})
}
func (item *primitiveItem) VisitArray(schema *proto.Array) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "array", Actual: item.Kind})
}
func (item *primitiveItem) VisitMap(schema *proto.Map) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: item.Kind})
}
func (item *primitiveItem) VisitKind(schema *proto.Kind) {
item.AddValidationError(InvalidTypeError{Path: schema.GetPath().String(), Expected: "map", Actual: item.Kind})
}
func (item *primitiveItem) VisitArbitrary(schema *proto.Arbitrary) {
}
func (item *primitiveItem) VisitReference(schema proto.Reference) {
// passthrough
schema.SubSchema().Accept(item)
}
// itemFactory creates the relevant item type/visitor based on the current yaml type.
func itemFactory(path proto.Path, v interface{}) (validationItem, error) {
// We need to special case for no-type fields in yaml (e.g. empty item in list)
if v == nil {
return nil, InvalidObjectTypeError{Type: "nil", Path: path.String()}
}
kind := reflect.TypeOf(v).Kind()
switch kind {
case reflect.Bool:
return &primitiveItem{
baseItem: baseItem{path: path},
Value: v,
Kind: proto.Boolean,
}, nil
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64,
reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
return &primitiveItem{
baseItem: baseItem{path: path},
Value: v,
Kind: proto.Integer,
}, nil
case reflect.Float32,
reflect.Float64:
return &primitiveItem{
baseItem: baseItem{path: path},
Value: v,
Kind: proto.Number,
}, nil
case reflect.String:
return &primitiveItem{
baseItem: baseItem{path: path},
Value: v,
Kind: proto.String,
}, nil
case reflect.Array,
reflect.Slice:
return &arrayItem{
baseItem: baseItem{path: path},
Array: v.([]interface{}),
}, nil
case reflect.Map:
return &mapItem{
baseItem: baseItem{path: path},
Map: v.(map[string]interface{}),
}, nil
}
return nil, InvalidObjectTypeError{Type: kind.String(), Path: path.String()}
}

View File

@@ -1,30 +0,0 @@
/*
Copyright 2017 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 (
"k8s.io/kube-openapi/pkg/util/proto"
)
func ValidateModel(obj interface{}, schema proto.Schema, name string) []error {
rootValidation, err := itemFactory(proto.NewPath(name), obj)
if err != nil {
return []error{err}
}
schema.Accept(rootValidation)
return rootValidation.Errors()
}

View File

@@ -1,49 +0,0 @@
/*
Copyright 2017 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 (
. "github.com/onsi/ginkgo"
. "github.com/onsi/ginkgo/config"
. "github.com/onsi/ginkgo/types"
. "github.com/onsi/gomega"
"fmt"
"testing"
)
func TestOpenapi(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t, "Openapi Suite", []Reporter{newlineReporter{}})
}
// Print a newline after the default newlineReporter due to issue
// https://github.com/jstemmer/go-junit-report/issues/31
type newlineReporter struct{}
func (newlineReporter) SpecSuiteWillBegin(config GinkgoConfigType, summary *SuiteSummary) {}
func (newlineReporter) BeforeSuiteDidRun(setupSummary *SetupSummary) {}
func (newlineReporter) AfterSuiteDidRun(setupSummary *SetupSummary) {}
func (newlineReporter) SpecWillRun(specSummary *SpecSummary) {}
func (newlineReporter) SpecDidComplete(specSummary *SpecSummary) {}
// SpecSuiteDidEnd Prints a newline between "35 Passed | 0 Failed | 0 Pending | 0 Skipped" and "--- PASS:"
func (newlineReporter) SpecSuiteDidEnd(summary *SuiteSummary) { fmt.Printf("\n") }

View File

@@ -1,369 +0,0 @@
/*
Copyright 2017 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_test
import (
"fmt"
"path/filepath"
"github.com/ghodss/yaml"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/util/proto/testing"
"k8s.io/kube-openapi/pkg/util/proto/validation"
)
var fakeSchema = testing.Fake{Path: filepath.Join("..", "testdata", "swagger.json")}
func Validate(models proto.Models, model string, data string) []error {
var obj interface{}
if err := yaml.Unmarshal([]byte(data), &obj); err != nil {
return []error{fmt.Errorf("pre-validation: failed to parse yaml: %v", err)}
}
schema := models.LookupModel(model)
if schema == nil {
return []error{fmt.Errorf("pre-validation: couldn't find model %s", model)}
}
return validation.ValidateModel(obj, schema, model)
}
var _ = Describe("resource validation using OpenAPI Schema", func() {
var models proto.Models
BeforeEach(func() {
s, err := fakeSchema.OpenAPISchema()
Expect(err).To(BeNil())
models, err = proto.NewOpenAPIData(s)
Expect(err).To(BeNil())
})
It("finds Deployment in Schema and validates it", func() {
err := Validate(models, "io.k8s.api.apps.v1beta1.Deployment", `
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
name: redis-master
name: name
spec:
replicas: 1
template:
metadata:
labels:
app: redis
spec:
containers:
- image: redis
name: redis
`)
Expect(err).To(BeNil())
})
It("validates a valid pod", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
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
`)
Expect(err).To(BeNil())
})
It("finds invalid command (string instead of []string) in Json Pod", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
{
"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"
}
]
}
}
`)
Expect(err).To(Equal([]error{
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].args",
Err: validation.InvalidTypeError{
Path: "io.k8s.api.core.v1.Container.args",
Expected: "array",
Actual: "string",
},
},
}))
})
It("fails because hostPort is string instead of int", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
{
"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"
}
]
}
]
}
}
`)
Expect(err).To(Equal([]error{
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].ports[0].hostPort",
Err: validation.InvalidTypeError{
Path: "io.k8s.api.core.v1.ContainerPort.hostPort",
Expected: "integer",
Actual: "string",
},
},
}))
})
It("fails because volume is not an array of object", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
{
"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"
}
]
}
]
}
}
`)
Expect(err).To(BeNil())
})
It("fails because some string lists have empty strings", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
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:
-
`)
Expect(err).To(Equal([]error{
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].args",
Err: validation.InvalidObjectTypeError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].args[0]",
Type: "nil",
},
},
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].command",
Err: validation.InvalidObjectTypeError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0].command[0]",
Type: "nil",
},
},
}))
})
It("fails if required fields are missing", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- command: ["my", "command"]
`)
Expect(err).To(Equal([]error{
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
Err: validation.MissingRequiredFieldError{
Path: "io.k8s.api.core.v1.Container",
Field: "name",
},
},
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
Err: validation.MissingRequiredFieldError{
Path: "io.k8s.api.core.v1.Container",
Field: "image",
},
},
}))
})
It("fails if required fields are empty", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- image:
name:
`)
Expect(err).To(Equal([]error{
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
Err: validation.MissingRequiredFieldError{
Path: "io.k8s.api.core.v1.Container",
Field: "name",
},
},
validation.ValidationError{
Path: "io.k8s.api.core.v1.Pod.spec.containers[0]",
Err: validation.MissingRequiredFieldError{
Path: "io.k8s.api.core.v1.Container",
Field: "image",
},
},
}))
})
It("is fine with empty non-mandatory fields", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
apiVersion: v1
kind: Pod
metadata:
labels:
name: redis-master
name: name
spec:
containers:
- image: image
name: name
command:
`)
Expect(err).To(BeNil())
})
It("fails because apiVersion is not provided", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
kind: Pod
metadata:
name: name
spec:
containers:
- name: name
image: image
`)
Expect(err).To(BeNil())
})
It("fails because apiVersion type is not string and kind is not provided", func() {
err := Validate(models, "io.k8s.api.core.v1.Pod", `
apiVersion: 1
metadata:
name: name
spec:
containers:
- name: name
image: image
`)
Expect(err).To(BeNil())
})
})

View File

@@ -1,27 +0,0 @@
/*
Copyright 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.
*/
// Code generated by set-gen. DO NOT EDIT.
// NOTE: This file is copied from k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/sets/empty.go
// because in Kubernetes we don't allowed vendor code to import staging code. See
// https://github.com/kubernetes/kube-openapi/pull/90 for more details.
package sets
// Empty is public since it is used by some internal API objects for conversions between external
// string arrays and internal sets, and conversion logic requires public types today.
type Empty struct{}

View File

@@ -1,207 +0,0 @@
/*
Copyright 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.
*/
// Code generated by set-gen. DO NOT EDIT.
// NOTE: This file is copied from k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/util/sets/string.go
// because in Kubernetes we don't allowed vendor code to import staging code. See
// https://github.com/kubernetes/kube-openapi/pull/90 for more details.
package sets
import (
"reflect"
"sort"
)
// sets.String is a set of strings, implemented via map[string]struct{} for minimal memory consumption.
type String map[string]Empty
// NewString creates a String from a list of values.
func NewString(items ...string) String {
ss := String{}
ss.Insert(items...)
return ss
}
// StringKeySet creates a String from a keys of a map[string](? extends interface{}).
// If the value passed in is not actually a map, this will panic.
func StringKeySet(theMap interface{}) String {
v := reflect.ValueOf(theMap)
ret := String{}
for _, keyValue := range v.MapKeys() {
ret.Insert(keyValue.Interface().(string))
}
return ret
}
// Insert adds items to the set.
func (s String) Insert(items ...string) {
for _, item := range items {
s[item] = Empty{}
}
}
// Delete removes all items from the set.
func (s String) Delete(items ...string) {
for _, item := range items {
delete(s, item)
}
}
// Has returns true if and only if item is contained in the set.
func (s String) Has(item string) bool {
_, contained := s[item]
return contained
}
// HasAll returns true if and only if all items are contained in the set.
func (s String) HasAll(items ...string) bool {
for _, item := range items {
if !s.Has(item) {
return false
}
}
return true
}
// HasAny returns true if any items are contained in the set.
func (s String) HasAny(items ...string) bool {
for _, item := range items {
if s.Has(item) {
return true
}
}
return false
}
// Difference returns a set of objects that are not in s2
// For example:
// s1 = {a1, a2, a3}
// s2 = {a1, a2, a4, a5}
// s1.Difference(s2) = {a3}
// s2.Difference(s1) = {a4, a5}
func (s String) Difference(s2 String) String {
result := NewString()
for key := range s {
if !s2.Has(key) {
result.Insert(key)
}
}
return result
}
// Union returns a new set which includes items in either s1 or s2.
// For example:
// s1 = {a1, a2}
// s2 = {a3, a4}
// s1.Union(s2) = {a1, a2, a3, a4}
// s2.Union(s1) = {a1, a2, a3, a4}
func (s1 String) Union(s2 String) String {
result := NewString()
for key := range s1 {
result.Insert(key)
}
for key := range s2 {
result.Insert(key)
}
return result
}
// Intersection returns a new set which includes the item in BOTH s1 and s2
// For example:
// s1 = {a1, a2}
// s2 = {a2, a3}
// s1.Intersection(s2) = {a2}
func (s1 String) Intersection(s2 String) String {
var walk, other String
result := NewString()
if s1.Len() < s2.Len() {
walk = s1
other = s2
} else {
walk = s2
other = s1
}
for key := range walk {
if other.Has(key) {
result.Insert(key)
}
}
return result
}
// IsSuperset returns true if and only if s1 is a superset of s2.
func (s1 String) IsSuperset(s2 String) bool {
for item := range s2 {
if !s1.Has(item) {
return false
}
}
return true
}
// Equal returns true if and only if s1 is equal (as a set) to s2.
// Two sets are equal if their membership is identical.
// (In practice, this means same elements, order doesn't matter)
func (s1 String) Equal(s2 String) bool {
return len(s1) == len(s2) && s1.IsSuperset(s2)
}
type sortableSliceOfString []string
func (s sortableSliceOfString) Len() int { return len(s) }
func (s sortableSliceOfString) Less(i, j int) bool { return lessString(s[i], s[j]) }
func (s sortableSliceOfString) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// List returns the contents as a sorted string slice.
func (s String) List() []string {
res := make(sortableSliceOfString, 0, len(s))
for key := range s {
res = append(res, key)
}
sort.Sort(res)
return []string(res)
}
// UnsortedList returns the slice with contents in random order.
func (s String) UnsortedList() []string {
res := make([]string, 0, len(s))
for key := range s {
res = append(res, key)
}
return res
}
// Returns a single element from the set.
func (s String) PopAny() (string, bool) {
for key := range s {
s.Delete(key)
return key, true
}
var zeroValue string
return zeroValue, false
}
// Len returns the size of the set.
func (s String) Len() int {
return len(s)
}
func lessString(lhs, rhs string) bool {
return lhs < rhs
}

View File

@@ -1,79 +0,0 @@
/*
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 util
// A simple trie implementation with Add and HasPrefix methods only.
type Trie struct {
children map[byte]*Trie
wordTail bool
word string
}
// NewTrie creates a Trie and add all strings in the provided list to it.
func NewTrie(list []string) Trie {
ret := Trie{
children: make(map[byte]*Trie),
wordTail: false,
}
for _, v := range list {
ret.Add(v)
}
return ret
}
// Add adds a word to this trie
func (t *Trie) Add(v string) {
root := t
for _, b := range []byte(v) {
child, exists := root.children[b]
if !exists {
child = &Trie{
children: make(map[byte]*Trie),
wordTail: false,
}
root.children[b] = child
}
root = child
}
root.wordTail = true
root.word = v
}
// HasPrefix returns true of v has any of the prefixes stored in this trie.
func (t *Trie) HasPrefix(v string) bool {
_, has := t.GetPrefix(v)
return has
}
// GetPrefix is like HasPrefix but return the prefix in case of match or empty string otherwise.
func (t *Trie) GetPrefix(v string) (string, bool) {
root := t
if root.wordTail {
return root.word, true
}
for _, b := range []byte(v) {
child, exists := root.children[b]
if !exists {
return "", false
}
if child.wordTail {
return child.word, true
}
root = child
}
return "", false
}

View File

@@ -1,59 +0,0 @@
/*
Copyright 2017 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 util
import (
"reflect"
"strings"
)
// ToCanonicalName converts Golang package/type name into canonical OpenAPI name.
// Examples:
// Input: k8s.io/api/core/v1.Pod
// Output: io.k8s.api.core.v1.Pod
//
// Input: k8s.io/api/core/v1
// Output: io.k8s.api.core.v1
func ToCanonicalName(name string) string {
nameParts := strings.Split(name, "/")
// Reverse first part. e.g., io.k8s... instead of k8s.io...
if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") {
parts := strings.Split(nameParts[0], ".")
for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
parts[i], parts[j] = parts[j], parts[i]
}
nameParts[0] = strings.Join(parts, ".")
}
return strings.Join(nameParts, ".")
}
// GetCanonicalTypeName will find the canonical type name of a sample object, removing
// the "vendor" part of the path
func GetCanonicalTypeName(model interface{}) string {
t := reflect.TypeOf(model)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.PkgPath() == "" {
return t.Name()
}
path := t.PkgPath()
if strings.Contains(path, "/vendor/") {
path = path[strings.Index(path, "/vendor/")+len("/vendor/"):]
}
return path + "." + t.Name()
}

View File

@@ -1,58 +0,0 @@
/*
Copyright 2018 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 util
import (
"reflect"
"testing"
)
func TestCanonicalName(t *testing.T) {
var tests = []struct {
input string
expected string
}{
{"k8s.io/api/core/v1.Pod", "io.k8s.api.core.v1.Pod"},
{"k8s.io/api/networking/v1/NetworkPolicy", "io.k8s.api.networking.v1.NetworkPolicy"},
{"k8s.io/api/apps/v1beta2.Scale", "io.k8s.api.apps.v1beta2.Scale"},
{"servicecatalog.k8s.io/foo/bar/v1alpha1.Baz", "io.k8s.servicecatalog.foo.bar.v1alpha1.Baz"},
}
for _, test := range tests {
if got := ToCanonicalName(test.input); got != test.expected {
t.Errorf("ToCanonicalName(%q) = %v", test.input, got)
}
}
}
type TestType struct{}
func TestGetCanonicalTypeName(t *testing.T) {
var tests = []struct {
input interface{}
expected string
}{
{TestType{}, "k8s.io/kube-openapi/pkg/util.TestType"},
{&TestType{}, "k8s.io/kube-openapi/pkg/util.TestType"},
}
for _, test := range tests {
if got := GetCanonicalTypeName(test.input); got != test.expected {
t.Errorf("GetCanonicalTypeName(%q) = %v", reflect.TypeOf(test.input), got)
}
}
}