Bumping k8s dependencies to 1.13

This commit is contained in:
Cheng Xing
2018-11-16 14:08:25 -08:00
parent 305407125c
commit b4c0b68ec7
8002 changed files with 884099 additions and 276228 deletions

View File

@@ -21,8 +21,8 @@ import (
"sort"
"strings"
openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2"
yaml "gopkg.in/yaml.v2"
"github.com/googleapis/gnostic/OpenAPIv2"
"gopkg.in/yaml.v2"
)
func newSchemaError(path *Path, format string, a ...interface{}) error {
@@ -126,12 +126,17 @@ func (d *Definitions) parseMap(s *openapi_v2.Schema, path *Path) (Schema, error)
if len(s.GetType().GetValue()) != 0 && s.GetType().GetValue()[0] != object {
return nil, newSchemaError(path, "invalid object type")
}
var sub Schema
if s.GetAdditionalProperties().GetSchema() == nil {
return nil, newSchemaError(path, "invalid object doesn't have additional properties")
}
sub, err := d.ParseSchema(s.GetAdditionalProperties().GetSchema(), path)
if err != nil {
return nil, err
sub = &Arbitrary{
BaseSchema: d.parseBaseSchema(s, path),
}
} else {
var err error
sub, err = d.ParseSchema(s.GetAdditionalProperties().GetSchema(), path)
if err != nil {
return nil, err
}
}
return &Map{
BaseSchema: d.parseBaseSchema(s, path),
@@ -148,12 +153,10 @@ func (d *Definitions) parsePrimitive(s *openapi_v2.Schema, path *Path) (Schema,
t = s.GetType().GetValue()[0]
}
switch t {
case String:
case Number:
case Integer:
case Boolean:
case "": // Some models are completely empty, and can be safely ignored.
// Do nothing
case String: // do nothing
case Number: // do nothing
case Integer: // do nothing
case Boolean: // do nothing
default:
return nil, newSchemaError(path, "Unknown primitive type: %q", t)
}
@@ -193,20 +196,24 @@ func (d *Definitions) parseKind(s *openapi_v2.Schema, path *Path) (Schema, error
}
fields := map[string]Schema{}
fieldOrder := []string{}
for _, namedSchema := range s.GetProperties().GetAdditionalProperties() {
var err error
path := path.FieldPath(namedSchema.GetName())
fields[namedSchema.GetName()], err = d.ParseSchema(namedSchema.GetValue(), &path)
name := namedSchema.GetName()
path := path.FieldPath(name)
fields[name], err = d.ParseSchema(namedSchema.GetValue(), &path)
if err != nil {
return nil, err
}
fieldOrder = append(fieldOrder, name)
}
return &Kind{
BaseSchema: d.parseBaseSchema(s, path),
RequiredFields: s.GetRequired(),
Fields: fields,
FieldOrder: fieldOrder,
}, nil
}
@@ -219,27 +226,38 @@ func (d *Definitions) parseArbitrary(s *openapi_v2.Schema, path *Path) (Schema,
// ParseSchema creates a walkable Schema from an openapi schema. While
// this function is public, it doesn't leak through the interface.
func (d *Definitions) ParseSchema(s *openapi_v2.Schema, path *Path) (Schema, error) {
objectTypes := s.GetType().GetValue()
if len(objectTypes) == 1 {
t := objectTypes[0]
switch t {
case object:
return d.parseMap(s, path)
case array:
return d.parseArray(s, path)
}
}
if s.GetXRef() != "" {
return d.parseReference(s, path)
}
if s.GetProperties() != nil {
return d.parseKind(s, path)
objectTypes := s.GetType().GetValue()
switch len(objectTypes) {
case 0:
// in the OpenAPI schema served by older k8s versions, object definitions created from structs did not include
// the type:object property (they only included the "properties" property), so we need to handle this case
if s.GetProperties() != nil {
return d.parseKind(s, path)
} else {
// Definition has no type and no properties. Treat it as an arbitrary value
// TODO: what if it has additionalProperties or patternProperties?
return d.parseArbitrary(s, path)
}
case 1:
t := objectTypes[0]
switch t {
case object:
if s.GetProperties() != nil {
return d.parseKind(s, path)
} else {
return d.parseMap(s, path)
}
case array:
return d.parseArray(s, path)
}
return d.parsePrimitive(s, path)
default:
// the OpenAPI generator never generates (nor it ever did in the past) OpenAPI type definitions with multiple types
return nil, newSchemaError(path, "definitions with multiple types aren't supported")
}
if len(objectTypes) == 0 || (len(objectTypes) == 1 && objectTypes[0] == "") {
return d.parseArbitrary(s, path)
}
return d.parsePrimitive(s, path)
}
// LookupModel is public through the interface of Models. It

View File

@@ -59,7 +59,7 @@ type SchemaVisitor interface {
}
// SchemaVisitorArbitrary is an additional visitor interface which handles
// arbitrary types. For backwards compatability, it's a separate interface
// arbitrary types. For backwards compatibility, it's a separate interface
// which is checked for at runtime.
type SchemaVisitorArbitrary interface {
SchemaVisitor
@@ -173,6 +173,8 @@ type Kind struct {
RequiredFields []string
// Maps field names to types.
Fields map[string]Schema
// FieldOrder reports the canonical order for the fields.
FieldOrder []string
}
var _ Schema = &Kind{}

View File

@@ -26,9 +26,10 @@ import (
"k8s.io/kube-openapi/pkg/util/proto/testing"
)
var fakeSchema = testing.Fake{Path: filepath.Join("testing", "swagger.json")}
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 openAPIData", func() {
var _ = Describe("Reading apps/v1beta1/Deployment from v1.8 openAPIData", func() {
var models proto.Models
BeforeEach(func() {
s, err := fakeSchema.OpenAPISchema()
@@ -132,6 +133,63 @@ var _ = Describe("Reading apps/v1beta1/Deployment from openAPIData", func() {
})
})
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() {

View File

@@ -1112,7 +1112,7 @@
"type": "string"
},
"kind": {
"description": "Expected values Shared: mulitple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared",
"description": "Expected values Shared: multiple blob disks per storage account Dedicated: single blob disk per storage account Managed: azure managed data disk (only in managed availability set). defaults to shared",
"type": "string"
},
"readOnly": {
@@ -1672,7 +1672,7 @@
],
"properties": {
"names": {
"description": "Names by which this image is known. e.g. [\"gcr.io/google_containers/hyperkube:v1.0.7\", \"dockerhub.io/google_containers/hyperkube:v1.0.7\"]",
"description": "Names by which this image is known. e.g. [\"k8s.gcr.io/hyperkube:v1.0.7\", \"dockerhub.io/google_containers/hyperkube:v1.0.7\"]",
"type": "array",
"items": {
"type": "string"

File diff suppressed because it is too large Load Diff

View File

@@ -60,3 +60,9 @@ func (f *Fake) OpenAPISchema() (*openapi_v2.Document, error) {
})
return f.document, f.err
}
type Empty struct{}
func (Empty) OpenAPISchema() (*openapi_v2.Document, error) {
return nil, nil
}

View File

@@ -0,0 +1,49 @@
/*
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

@@ -0,0 +1,369 @@
/*
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())
})
})