mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 19:01:49 +00:00
Merge pull request #47263 from nikhita/crd-01-validation-types
Automatic merge from submit-queue apiextensions: validation for customresources - [x] Add types for validation of CustomResources - [x] Fix conversion-gen: #49747 - [x] Fix defaulter-gen: kubernetes/gengo#61 - [x] Convert to OpenAPI types - [x] Validate CR using go-openapi - [x] Validate CRD Schema - [x] Add integration tests - [x] Fix round trip tests: #51204 - [x] Add custom fuzzer functions - [x] Add custom conversion functions - [x] Fix data race while updating CRD: #50098 - [x] Add feature gate for CustomResourceValidation - [x] Fix protobuf generation Proposal: https://github.com/kubernetes/community/pull/708 Additional discussion: https://github.com/kubernetes/kubernetes/issues/49879, https://github.com/kubernetes/kubernetes/pull/50625 **Release note**: ```release-note Add validation for CustomResources via JSON Schema. ``` /cc @sttts @deads2k
This commit is contained in:
commit
4457e43e7b
@ -548,6 +548,7 @@ staging/src/k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion/
|
||||
staging/src/k8s.io/apiextensions-apiserver/pkg/cmd/server
|
||||
staging/src/k8s.io/apiextensions-apiserver/pkg/controller/finalizer
|
||||
staging/src/k8s.io/apiextensions-apiserver/pkg/controller/status
|
||||
staging/src/k8s.io/apiextensions-apiserver/pkg/features
|
||||
staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource
|
||||
staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition
|
||||
staging/src/k8s.io/apiextensions-apiserver/test/integration/testserver
|
||||
|
@ -9,6 +9,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["kube_features.go"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/features:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package features
|
||||
|
||||
import (
|
||||
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
)
|
||||
@ -44,13 +45,6 @@ const (
|
||||
// alpha: v1.4
|
||||
DynamicKubeletConfig utilfeature.Feature = "DynamicKubeletConfig"
|
||||
|
||||
// owner: tallclair
|
||||
// alpha: v1.5
|
||||
//
|
||||
// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
|
||||
// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
|
||||
StreamingProxyRedirects utilfeature.Feature = genericfeatures.StreamingProxyRedirects
|
||||
|
||||
// owner: @pweil-
|
||||
// alpha: v1.5
|
||||
//
|
||||
@ -158,11 +152,16 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
||||
DebugContainers: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
PodPriority: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
EnableEquivalenceClassCache: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
TaintNodesByCondition: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
|
||||
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta},
|
||||
genericfeatures.AdvancedAuditing: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
TaintNodesByCondition: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
genericfeatures.Initializers: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
genericfeatures.StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta},
|
||||
genericfeatures.AdvancedAuditing: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
genericfeatures.APIResponseCompression: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
genericfeatures.Initializers: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
|
||||
// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
apiextensionsfeatures.CustomResourceValidation: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@ syntax = 'proto2';
|
||||
|
||||
package k8s.io.api.core.v1;
|
||||
|
||||
import "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/api/resource/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
|
@ -45,6 +45,7 @@ filegroup(
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/cmd/server:all-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/controller/finalizer:all-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/controller/status:all-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:all-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource:all-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition:all-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/test/integration:all-srcs",
|
||||
|
@ -22,6 +22,10 @@
|
||||
"ImportPath": "github.com/PuerkitoBio/urlesc",
|
||||
"Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/asaskevich/govalidator",
|
||||
"Rev": "593d64559f7600f29581a3ee42177f5dbded27a9"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/beorn7/perks/quantile",
|
||||
"Rev": "3ac7bf7a47d159a033b107610db8a1b6575507a4"
|
||||
@ -110,6 +114,14 @@
|
||||
"ImportPath": "github.com/ghodss/yaml",
|
||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/analysis",
|
||||
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/errors",
|
||||
"Rev": "d24ebc2075bad502fac3a8ae27aa6dd58e1952dc"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||
@ -118,14 +130,30 @@
|
||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/loads",
|
||||
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/runtime",
|
||||
"Rev": "11e322eeecc1032d5a0a96c566ed53f2b5c26e22"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/spec",
|
||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/strfmt",
|
||||
"Rev": "d65c7fdb29eca313476e529628176fe17e58c488"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/swag",
|
||||
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-openapi/validate",
|
||||
"Rev": "deaf2c9013bc1a7f4c774662259a506ba874d80f"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||
|
@ -9,10 +9,12 @@ load(
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"deepcopy.go",
|
||||
"doc.go",
|
||||
"helpers.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"types_jsonschema.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
deps = [
|
||||
|
@ -0,0 +1,279 @@
|
||||
/*
|
||||
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 apiextensions
|
||||
|
||||
// TODO: Update this after a tag is created for interface fields in DeepCopy
|
||||
func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaProps)
|
||||
|
||||
*out = *in
|
||||
|
||||
if in.Default != nil {
|
||||
defaultJSON := JSON(deepCopyJSON(*(in.Default)))
|
||||
out.Default = &(defaultJSON)
|
||||
} else {
|
||||
out.Default = nil
|
||||
}
|
||||
|
||||
if in.Example != nil {
|
||||
exampleJSON := JSON(deepCopyJSON(*(in.Example)))
|
||||
out.Example = &(exampleJSON)
|
||||
} else {
|
||||
out.Example = nil
|
||||
}
|
||||
|
||||
if in.Ref != nil {
|
||||
in, out := &in.Ref, &out.Ref
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Maximum != nil {
|
||||
in, out := &in.Maximum, &out.Maximum
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Minimum != nil {
|
||||
in, out := &in.Minimum, &out.Minimum
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MaxLength != nil {
|
||||
in, out := &in.MaxLength, &out.MaxLength
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinLength != nil {
|
||||
in, out := &in.MinLength, &out.MinLength
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.MaxItems != nil {
|
||||
in, out := &in.MaxItems, &out.MaxItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinItems != nil {
|
||||
in, out := &in.MinItems, &out.MinItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MultipleOf != nil {
|
||||
in, out := &in.MultipleOf, &out.MultipleOf
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Enum != nil {
|
||||
out.Enum = make([]JSON, len(in.Enum))
|
||||
for i := range in.Enum {
|
||||
out.Enum[i] = deepCopyJSON(in.Enum[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.MaxProperties != nil {
|
||||
in, out := &in.MaxProperties, &out.MaxProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinProperties != nil {
|
||||
in, out := &in.MinProperties, &out.MinProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Required != nil {
|
||||
in, out := &in.Required, &out.Required
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrArray)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.AllOf != nil {
|
||||
in, out := &in.AllOf, &out.AllOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.OneOf != nil {
|
||||
in, out := &in.OneOf, &out.OneOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.AnyOf != nil {
|
||||
in, out := &in.AnyOf, &out.AnyOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.Not != nil {
|
||||
in, out := &in.Not, &out.Not
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.AdditionalProperties != nil {
|
||||
in, out := &in.AdditionalProperties, &out.AdditionalProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.PatternProperties != nil {
|
||||
in, out := &in.PatternProperties, &out.PatternProperties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.Dependencies != nil {
|
||||
in, out := &in.Dependencies, &out.Dependencies
|
||||
*out = make(JSONSchemaDependencies, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.AdditionalItems != nil {
|
||||
in, out := &in.AdditionalItems, &out.AdditionalItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Definitions != nil {
|
||||
in, out := &in.Definitions, &out.Definitions
|
||||
*out = make(JSONSchemaDefinitions, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.ExternalDocs != nil {
|
||||
in, out := &in.ExternalDocs, &out.ExternalDocs
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ExternalDocumentation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func deepCopyJSON(x interface{}) interface{} {
|
||||
switch x := x.(type) {
|
||||
case map[string]interface{}:
|
||||
clone := make(map[string]interface{}, len(x))
|
||||
for k, v := range x {
|
||||
clone[k] = deepCopyJSON(v)
|
||||
}
|
||||
return clone
|
||||
case []interface{}:
|
||||
clone := make([]interface{}, len(x))
|
||||
for i := range x {
|
||||
clone[i] = deepCopyJSON(x[i])
|
||||
}
|
||||
return clone
|
||||
default:
|
||||
return x
|
||||
}
|
||||
}
|
@ -17,6 +17,7 @@ limitations under the License.
|
||||
package fuzzer
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/google/gofuzz"
|
||||
@ -42,5 +43,65 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||
obj.Names.ListKind = obj.Names.Kind + "List"
|
||||
}
|
||||
},
|
||||
func(obj *apiextensions.JSONSchemaProps, c fuzz.Continue) {
|
||||
// we cannot use c.FuzzNoCustom because of the interface{} fields. So let's loop with reflection.
|
||||
vobj := reflect.ValueOf(obj).Elem()
|
||||
tobj := reflect.TypeOf(obj).Elem()
|
||||
for i := 0; i < tobj.NumField(); i++ {
|
||||
field := tobj.Field(i)
|
||||
switch field.Name {
|
||||
case "Default", "Enum", "Example":
|
||||
continue
|
||||
default:
|
||||
isValue := true
|
||||
switch field.Type.Kind() {
|
||||
case reflect.Interface, reflect.Map, reflect.Slice, reflect.Ptr:
|
||||
isValue = false
|
||||
}
|
||||
if isValue || c.Intn(5) == 0 {
|
||||
c.Fuzz(vobj.Field(i).Addr().Interface())
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.RandBool() {
|
||||
validJSON := apiextensions.JSON(`{"some": {"json": "test"}, "string": 42}`)
|
||||
obj.Default = &validJSON
|
||||
}
|
||||
if c.RandBool() {
|
||||
obj.Enum = []apiextensions.JSON{c.Float64(), c.RandString(), c.RandBool()}
|
||||
}
|
||||
if c.RandBool() {
|
||||
validJSON := apiextensions.JSON(`"foobarbaz"`)
|
||||
obj.Example = &validJSON
|
||||
}
|
||||
},
|
||||
func(obj *apiextensions.JSONSchemaPropsOrBool, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
obj.Schema = &apiextensions.JSONSchemaProps{}
|
||||
c.Fuzz(obj.Schema)
|
||||
} else {
|
||||
obj.Allows = c.RandBool()
|
||||
}
|
||||
},
|
||||
func(obj *apiextensions.JSONSchemaPropsOrArray, c fuzz.Continue) {
|
||||
// disallow both Schema and JSONSchemas to be nil.
|
||||
if c.RandBool() {
|
||||
obj.Schema = &apiextensions.JSONSchemaProps{}
|
||||
c.Fuzz(obj.Schema)
|
||||
} else {
|
||||
obj.JSONSchemas = make([]apiextensions.JSONSchemaProps, c.Intn(3)+1)
|
||||
for i := range obj.JSONSchemas {
|
||||
c.Fuzz(&obj.JSONSchemas[i])
|
||||
}
|
||||
}
|
||||
},
|
||||
func(obj *apiextensions.JSONSchemaPropsOrStringArray, c fuzz.Continue) {
|
||||
if c.RandBool() {
|
||||
obj.Schema = &apiextensions.JSONSchemaProps{}
|
||||
c.Fuzz(obj.Schema)
|
||||
} else {
|
||||
c.Fuzz(&obj.Property)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,10 @@ type CustomResourceDefinitionSpec struct {
|
||||
Version string
|
||||
// Names are the names used to describe this custom resource
|
||||
Names CustomResourceDefinitionNames
|
||||
|
||||
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
||||
Scope ResourceScope
|
||||
// Validation describes the validation methods for CustomResources
|
||||
Validation *CustomResourceValidation
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
||||
@ -139,3 +140,9 @@ type CustomResourceDefinitionList struct {
|
||||
// Items individual CustomResourceDefinitions
|
||||
Items []CustomResourceDefinition
|
||||
}
|
||||
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources.
|
||||
type CustomResourceValidation struct {
|
||||
// OpenAPIV3Schema is the OpenAPI v3 schema to be validated against.
|
||||
OpenAPIV3Schema *JSONSchemaProps
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
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 apiextensions
|
||||
|
||||
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
|
||||
type JSONSchemaProps struct {
|
||||
ID string
|
||||
Schema JSONSchemaURL
|
||||
Ref *string
|
||||
Description string
|
||||
Type string
|
||||
Format string
|
||||
Title string
|
||||
Default *JSON
|
||||
Maximum *float64
|
||||
ExclusiveMaximum bool
|
||||
Minimum *float64
|
||||
ExclusiveMinimum bool
|
||||
MaxLength *int64
|
||||
MinLength *int64
|
||||
Pattern string
|
||||
MaxItems *int64
|
||||
MinItems *int64
|
||||
UniqueItems bool
|
||||
MultipleOf *float64
|
||||
Enum []JSON
|
||||
MaxProperties *int64
|
||||
MinProperties *int64
|
||||
Required []string
|
||||
Items *JSONSchemaPropsOrArray
|
||||
AllOf []JSONSchemaProps
|
||||
OneOf []JSONSchemaProps
|
||||
AnyOf []JSONSchemaProps
|
||||
Not *JSONSchemaProps
|
||||
Properties map[string]JSONSchemaProps
|
||||
AdditionalProperties *JSONSchemaPropsOrBool
|
||||
PatternProperties map[string]JSONSchemaProps
|
||||
Dependencies JSONSchemaDependencies
|
||||
AdditionalItems *JSONSchemaPropsOrBool
|
||||
Definitions JSONSchemaDefinitions
|
||||
ExternalDocs *ExternalDocumentation
|
||||
Example *JSON
|
||||
}
|
||||
|
||||
// JSON represents any valid JSON value.
|
||||
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
|
||||
type JSON interface{}
|
||||
|
||||
// JSONSchemaURL represents a schema url.
|
||||
type JSONSchemaURL string
|
||||
|
||||
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
|
||||
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
|
||||
type JSONSchemaPropsOrArray struct {
|
||||
Schema *JSONSchemaProps
|
||||
JSONSchemas []JSONSchemaProps
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
|
||||
// Defaults to true for the boolean property.
|
||||
type JSONSchemaPropsOrBool struct {
|
||||
Allows bool
|
||||
Schema *JSONSchemaProps
|
||||
}
|
||||
|
||||
// JSONSchemaDependencies represent a dependencies property.
|
||||
type JSONSchemaDependencies map[string]JSONSchemaPropsOrStringArray
|
||||
|
||||
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
|
||||
type JSONSchemaPropsOrStringArray struct {
|
||||
Schema *JSONSchemaProps
|
||||
Property []string
|
||||
}
|
||||
|
||||
// JSONSchemaDefinitions contains the models explicitly defined in this spec.
|
||||
type JSONSchemaDefinitions map[string]JSONSchemaProps
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for extended documentation.
|
||||
type ExternalDocumentation struct {
|
||||
Description string
|
||||
URL string
|
||||
}
|
@ -3,27 +3,34 @@ package(default_visibility = ["//visibility:public"])
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"conversion.go",
|
||||
"deepcopy.go",
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"generated.pb.go",
|
||||
"marshal.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"types_jsonschema.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
||||
"//vendor/github.com/gogo/protobuf/sortkeys:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
@ -45,3 +52,16 @@ filegroup(
|
||||
srcs = ["generated.proto"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"conversion_test.go",
|
||||
"marshal_test.go",
|
||||
],
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
)
|
||||
|
||||
func addConversionFuncs(scheme *runtime.Scheme) error {
|
||||
// Add non-generated conversion functions
|
||||
err := scheme.AddConversionFuncs(
|
||||
Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps,
|
||||
Convert_apiextensions_JSON_To_v1beta1_JSON,
|
||||
Convert_v1beta1_JSON_To_apiextensions_JSON,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in *apiextensions.JSONSchemaProps, out *JSONSchemaProps, s conversion.Scope) error {
|
||||
if err := autoConvert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in, out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Default != nil && *(in.Default) == nil {
|
||||
out.Default = nil
|
||||
}
|
||||
if in.Example != nil && *(in.Example) == nil {
|
||||
out.Example = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_apiextensions_JSON_To_v1beta1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error {
|
||||
raw, err := json.Marshal(*in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.Raw = raw
|
||||
return nil
|
||||
}
|
||||
|
||||
func Convert_v1beta1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error {
|
||||
if in != nil {
|
||||
var i interface{}
|
||||
if err := json.Unmarshal(in.Raw, &i); err != nil {
|
||||
return err
|
||||
}
|
||||
*out = i
|
||||
} else {
|
||||
out = nil
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
)
|
||||
|
||||
func TestJSONConversion(t *testing.T) {
|
||||
nilJSON := apiextensions.JSON(nil)
|
||||
nullJSON := apiextensions.JSON("null")
|
||||
stringJSON := apiextensions.JSON("foo")
|
||||
boolJSON := apiextensions.JSON(true)
|
||||
sliceJSON := apiextensions.JSON([]string{"foo", "bar", "baz"})
|
||||
|
||||
testCases := map[string]struct {
|
||||
input *apiextensions.JSONSchemaProps
|
||||
expected *JSONSchemaProps
|
||||
}{
|
||||
"nil": {
|
||||
input: &apiextensions.JSONSchemaProps{
|
||||
Default: nil,
|
||||
},
|
||||
expected: &JSONSchemaProps{},
|
||||
},
|
||||
"aliased nil": {
|
||||
input: &apiextensions.JSONSchemaProps{
|
||||
Default: &nilJSON,
|
||||
},
|
||||
expected: &JSONSchemaProps{},
|
||||
},
|
||||
"null": {
|
||||
input: &apiextensions.JSONSchemaProps{
|
||||
Default: &nullJSON,
|
||||
},
|
||||
expected: &JSONSchemaProps{
|
||||
Default: &JSON{
|
||||
Raw: []byte(`"null"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
"string": {
|
||||
input: &apiextensions.JSONSchemaProps{
|
||||
Default: &stringJSON,
|
||||
},
|
||||
expected: &JSONSchemaProps{
|
||||
Default: &JSON{
|
||||
Raw: []byte(`"foo"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
"bool": {
|
||||
input: &apiextensions.JSONSchemaProps{
|
||||
Default: &boolJSON,
|
||||
},
|
||||
expected: &JSONSchemaProps{
|
||||
Default: &JSON{
|
||||
Raw: []byte(`true`),
|
||||
},
|
||||
},
|
||||
},
|
||||
"slice": {
|
||||
input: &apiextensions.JSONSchemaProps{
|
||||
Default: &sliceJSON,
|
||||
},
|
||||
expected: &JSONSchemaProps{
|
||||
Default: &JSON{
|
||||
Raw: []byte(`["foo","bar","baz"]`),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
scheme := runtime.NewScheme()
|
||||
|
||||
// add internal and external types
|
||||
if err := apiextensions.AddToScheme(scheme); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := AddToScheme(scheme); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for k, tc := range testCases {
|
||||
external := &JSONSchemaProps{}
|
||||
if err := scheme.Convert(tc.input, external, nil); err != nil {
|
||||
t.Errorf("%s: unexpected error: %v", k, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(external, tc.expected) {
|
||||
t.Errorf("%s: expected\n\t%#v, got \n\t%#v", k, tc.expected, external)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,257 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
// TODO: Update this after a tag is created for interface fields in DeepCopy
|
||||
func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaProps)
|
||||
*out = *in
|
||||
|
||||
if in.Ref != nil {
|
||||
in, out := &in.Ref, &out.Ref
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Maximum != nil {
|
||||
in, out := &in.Maximum, &out.Maximum
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Minimum != nil {
|
||||
in, out := &in.Minimum, &out.Minimum
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MaxLength != nil {
|
||||
in, out := &in.MaxLength, &out.MaxLength
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinLength != nil {
|
||||
in, out := &in.MinLength, &out.MinLength
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.MaxItems != nil {
|
||||
in, out := &in.MaxItems, &out.MaxItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinItems != nil {
|
||||
in, out := &in.MinItems, &out.MinItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MultipleOf != nil {
|
||||
in, out := &in.MultipleOf, &out.MultipleOf
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(float64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MaxProperties != nil {
|
||||
in, out := &in.MaxProperties, &out.MaxProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.MinProperties != nil {
|
||||
in, out := &in.MinProperties, &out.MinProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(int64)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
|
||||
if in.Required != nil {
|
||||
in, out := &in.Required, &out.Required
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrArray)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.AllOf != nil {
|
||||
in, out := &in.AllOf, &out.AllOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.OneOf != nil {
|
||||
in, out := &in.OneOf, &out.OneOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.AnyOf != nil {
|
||||
in, out := &in.AnyOf, &out.AnyOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
|
||||
if in.Not != nil {
|
||||
in, out := &in.Not, &out.Not
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.AdditionalProperties != nil {
|
||||
in, out := &in.AdditionalProperties, &out.AdditionalProperties
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.PatternProperties != nil {
|
||||
in, out := &in.PatternProperties, &out.PatternProperties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.Dependencies != nil {
|
||||
in, out := &in.Dependencies, &out.Dependencies
|
||||
*out = make(JSONSchemaDependencies, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.AdditionalItems != nil {
|
||||
in, out := &in.AdditionalItems, &out.AdditionalItems
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
if in.Definitions != nil {
|
||||
in, out := &in.Definitions, &out.Definitions
|
||||
*out = make(JSONSchemaDefinitions, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = *val.DeepCopy()
|
||||
}
|
||||
}
|
||||
|
||||
if in.ExternalDocs != nil {
|
||||
in, out := &in.ExternalDocs, &out.ExternalDocs
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ExternalDocumentation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func deepCopyJSON(x interface{}) interface{} {
|
||||
switch x := x.(type) {
|
||||
case map[string]interface{}:
|
||||
clone := make(map[string]interface{}, len(x))
|
||||
for k, v := range x {
|
||||
clone[k] = deepCopyJSON(v)
|
||||
}
|
||||
return clone
|
||||
case []interface{}:
|
||||
clone := make([]interface{}, len(x))
|
||||
for i := range x {
|
||||
clone[i] = deepCopyJSON(x[i])
|
||||
}
|
||||
return clone
|
||||
default:
|
||||
return x
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -103,6 +103,11 @@ message CustomResourceDefinitionSpec {
|
||||
|
||||
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
||||
optional string scope = 4;
|
||||
|
||||
// Validation describes the validation methods for CustomResources
|
||||
// This field is alpha-level and should only be sent to servers that enable the CustomResourceValidation feature.
|
||||
// +optional
|
||||
optional CustomResourceValidation validation = 5;
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
|
||||
@ -115,3 +120,120 @@ message CustomResourceDefinitionStatus {
|
||||
optional CustomResourceDefinitionNames acceptedNames = 2;
|
||||
}
|
||||
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources.
|
||||
message CustomResourceValidation {
|
||||
// OpenAPIV3Schema is the OpenAPI v3 schema to be validated against.
|
||||
optional JSONSchemaProps openAPIV3Schema = 1;
|
||||
}
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for extended documentation.
|
||||
message ExternalDocumentation {
|
||||
optional string description = 1;
|
||||
|
||||
optional string url = 2;
|
||||
}
|
||||
|
||||
// JSON represents any valid JSON value.
|
||||
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
|
||||
message JSON {
|
||||
optional bytes raw = 1;
|
||||
}
|
||||
|
||||
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
|
||||
message JSONSchemaProps {
|
||||
optional string id = 1;
|
||||
|
||||
optional string schema = 2;
|
||||
|
||||
optional string ref = 3;
|
||||
|
||||
optional string description = 4;
|
||||
|
||||
optional string type = 5;
|
||||
|
||||
optional string format = 6;
|
||||
|
||||
optional string title = 7;
|
||||
|
||||
optional JSON default = 8;
|
||||
|
||||
optional double maximum = 9;
|
||||
|
||||
optional bool exclusiveMaximum = 10;
|
||||
|
||||
optional double minimum = 11;
|
||||
|
||||
optional bool exclusiveMinimum = 12;
|
||||
|
||||
optional int64 maxLength = 13;
|
||||
|
||||
optional int64 minLength = 14;
|
||||
|
||||
optional string pattern = 15;
|
||||
|
||||
optional int64 maxItems = 16;
|
||||
|
||||
optional int64 minItems = 17;
|
||||
|
||||
optional bool uniqueItems = 18;
|
||||
|
||||
optional double multipleOf = 19;
|
||||
|
||||
repeated JSON enum = 20;
|
||||
|
||||
optional int64 maxProperties = 21;
|
||||
|
||||
optional int64 minProperties = 22;
|
||||
|
||||
repeated string required = 23;
|
||||
|
||||
optional JSONSchemaPropsOrArray items = 24;
|
||||
|
||||
repeated JSONSchemaProps allOf = 25;
|
||||
|
||||
repeated JSONSchemaProps oneOf = 26;
|
||||
|
||||
repeated JSONSchemaProps anyOf = 27;
|
||||
|
||||
optional JSONSchemaProps not = 28;
|
||||
|
||||
map<string, JSONSchemaProps> properties = 29;
|
||||
|
||||
optional JSONSchemaPropsOrBool additionalProperties = 30;
|
||||
|
||||
map<string, JSONSchemaProps> patternProperties = 31;
|
||||
|
||||
map<string, JSONSchemaPropsOrStringArray> dependencies = 32;
|
||||
|
||||
optional JSONSchemaPropsOrBool additionalItems = 33;
|
||||
|
||||
map<string, JSONSchemaProps> definitions = 34;
|
||||
|
||||
optional ExternalDocumentation externalDocs = 35;
|
||||
|
||||
optional JSON example = 36;
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
|
||||
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
|
||||
message JSONSchemaPropsOrArray {
|
||||
optional JSONSchemaProps schema = 1;
|
||||
|
||||
repeated JSONSchemaProps jSONSchemas = 2;
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
|
||||
// Defaults to true for the boolean property.
|
||||
message JSONSchemaPropsOrBool {
|
||||
optional bool allows = 1;
|
||||
|
||||
optional JSONSchemaProps schema = 2;
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
|
||||
message JSONSchemaPropsOrStringArray {
|
||||
optional JSONSchemaProps schema = 1;
|
||||
|
||||
repeated string property = 2;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,134 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
)
|
||||
|
||||
var jsTrue = []byte("true")
|
||||
var jsFalse = []byte("false")
|
||||
|
||||
func (s JSONSchemaPropsOrBool) MarshalJSON() ([]byte, error) {
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
if s.Schema == nil && !s.Allows {
|
||||
return jsFalse, nil
|
||||
}
|
||||
return jsTrue, nil
|
||||
}
|
||||
|
||||
func (s *JSONSchemaPropsOrBool) UnmarshalJSON(data []byte) error {
|
||||
var nw JSONSchemaPropsOrBool
|
||||
switch {
|
||||
case len(data) == 0:
|
||||
case data[0] == '{':
|
||||
var sch JSONSchemaProps
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
case len(data) == 4 && string(data) == "true":
|
||||
nw.Allows = true
|
||||
case len(data) == 5 && string(data) == "false":
|
||||
nw.Allows = false
|
||||
default:
|
||||
return errors.New("boolean or JSON schema expected")
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSONSchemaPropsOrStringArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s.Property) > 0 {
|
||||
return json.Marshal(s.Property)
|
||||
}
|
||||
if s.Schema != nil {
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
func (s *JSONSchemaPropsOrStringArray) UnmarshalJSON(data []byte) error {
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
var nw JSONSchemaPropsOrStringArray
|
||||
if first == '{' {
|
||||
var sch JSONSchemaProps
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.Property); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSONSchemaPropsOrArray) MarshalJSON() ([]byte, error) {
|
||||
if len(s.JSONSchemas) > 0 {
|
||||
return json.Marshal(s.JSONSchemas)
|
||||
}
|
||||
return json.Marshal(s.Schema)
|
||||
}
|
||||
|
||||
func (s *JSONSchemaPropsOrArray) UnmarshalJSON(data []byte) error {
|
||||
var nw JSONSchemaPropsOrArray
|
||||
var first byte
|
||||
if len(data) > 1 {
|
||||
first = data[0]
|
||||
}
|
||||
if first == '{' {
|
||||
var sch JSONSchemaProps
|
||||
if err := json.Unmarshal(data, &sch); err != nil {
|
||||
return err
|
||||
}
|
||||
nw.Schema = &sch
|
||||
}
|
||||
if first == '[' {
|
||||
if err := json.Unmarshal(data, &nw.JSONSchemas); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
*s = nw
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s JSON) MarshalJSON() ([]byte, error) {
|
||||
if len(s.Raw) > 0 {
|
||||
return s.Raw, nil
|
||||
}
|
||||
return []byte("null"), nil
|
||||
|
||||
}
|
||||
|
||||
func (s *JSON) UnmarshalJSON(data []byte) error {
|
||||
if len(data) > 0 && string(data) != "null" {
|
||||
s.Raw = data
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type JSONSchemaPropsOrBoolHolder struct {
|
||||
JSPoB JSONSchemaPropsOrBool `json:"val1"`
|
||||
JSPoBOmitEmpty *JSONSchemaPropsOrBool `json:"val2,omitempty"`
|
||||
}
|
||||
|
||||
func TestJSONSchemaPropsOrBoolUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result JSONSchemaPropsOrBoolHolder
|
||||
}{
|
||||
{`{}`, JSONSchemaPropsOrBoolHolder{}},
|
||||
|
||||
{`{"val1": {}}`, JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{}}}},
|
||||
{`{"val1": {"type":"string"}}`, JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{Type: "string"}}}},
|
||||
{`{"val1": false}`, JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{}}},
|
||||
{`{"val1": true}`, JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{Allows: true}}},
|
||||
|
||||
{`{"val2": {}}`, JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{}}}},
|
||||
{`{"val2": {"type":"string"}}`, JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{Type: "string"}}}},
|
||||
{`{"val2": false}`, JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{}}},
|
||||
{`{"val2": true}`, JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{Allows: true}}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result JSONSchemaPropsOrBoolHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.result) {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStringArrayOrStringMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input JSONSchemaPropsOrBoolHolder
|
||||
result string
|
||||
}{
|
||||
{JSONSchemaPropsOrBoolHolder{}, `{"val1":false}`},
|
||||
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{}}}, `{"val1":{}}`},
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{Type: "string"}}}, `{"val1":{"type":"string"}}`},
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{}}, `{"val1":false}`},
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoB: JSONSchemaPropsOrBool{Allows: true}}, `{"val1":true}`},
|
||||
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{}}}, `{"val1":false,"val2":{}}`},
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{Schema: &JSONSchemaProps{Type: "string"}}}, `{"val1":false,"val2":{"type":"string"}}`},
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{}}, `{"val1":false,"val2":false}`},
|
||||
{JSONSchemaPropsOrBoolHolder{JSPoBOmitEmpty: &JSONSchemaPropsOrBool{Allows: true}}, `{"val1":false,"val2":true}`},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
result, err := json.Marshal(&c.input)
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error marshaling input '%v': %v", c.input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("Failed to marshal input '%v': expected: %q, got %q", c.input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type JSONSchemaPropsOrArrayHolder struct {
|
||||
JSPoA JSONSchemaPropsOrArray `json:"val1"`
|
||||
JSPoAOmitEmpty *JSONSchemaPropsOrArray `json:"val2,omitempty"`
|
||||
}
|
||||
|
||||
func TestJSONSchemaPropsOrArrayUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result JSONSchemaPropsOrArrayHolder
|
||||
}{
|
||||
{`{}`, JSONSchemaPropsOrArrayHolder{}},
|
||||
|
||||
{`{"val1": {}}`, JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{}}}},
|
||||
{`{"val1": {"type":"string"}}`, JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{Type: "string"}}}},
|
||||
{`{"val1": [{}]}`, JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}}}}},
|
||||
{`{"val1": [{},{"type":"string"}]}`, JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}, {Type: "string"}}}}},
|
||||
|
||||
{`{"val2": {}}`, JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{}}}},
|
||||
{`{"val2": {"type":"string"}}`, JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{Type: "string"}}}},
|
||||
{`{"val2": [{}]}`, JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}}}}},
|
||||
{`{"val2": [{},{"type":"string"}]}`, JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}, {Type: "string"}}}}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
var result JSONSchemaPropsOrArrayHolder
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("Failed to unmarshal input '%v': %v", c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.result) {
|
||||
t.Errorf("Failed to unmarshal input '%v': expected %+v, got %+v", c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONSchemaPropsOrArrayMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input JSONSchemaPropsOrArrayHolder
|
||||
result string
|
||||
}{
|
||||
{JSONSchemaPropsOrArrayHolder{}, `{"val1":null}`},
|
||||
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{}}}, `{"val1":{}}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{Type: "string"}}}, `{"val1":{"type":"string"}}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}}}}, `{"val1":[{}]}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoA: JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}, {Type: "string"}}}}, `{"val1":[{},{"type":"string"}]}`},
|
||||
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{}}, `{"val1":null,"val2":null}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{}}}, `{"val1":null,"val2":{}}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{Schema: &JSONSchemaProps{Type: "string"}}}, `{"val1":null,"val2":{"type":"string"}}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}}}}, `{"val1":null,"val2":[{}]}`},
|
||||
{JSONSchemaPropsOrArrayHolder{JSPoAOmitEmpty: &JSONSchemaPropsOrArray{JSONSchemas: []JSONSchemaProps{{}, {Type: "string"}}}}, `{"val1":null,"val2":[{},{"type":"string"}]}`},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
result, err := json.Marshal(&c.input)
|
||||
if err != nil {
|
||||
t.Errorf("%d: Unexpected error marshaling input '%v': %v", i, c.input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("%d: Failed to marshal input '%v': expected: %q, got %q", i, c.input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
@ -38,7 +38,7 @@ func Resource(resource string) schema.GroupResource {
|
||||
}
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
@ -52,3 +52,10 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addDefaultingFuncs, addConversionFuncs)
|
||||
}
|
||||
|
@ -26,9 +26,12 @@ type CustomResourceDefinitionSpec struct {
|
||||
Version string `json:"version" protobuf:"bytes,2,opt,name=version"`
|
||||
// Names are the names used to describe this custom resource
|
||||
Names CustomResourceDefinitionNames `json:"names" protobuf:"bytes,3,opt,name=names"`
|
||||
|
||||
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
||||
Scope ResourceScope `json:"scope" protobuf:"bytes,4,opt,name=scope,casttype=ResourceScope"`
|
||||
// Validation describes the validation methods for CustomResources
|
||||
// This field is alpha-level and should only be sent to servers that enable the CustomResourceValidation feature.
|
||||
// +optional
|
||||
Validation *CustomResourceValidation `json:"validation,omitempty" protobuf:"bytes,5,opt,name=validation"`
|
||||
}
|
||||
|
||||
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
||||
@ -139,3 +142,9 @@ type CustomResourceDefinitionList struct {
|
||||
// Items individual CustomResourceDefinitions
|
||||
Items []CustomResourceDefinition `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources.
|
||||
type CustomResourceValidation struct {
|
||||
// OpenAPIV3Schema is the OpenAPI v3 schema to be validated against.
|
||||
OpenAPIV3Schema *JSONSchemaProps `json:"openAPIV3Schema,omitempty" protobuf:"bytes,1,opt,name=openAPIV3Schema"`
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
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 v1beta1
|
||||
|
||||
// JSONSchemaProps is a JSON-Schema following Specification Draft 4 (http://json-schema.org/).
|
||||
type JSONSchemaProps struct {
|
||||
ID string `json:"id,omitempty" protobuf:"bytes,1,opt,name=id"`
|
||||
Schema JSONSchemaURL `json:"$schema,omitempty" protobuf:"bytes,2,opt,name=schema"`
|
||||
Ref *string `json:"$ref,omitempty" protobuf:"bytes,3,opt,name=ref"`
|
||||
Description string `json:"description,omitempty" protobuf:"bytes,4,opt,name=description"`
|
||||
Type string `json:"type,omitempty" protobuf:"bytes,5,opt,name=type"`
|
||||
Format string `json:"format,omitempty" protobuf:"bytes,6,opt,name=format"`
|
||||
Title string `json:"title,omitempty" protobuf:"bytes,7,opt,name=title"`
|
||||
Default *JSON `json:"default,omitempty" protobuf:"bytes,8,opt,name=default"`
|
||||
Maximum *float64 `json:"maximum,omitempty" protobuf:"bytes,9,opt,name=maximum"`
|
||||
ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty" protobuf:"bytes,10,opt,name=exclusiveMaximum"`
|
||||
Minimum *float64 `json:"minimum,omitempty" protobuf:"bytes,11,opt,name=minimum"`
|
||||
ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty" protobuf:"bytes,12,opt,name=exclusiveMinimum"`
|
||||
MaxLength *int64 `json:"maxLength,omitempty" protobuf:"bytes,13,opt,name=maxLength"`
|
||||
MinLength *int64 `json:"minLength,omitempty" protobuf:"bytes,14,opt,name=minLength"`
|
||||
Pattern string `json:"pattern,omitempty" protobuf:"bytes,15,opt,name=pattern"`
|
||||
MaxItems *int64 `json:"maxItems,omitempty" protobuf:"bytes,16,opt,name=maxItems"`
|
||||
MinItems *int64 `json:"minItems,omitempty" protobuf:"bytes,17,opt,name=minItems"`
|
||||
UniqueItems bool `json:"uniqueItems,omitempty" protobuf:"bytes,18,opt,name=uniqueItems"`
|
||||
MultipleOf *float64 `json:"multipleOf,omitempty" protobuf:"bytes,19,opt,name=multipleOf"`
|
||||
Enum []JSON `json:"enum,omitempty" protobuf:"bytes,20,rep,name=enum"`
|
||||
MaxProperties *int64 `json:"maxProperties,omitempty" protobuf:"bytes,21,opt,name=maxProperties"`
|
||||
MinProperties *int64 `json:"minProperties,omitempty" protobuf:"bytes,22,opt,name=minProperties"`
|
||||
Required []string `json:"required,omitempty" protobuf:"bytes,23,rep,name=required"`
|
||||
Items *JSONSchemaPropsOrArray `json:"items,omitempty" protobuf:"bytes,24,opt,name=items"`
|
||||
AllOf []JSONSchemaProps `json:"allOf,omitempty" protobuf:"bytes,25,rep,name=allOf"`
|
||||
OneOf []JSONSchemaProps `json:"oneOf,omitempty" protobuf:"bytes,26,rep,name=oneOf"`
|
||||
AnyOf []JSONSchemaProps `json:"anyOf,omitempty" protobuf:"bytes,27,rep,name=anyOf"`
|
||||
Not *JSONSchemaProps `json:"not,omitempty" protobuf:"bytes,28,opt,name=not"`
|
||||
Properties map[string]JSONSchemaProps `json:"properties,omitempty" protobuf:"bytes,29,rep,name=properties"`
|
||||
AdditionalProperties *JSONSchemaPropsOrBool `json:"additionalProperties,omitempty" protobuf:"bytes,30,opt,name=additionalProperties"`
|
||||
PatternProperties map[string]JSONSchemaProps `json:"patternProperties,omitempty" protobuf:"bytes,31,rep,name=patternProperties"`
|
||||
Dependencies JSONSchemaDependencies `json:"dependencies,omitempty" protobuf:"bytes,32,opt,name=dependencies"`
|
||||
AdditionalItems *JSONSchemaPropsOrBool `json:"additionalItems,omitempty" protobuf:"bytes,33,opt,name=additionalItems"`
|
||||
Definitions JSONSchemaDefinitions `json:"definitions,omitempty" protobuf:"bytes,34,opt,name=definitions"`
|
||||
ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty" protobuf:"bytes,35,opt,name=externalDocs"`
|
||||
Example *JSON `json:"example,omitempty" protobuf:"bytes,36,opt,name=example"`
|
||||
}
|
||||
|
||||
// JSON represents any valid JSON value.
|
||||
// These types are supported: bool, int64, float64, string, []interface{}, map[string]interface{} and nil.
|
||||
type JSON struct {
|
||||
Raw []byte `protobuf:"bytes,1,opt,name=raw"`
|
||||
}
|
||||
|
||||
// JSONSchemaURL represents a schema url.
|
||||
type JSONSchemaURL string
|
||||
|
||||
// JSONSchemaPropsOrArray represents a value that can either be a JSONSchemaProps
|
||||
// or an array of JSONSchemaProps. Mainly here for serialization purposes.
|
||||
type JSONSchemaPropsOrArray struct {
|
||||
Schema *JSONSchemaProps `protobuf:"bytes,1,opt,name=schema"`
|
||||
JSONSchemas []JSONSchemaProps `protobuf:"bytes,2,rep,name=jSONSchemas"`
|
||||
}
|
||||
|
||||
// JSONSchemaPropsOrBool represents JSONSchemaProps or a boolean value.
|
||||
// Defaults to true for the boolean property.
|
||||
type JSONSchemaPropsOrBool struct {
|
||||
Allows bool `protobuf:"varint,1,opt,name=allows"`
|
||||
Schema *JSONSchemaProps `protobuf:"bytes,2,opt,name=schema"`
|
||||
}
|
||||
|
||||
// JSONSchemaDependencies represent a dependencies property.
|
||||
type JSONSchemaDependencies map[string]JSONSchemaPropsOrStringArray
|
||||
|
||||
// JSONSchemaPropsOrStringArray represents a JSONSchemaProps or a string array.
|
||||
type JSONSchemaPropsOrStringArray struct {
|
||||
Schema *JSONSchemaProps `protobuf:"bytes,1,opt,name=schema"`
|
||||
Property []string `protobuf:"bytes,2,rep,name=property"`
|
||||
}
|
||||
|
||||
// JSONSchemaDefinitions contains the models explicitly defined in this spec.
|
||||
type JSONSchemaDefinitions map[string]JSONSchemaProps
|
||||
|
||||
// ExternalDocumentation allows referencing an external resource for extended documentation.
|
||||
type ExternalDocumentation struct {
|
||||
Description string `json:"description,omitempty" protobuf:"bytes,1,opt,name=description"`
|
||||
URL string `json:"url,omitempty" protobuf:"bytes,2,opt,name=url"`
|
||||
}
|
@ -47,6 +47,20 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
Convert_apiextensions_CustomResourceDefinitionSpec_To_v1beta1_CustomResourceDefinitionSpec,
|
||||
Convert_v1beta1_CustomResourceDefinitionStatus_To_apiextensions_CustomResourceDefinitionStatus,
|
||||
Convert_apiextensions_CustomResourceDefinitionStatus_To_v1beta1_CustomResourceDefinitionStatus,
|
||||
Convert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation,
|
||||
Convert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation,
|
||||
Convert_v1beta1_ExternalDocumentation_To_apiextensions_ExternalDocumentation,
|
||||
Convert_apiextensions_ExternalDocumentation_To_v1beta1_ExternalDocumentation,
|
||||
Convert_v1beta1_JSON_To_apiextensions_JSON,
|
||||
Convert_apiextensions_JSON_To_v1beta1_JSON,
|
||||
Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps,
|
||||
Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps,
|
||||
Convert_v1beta1_JSONSchemaPropsOrArray_To_apiextensions_JSONSchemaPropsOrArray,
|
||||
Convert_apiextensions_JSONSchemaPropsOrArray_To_v1beta1_JSONSchemaPropsOrArray,
|
||||
Convert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool,
|
||||
Convert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool,
|
||||
Convert_v1beta1_JSONSchemaPropsOrStringArray_To_apiextensions_JSONSchemaPropsOrStringArray,
|
||||
Convert_apiextensions_JSONSchemaPropsOrStringArray_To_v1beta1_JSONSchemaPropsOrStringArray,
|
||||
)
|
||||
}
|
||||
|
||||
@ -112,7 +126,17 @@ func Convert_apiextensions_CustomResourceDefinitionCondition_To_v1beta1_CustomRe
|
||||
|
||||
func autoConvert_v1beta1_CustomResourceDefinitionList_To_apiextensions_CustomResourceDefinitionList(in *CustomResourceDefinitionList, out *apiextensions.CustomResourceDefinitionList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]apiextensions.CustomResourceDefinition)(unsafe.Pointer(&in.Items))
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]apiextensions.CustomResourceDefinition, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1beta1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -123,7 +147,17 @@ func Convert_v1beta1_CustomResourceDefinitionList_To_apiextensions_CustomResourc
|
||||
|
||||
func autoConvert_apiextensions_CustomResourceDefinitionList_To_v1beta1_CustomResourceDefinitionList(in *apiextensions.CustomResourceDefinitionList, out *CustomResourceDefinitionList, s conversion.Scope) error {
|
||||
out.ListMeta = in.ListMeta
|
||||
out.Items = *(*[]CustomResourceDefinition)(unsafe.Pointer(&in.Items))
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]CustomResourceDefinition, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apiextensions_CustomResourceDefinition_To_v1beta1_CustomResourceDefinition(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -167,6 +201,15 @@ func autoConvert_v1beta1_CustomResourceDefinitionSpec_To_apiextensions_CustomRes
|
||||
return err
|
||||
}
|
||||
out.Scope = apiextensions.ResourceScope(in.Scope)
|
||||
if in.Validation != nil {
|
||||
in, out := &in.Validation, &out.Validation
|
||||
*out = new(apiextensions.CustomResourceValidation)
|
||||
if err := Convert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Validation = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -182,6 +225,15 @@ func autoConvert_apiextensions_CustomResourceDefinitionSpec_To_v1beta1_CustomRes
|
||||
return err
|
||||
}
|
||||
out.Scope = ResourceScope(in.Scope)
|
||||
if in.Validation != nil {
|
||||
in, out := &in.Validation, &out.Validation
|
||||
*out = new(CustomResourceValidation)
|
||||
if err := Convert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Validation = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -215,3 +267,562 @@ func autoConvert_apiextensions_CustomResourceDefinitionStatus_To_v1beta1_CustomR
|
||||
func Convert_apiextensions_CustomResourceDefinitionStatus_To_v1beta1_CustomResourceDefinitionStatus(in *apiextensions.CustomResourceDefinitionStatus, out *CustomResourceDefinitionStatus, s conversion.Scope) error {
|
||||
return autoConvert_apiextensions_CustomResourceDefinitionStatus_To_v1beta1_CustomResourceDefinitionStatus(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(in *CustomResourceValidation, out *apiextensions.CustomResourceValidation, s conversion.Scope) error {
|
||||
if in.OpenAPIV3Schema != nil {
|
||||
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
|
||||
*out = new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.OpenAPIV3Schema = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation is an autogenerated conversion function.
|
||||
func Convert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(in *CustomResourceValidation, out *apiextensions.CustomResourceValidation, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_CustomResourceValidation_To_apiextensions_CustomResourceValidation(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation(in *apiextensions.CustomResourceValidation, out *CustomResourceValidation, s conversion.Scope) error {
|
||||
if in.OpenAPIV3Schema != nil {
|
||||
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
|
||||
*out = new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.OpenAPIV3Schema = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation is an autogenerated conversion function.
|
||||
func Convert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation(in *apiextensions.CustomResourceValidation, out *CustomResourceValidation, s conversion.Scope) error {
|
||||
return autoConvert_apiextensions_CustomResourceValidation_To_v1beta1_CustomResourceValidation(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_ExternalDocumentation_To_apiextensions_ExternalDocumentation(in *ExternalDocumentation, out *apiextensions.ExternalDocumentation, s conversion.Scope) error {
|
||||
out.Description = in.Description
|
||||
out.URL = in.URL
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_ExternalDocumentation_To_apiextensions_ExternalDocumentation is an autogenerated conversion function.
|
||||
func Convert_v1beta1_ExternalDocumentation_To_apiextensions_ExternalDocumentation(in *ExternalDocumentation, out *apiextensions.ExternalDocumentation, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_ExternalDocumentation_To_apiextensions_ExternalDocumentation(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_ExternalDocumentation_To_v1beta1_ExternalDocumentation(in *apiextensions.ExternalDocumentation, out *ExternalDocumentation, s conversion.Scope) error {
|
||||
out.Description = in.Description
|
||||
out.URL = in.URL
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiextensions_ExternalDocumentation_To_v1beta1_ExternalDocumentation is an autogenerated conversion function.
|
||||
func Convert_apiextensions_ExternalDocumentation_To_v1beta1_ExternalDocumentation(in *apiextensions.ExternalDocumentation, out *ExternalDocumentation, s conversion.Scope) error {
|
||||
return autoConvert_apiextensions_ExternalDocumentation_To_v1beta1_ExternalDocumentation(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_JSON_To_apiextensions_JSON(in *JSON, out *apiextensions.JSON, s conversion.Scope) error {
|
||||
// WARNING: in.Raw requires manual conversion: does not exist in peer-type
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_JSON_To_v1beta1_JSON(in *apiextensions.JSON, out *JSON, s conversion.Scope) error {
|
||||
// FIXME: Type apiextensions.JSON is unsupported.
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(in *JSONSchemaProps, out *apiextensions.JSONSchemaProps, s conversion.Scope) error {
|
||||
out.ID = in.ID
|
||||
out.Schema = apiextensions.JSONSchemaURL(in.Schema)
|
||||
out.Ref = (*string)(unsafe.Pointer(in.Ref))
|
||||
out.Description = in.Description
|
||||
out.Type = in.Type
|
||||
out.Format = in.Format
|
||||
out.Title = in.Title
|
||||
if in.Default != nil {
|
||||
in, out := &in.Default, &out.Default
|
||||
*out = new(apiextensions.JSON)
|
||||
if err := Convert_v1beta1_JSON_To_apiextensions_JSON(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Default = nil
|
||||
}
|
||||
out.Maximum = (*float64)(unsafe.Pointer(in.Maximum))
|
||||
out.ExclusiveMaximum = in.ExclusiveMaximum
|
||||
out.Minimum = (*float64)(unsafe.Pointer(in.Minimum))
|
||||
out.ExclusiveMinimum = in.ExclusiveMinimum
|
||||
out.MaxLength = (*int64)(unsafe.Pointer(in.MaxLength))
|
||||
out.MinLength = (*int64)(unsafe.Pointer(in.MinLength))
|
||||
out.Pattern = in.Pattern
|
||||
out.MaxItems = (*int64)(unsafe.Pointer(in.MaxItems))
|
||||
out.MinItems = (*int64)(unsafe.Pointer(in.MinItems))
|
||||
out.UniqueItems = in.UniqueItems
|
||||
out.MultipleOf = (*float64)(unsafe.Pointer(in.MultipleOf))
|
||||
if in.Enum != nil {
|
||||
in, out := &in.Enum, &out.Enum
|
||||
*out = make([]apiextensions.JSON, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1beta1_JSON_To_apiextensions_JSON(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Enum = nil
|
||||
}
|
||||
out.MaxProperties = (*int64)(unsafe.Pointer(in.MaxProperties))
|
||||
out.MinProperties = (*int64)(unsafe.Pointer(in.MinProperties))
|
||||
out.Required = *(*[]string)(unsafe.Pointer(&in.Required))
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = new(apiextensions.JSONSchemaPropsOrArray)
|
||||
if err := Convert_v1beta1_JSONSchemaPropsOrArray_To_apiextensions_JSONSchemaPropsOrArray(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
if in.AllOf != nil {
|
||||
in, out := &in.AllOf, &out.AllOf
|
||||
*out = make([]apiextensions.JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.AllOf = nil
|
||||
}
|
||||
if in.OneOf != nil {
|
||||
in, out := &in.OneOf, &out.OneOf
|
||||
*out = make([]apiextensions.JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.OneOf = nil
|
||||
}
|
||||
if in.AnyOf != nil {
|
||||
in, out := &in.AnyOf, &out.AnyOf
|
||||
*out = make([]apiextensions.JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.AnyOf = nil
|
||||
}
|
||||
if in.Not != nil {
|
||||
in, out := &in.Not, &out.Not
|
||||
*out = new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Not = nil
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = make(map[string]apiextensions.JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Properties = nil
|
||||
}
|
||||
if in.AdditionalProperties != nil {
|
||||
in, out := &in.AdditionalProperties, &out.AdditionalProperties
|
||||
*out = new(apiextensions.JSONSchemaPropsOrBool)
|
||||
if err := Convert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AdditionalProperties = nil
|
||||
}
|
||||
if in.PatternProperties != nil {
|
||||
in, out := &in.PatternProperties, &out.PatternProperties
|
||||
*out = make(map[string]apiextensions.JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.PatternProperties = nil
|
||||
}
|
||||
if in.Dependencies != nil {
|
||||
in, out := &in.Dependencies, &out.Dependencies
|
||||
*out = make(apiextensions.JSONSchemaDependencies, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(apiextensions.JSONSchemaPropsOrStringArray)
|
||||
if err := Convert_v1beta1_JSONSchemaPropsOrStringArray_To_apiextensions_JSONSchemaPropsOrStringArray(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Dependencies = nil
|
||||
}
|
||||
if in.AdditionalItems != nil {
|
||||
in, out := &in.AdditionalItems, &out.AdditionalItems
|
||||
*out = new(apiextensions.JSONSchemaPropsOrBool)
|
||||
if err := Convert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AdditionalItems = nil
|
||||
}
|
||||
if in.Definitions != nil {
|
||||
in, out := &in.Definitions, &out.Definitions
|
||||
*out = make(apiextensions.JSONSchemaDefinitions, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Definitions = nil
|
||||
}
|
||||
out.ExternalDocs = (*apiextensions.ExternalDocumentation)(unsafe.Pointer(in.ExternalDocs))
|
||||
if in.Example != nil {
|
||||
in, out := &in.Example, &out.Example
|
||||
*out = new(apiextensions.JSON)
|
||||
if err := Convert_v1beta1_JSON_To_apiextensions_JSON(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Example = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps is an autogenerated conversion function.
|
||||
func Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(in *JSONSchemaProps, out *apiextensions.JSONSchemaProps, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(in *apiextensions.JSONSchemaProps, out *JSONSchemaProps, s conversion.Scope) error {
|
||||
out.ID = in.ID
|
||||
out.Schema = JSONSchemaURL(in.Schema)
|
||||
out.Ref = (*string)(unsafe.Pointer(in.Ref))
|
||||
out.Description = in.Description
|
||||
out.Type = in.Type
|
||||
out.Format = in.Format
|
||||
out.Title = in.Title
|
||||
if in.Default != nil {
|
||||
in, out := &in.Default, &out.Default
|
||||
*out = new(JSON)
|
||||
if err := Convert_apiextensions_JSON_To_v1beta1_JSON(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Default = nil
|
||||
}
|
||||
out.Maximum = (*float64)(unsafe.Pointer(in.Maximum))
|
||||
out.ExclusiveMaximum = in.ExclusiveMaximum
|
||||
out.Minimum = (*float64)(unsafe.Pointer(in.Minimum))
|
||||
out.ExclusiveMinimum = in.ExclusiveMinimum
|
||||
out.MaxLength = (*int64)(unsafe.Pointer(in.MaxLength))
|
||||
out.MinLength = (*int64)(unsafe.Pointer(in.MinLength))
|
||||
out.Pattern = in.Pattern
|
||||
out.MaxItems = (*int64)(unsafe.Pointer(in.MaxItems))
|
||||
out.MinItems = (*int64)(unsafe.Pointer(in.MinItems))
|
||||
out.UniqueItems = in.UniqueItems
|
||||
out.MultipleOf = (*float64)(unsafe.Pointer(in.MultipleOf))
|
||||
if in.Enum != nil {
|
||||
in, out := &in.Enum, &out.Enum
|
||||
*out = make([]JSON, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apiextensions_JSON_To_v1beta1_JSON(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.Enum = nil
|
||||
}
|
||||
out.MaxProperties = (*int64)(unsafe.Pointer(in.MaxProperties))
|
||||
out.MinProperties = (*int64)(unsafe.Pointer(in.MinProperties))
|
||||
out.Required = *(*[]string)(unsafe.Pointer(&in.Required))
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = new(JSONSchemaPropsOrArray)
|
||||
if err := Convert_apiextensions_JSONSchemaPropsOrArray_To_v1beta1_JSONSchemaPropsOrArray(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Items = nil
|
||||
}
|
||||
if in.AllOf != nil {
|
||||
in, out := &in.AllOf, &out.AllOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.AllOf = nil
|
||||
}
|
||||
if in.OneOf != nil {
|
||||
in, out := &in.OneOf, &out.OneOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.OneOf = nil
|
||||
}
|
||||
if in.AnyOf != nil {
|
||||
in, out := &in.AnyOf, &out.AnyOf
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.AnyOf = nil
|
||||
}
|
||||
if in.Not != nil {
|
||||
in, out := &in.Not, &out.Not
|
||||
*out = new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Not = nil
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Properties = nil
|
||||
}
|
||||
if in.AdditionalProperties != nil {
|
||||
in, out := &in.AdditionalProperties, &out.AdditionalProperties
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
if err := Convert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AdditionalProperties = nil
|
||||
}
|
||||
if in.PatternProperties != nil {
|
||||
in, out := &in.PatternProperties, &out.PatternProperties
|
||||
*out = make(map[string]JSONSchemaProps, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.PatternProperties = nil
|
||||
}
|
||||
if in.Dependencies != nil {
|
||||
in, out := &in.Dependencies, &out.Dependencies
|
||||
*out = make(JSONSchemaDependencies, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(JSONSchemaPropsOrStringArray)
|
||||
if err := Convert_apiextensions_JSONSchemaPropsOrStringArray_To_v1beta1_JSONSchemaPropsOrStringArray(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Dependencies = nil
|
||||
}
|
||||
if in.AdditionalItems != nil {
|
||||
in, out := &in.AdditionalItems, &out.AdditionalItems
|
||||
*out = new(JSONSchemaPropsOrBool)
|
||||
if err := Convert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.AdditionalItems = nil
|
||||
}
|
||||
if in.Definitions != nil {
|
||||
in, out := &in.Definitions, &out.Definitions
|
||||
*out = make(JSONSchemaDefinitions, len(*in))
|
||||
for key, val := range *in {
|
||||
newVal := new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&val, newVal, s); err != nil {
|
||||
return err
|
||||
}
|
||||
(*out)[key] = *newVal
|
||||
}
|
||||
} else {
|
||||
out.Definitions = nil
|
||||
}
|
||||
out.ExternalDocs = (*ExternalDocumentation)(unsafe.Pointer(in.ExternalDocs))
|
||||
if in.Example != nil {
|
||||
in, out := &in.Example, &out.Example
|
||||
*out = new(JSON)
|
||||
if err := Convert_apiextensions_JSON_To_v1beta1_JSON(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Example = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_JSONSchemaPropsOrArray_To_apiextensions_JSONSchemaPropsOrArray(in *JSONSchemaPropsOrArray, out *apiextensions.JSONSchemaPropsOrArray, s conversion.Scope) error {
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Schema = nil
|
||||
}
|
||||
if in.JSONSchemas != nil {
|
||||
in, out := &in.JSONSchemas, &out.JSONSchemas
|
||||
*out = make([]apiextensions.JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.JSONSchemas = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_JSONSchemaPropsOrArray_To_apiextensions_JSONSchemaPropsOrArray is an autogenerated conversion function.
|
||||
func Convert_v1beta1_JSONSchemaPropsOrArray_To_apiextensions_JSONSchemaPropsOrArray(in *JSONSchemaPropsOrArray, out *apiextensions.JSONSchemaPropsOrArray, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_JSONSchemaPropsOrArray_To_apiextensions_JSONSchemaPropsOrArray(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_JSONSchemaPropsOrArray_To_v1beta1_JSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out *JSONSchemaPropsOrArray, s conversion.Scope) error {
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Schema = nil
|
||||
}
|
||||
if in.JSONSchemas != nil {
|
||||
in, out := &in.JSONSchemas, &out.JSONSchemas
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(&(*in)[i], &(*out)[i], s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out.JSONSchemas = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiextensions_JSONSchemaPropsOrArray_To_v1beta1_JSONSchemaPropsOrArray is an autogenerated conversion function.
|
||||
func Convert_apiextensions_JSONSchemaPropsOrArray_To_v1beta1_JSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out *JSONSchemaPropsOrArray, s conversion.Scope) error {
|
||||
return autoConvert_apiextensions_JSONSchemaPropsOrArray_To_v1beta1_JSONSchemaPropsOrArray(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool(in *JSONSchemaPropsOrBool, out *apiextensions.JSONSchemaPropsOrBool, s conversion.Scope) error {
|
||||
out.Allows = in.Allows
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Schema = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool is an autogenerated conversion function.
|
||||
func Convert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool(in *JSONSchemaPropsOrBool, out *apiextensions.JSONSchemaPropsOrBool, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_JSONSchemaPropsOrBool_To_apiextensions_JSONSchemaPropsOrBool(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool(in *apiextensions.JSONSchemaPropsOrBool, out *JSONSchemaPropsOrBool, s conversion.Scope) error {
|
||||
out.Allows = in.Allows
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Schema = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool is an autogenerated conversion function.
|
||||
func Convert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool(in *apiextensions.JSONSchemaPropsOrBool, out *JSONSchemaPropsOrBool, s conversion.Scope) error {
|
||||
return autoConvert_apiextensions_JSONSchemaPropsOrBool_To_v1beta1_JSONSchemaPropsOrBool(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1beta1_JSONSchemaPropsOrStringArray_To_apiextensions_JSONSchemaPropsOrStringArray(in *JSONSchemaPropsOrStringArray, out *apiextensions.JSONSchemaPropsOrStringArray, s conversion.Scope) error {
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(apiextensions.JSONSchemaProps)
|
||||
if err := Convert_v1beta1_JSONSchemaProps_To_apiextensions_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Schema = nil
|
||||
}
|
||||
out.Property = *(*[]string)(unsafe.Pointer(&in.Property))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1beta1_JSONSchemaPropsOrStringArray_To_apiextensions_JSONSchemaPropsOrStringArray is an autogenerated conversion function.
|
||||
func Convert_v1beta1_JSONSchemaPropsOrStringArray_To_apiextensions_JSONSchemaPropsOrStringArray(in *JSONSchemaPropsOrStringArray, out *apiextensions.JSONSchemaPropsOrStringArray, s conversion.Scope) error {
|
||||
return autoConvert_v1beta1_JSONSchemaPropsOrStringArray_To_apiextensions_JSONSchemaPropsOrStringArray(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_apiextensions_JSONSchemaPropsOrStringArray_To_v1beta1_JSONSchemaPropsOrStringArray(in *apiextensions.JSONSchemaPropsOrStringArray, out *JSONSchemaPropsOrStringArray, s conversion.Scope) error {
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
*out = new(JSONSchemaProps)
|
||||
if err := Convert_apiextensions_JSONSchemaProps_To_v1beta1_JSONSchemaProps(*in, *out, s); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
out.Schema = nil
|
||||
}
|
||||
out.Property = *(*[]string)(unsafe.Pointer(&in.Property))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_apiextensions_JSONSchemaPropsOrStringArray_To_v1beta1_JSONSchemaPropsOrStringArray is an autogenerated conversion function.
|
||||
func Convert_apiextensions_JSONSchemaPropsOrStringArray_To_v1beta1_JSONSchemaPropsOrStringArray(in *apiextensions.JSONSchemaPropsOrStringArray, out *JSONSchemaPropsOrStringArray, s conversion.Scope) error {
|
||||
return autoConvert_apiextensions_JSONSchemaPropsOrStringArray_To_v1beta1_JSONSchemaPropsOrStringArray(in, out, s)
|
||||
}
|
||||
|
@ -60,6 +60,34 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
in.(*CustomResourceDefinitionStatus).DeepCopyInto(out.(*CustomResourceDefinitionStatus))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CustomResourceDefinitionStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CustomResourceValidation).DeepCopyInto(out.(*CustomResourceValidation))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CustomResourceValidation{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ExternalDocumentation).DeepCopyInto(out.(*ExternalDocumentation))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ExternalDocumentation{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSON).DeepCopyInto(out.(*JSON))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSON{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaProps).DeepCopyInto(out.(*JSONSchemaProps))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaProps{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaPropsOrArray).DeepCopyInto(out.(*JSONSchemaPropsOrArray))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaPropsOrArray{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaPropsOrBool).DeepCopyInto(out.(*JSONSchemaPropsOrBool))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaPropsOrBool{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaPropsOrStringArray).DeepCopyInto(out.(*JSONSchemaPropsOrStringArray))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaPropsOrStringArray{})},
|
||||
)
|
||||
}
|
||||
|
||||
@ -168,6 +196,15 @@ func (in *CustomResourceDefinitionNames) DeepCopy() *CustomResourceDefinitionNam
|
||||
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
|
||||
*out = *in
|
||||
in.Names.DeepCopyInto(&out.Names)
|
||||
if in.Validation != nil {
|
||||
in, out := &in.Validation, &out.Validation
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(CustomResourceValidation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -204,3 +241,159 @@ func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionSt
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceValidation) DeepCopyInto(out *CustomResourceValidation) {
|
||||
*out = *in
|
||||
if in.OpenAPIV3Schema != nil {
|
||||
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceValidation.
|
||||
func (in *CustomResourceValidation) DeepCopy() *CustomResourceValidation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceValidation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExternalDocumentation) DeepCopyInto(out *ExternalDocumentation) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalDocumentation.
|
||||
func (in *ExternalDocumentation) DeepCopy() *ExternalDocumentation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExternalDocumentation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSON) DeepCopyInto(out *JSON) {
|
||||
*out = *in
|
||||
if in.Raw != nil {
|
||||
in, out := &in.Raw, &out.Raw
|
||||
*out = make([]byte, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSON.
|
||||
func (in *JSON) DeepCopy() *JSON {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSON)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaProps) DeepCopyInto(out *JSONSchemaProps) {
|
||||
clone := in.DeepCopy()
|
||||
*out = *clone
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrArray) DeepCopyInto(out *JSONSchemaPropsOrArray) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.JSONSchemas != nil {
|
||||
in, out := &in.JSONSchemas, &out.JSONSchemas
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrArray.
|
||||
func (in *JSONSchemaPropsOrArray) DeepCopy() *JSONSchemaPropsOrArray {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrArray)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrBool) DeepCopyInto(out *JSONSchemaPropsOrBool) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrBool.
|
||||
func (in *JSONSchemaPropsOrBool) DeepCopy() *JSONSchemaPropsOrBool {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrBool)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrStringArray) DeepCopyInto(out *JSONSchemaPropsOrStringArray) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.Property != nil {
|
||||
in, out := &in.Property, &out.Property
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrStringArray.
|
||||
func (in *JSONSchemaPropsOrStringArray) DeepCopy() *JSONSchemaPropsOrStringArray {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrStringArray)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["validation.go"],
|
||||
deps = [
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -20,10 +20,15 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
"github.com/go-openapi/spec"
|
||||
|
||||
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||
validationutil "k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||
)
|
||||
|
||||
// ValidateCustomResourceDefinition statically validates
|
||||
@ -100,6 +105,12 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
|
||||
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionNames(&spec.Names, fldPath.Child("names"))...)
|
||||
|
||||
if utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceValidation) {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionValidation(spec.Validation, fldPath.Child("validation"))...)
|
||||
} else if spec.Validation != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("validation"), "disabled by feature-gate"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@ -158,3 +169,162 @@ func ValidateCustomResourceDefinitionNames(names *apiextensions.CustomResourceDe
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// specStandardValidator applies validations for different OpenAPI specfication versions.
|
||||
type specStandardValidator interface {
|
||||
validate(spec *apiextensions.JSONSchemaProps, fldPath *field.Path) field.ErrorList
|
||||
}
|
||||
|
||||
// ValidateCustomResourceDefinitionValidation statically validates
|
||||
func ValidateCustomResourceDefinitionValidation(customResourceValidation *apiextensions.CustomResourceValidation, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if customResourceValidation == nil {
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if customResourceValidation.OpenAPIV3Schema != nil {
|
||||
openAPIV3Schema := &specStandardValidatorV3{}
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(customResourceValidation.OpenAPIV3Schema, fldPath.Child("openAPIV3Schema"), openAPIV3Schema)...)
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
// ValidateCustomResourceDefinitionOpenAPISchema statically validates
|
||||
func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSchemaProps, fldPath *field.Path, ssv specStandardValidator) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if schema == nil {
|
||||
return allErrs
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, ssv.validate(schema, fldPath)...)
|
||||
|
||||
if schema.UniqueItems == true {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("uniqueItems"), "uniqueItems cannot be set to true since the runtime complexity becomes quadratic"))
|
||||
}
|
||||
|
||||
// additionalProperties contradicts Kubernetes API convention to ignore unknown fields
|
||||
if schema.AdditionalProperties != nil {
|
||||
if schema.AdditionalProperties.Allows == false {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("additionalProperties"), "additionalProperties cannot be set to false"))
|
||||
}
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(schema.AdditionalProperties.Schema, fldPath.Child("additionalProperties"), ssv)...)
|
||||
}
|
||||
|
||||
if schema.Ref != nil {
|
||||
openapiRef, err := spec.NewRef(*schema.Ref)
|
||||
if err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("ref"), *schema.Ref, err.Error()))
|
||||
}
|
||||
|
||||
if !openapiRef.IsValidURI() {
|
||||
allErrs = append(allErrs, field.Invalid(fldPath.Child("ref"), *schema.Ref, "ref does not point to a valid URI"))
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(schema.AdditionalItems.Schema, fldPath.Child("additionalItems"), ssv)...)
|
||||
}
|
||||
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(schema.Not, fldPath.Child("not"), ssv)...)
|
||||
|
||||
if len(schema.AllOf) != 0 {
|
||||
for _, jsonSchema := range schema.AllOf {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("allOf"), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(schema.OneOf) != 0 {
|
||||
for _, jsonSchema := range schema.OneOf {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("oneOf"), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(schema.AnyOf) != 0 {
|
||||
for _, jsonSchema := range schema.AnyOf {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("anyOf"), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(schema.Properties) != 0 {
|
||||
for property, jsonSchema := range schema.Properties {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("properties").Key(property), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(schema.PatternProperties) != 0 {
|
||||
for property, jsonSchema := range schema.PatternProperties {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("patternProperties").Key(property), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
if len(schema.Definitions) != 0 {
|
||||
for definition, jsonSchema := range schema.Definitions {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("definitions").Key(definition), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(schema.Items.Schema, fldPath.Child("items"), ssv)...)
|
||||
if len(schema.Items.JSONSchemas) != 0 {
|
||||
for _, jsonSchema := range schema.Items.JSONSchemas {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(&jsonSchema, fldPath.Child("items"), ssv)...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Dependencies != nil {
|
||||
for dependency, jsonSchemaPropsOrStringArray := range schema.Dependencies {
|
||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionOpenAPISchema(jsonSchemaPropsOrStringArray.Schema, fldPath.Child("dependencies").Key(dependency), ssv)...)
|
||||
}
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
||||
type specStandardValidatorV3 struct{}
|
||||
|
||||
// validate validates against OpenAPI Schema v3.
|
||||
func (v *specStandardValidatorV3) validate(schema *apiextensions.JSONSchemaProps, fldPath *field.Path) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
|
||||
if schema == nil {
|
||||
return allErrs
|
||||
}
|
||||
|
||||
if schema.Default != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("default"), "default is not supported"))
|
||||
}
|
||||
|
||||
if schema.ID != "" {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("id"), "id is not supported"))
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("additionalItems"), "additionalItems is not supported"))
|
||||
}
|
||||
|
||||
if len(schema.PatternProperties) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("patternProperties"), "patternProperties is not supported"))
|
||||
}
|
||||
|
||||
if len(schema.Definitions) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("definitions"), "definitions is not supported"))
|
||||
}
|
||||
|
||||
if schema.Dependencies != nil {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("dependencies"), "dependencies is not supported"))
|
||||
}
|
||||
|
||||
if schema.Type == "null" {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("type"), "type cannot be set to null"))
|
||||
}
|
||||
|
||||
if schema.Items != nil && len(schema.Items.JSONSchemas) != 0 {
|
||||
allErrs = append(allErrs, field.Forbidden(fldPath.Child("items"), "items must be a schema object and not an array"))
|
||||
}
|
||||
|
||||
return allErrs
|
||||
}
|
||||
|
@ -60,6 +60,30 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
||||
in.(*CustomResourceDefinitionStatus).DeepCopyInto(out.(*CustomResourceDefinitionStatus))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CustomResourceDefinitionStatus{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*CustomResourceValidation).DeepCopyInto(out.(*CustomResourceValidation))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&CustomResourceValidation{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*ExternalDocumentation).DeepCopyInto(out.(*ExternalDocumentation))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&ExternalDocumentation{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaProps).DeepCopyInto(out.(*JSONSchemaProps))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaProps{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaPropsOrArray).DeepCopyInto(out.(*JSONSchemaPropsOrArray))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaPropsOrArray{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaPropsOrBool).DeepCopyInto(out.(*JSONSchemaPropsOrBool))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaPropsOrBool{})},
|
||||
conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {
|
||||
in.(*JSONSchemaPropsOrStringArray).DeepCopyInto(out.(*JSONSchemaPropsOrStringArray))
|
||||
return nil
|
||||
}, InType: reflect.TypeOf(&JSONSchemaPropsOrStringArray{})},
|
||||
)
|
||||
}
|
||||
|
||||
@ -168,6 +192,15 @@ func (in *CustomResourceDefinitionNames) DeepCopy() *CustomResourceDefinitionNam
|
||||
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
|
||||
*out = *in
|
||||
in.Names.DeepCopyInto(&out.Names)
|
||||
if in.Validation != nil {
|
||||
in, out := &in.Validation, &out.Validation
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(CustomResourceValidation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -204,3 +237,138 @@ func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionSt
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *CustomResourceValidation) DeepCopyInto(out *CustomResourceValidation) {
|
||||
*out = *in
|
||||
if in.OpenAPIV3Schema != nil {
|
||||
in, out := &in.OpenAPIV3Schema, &out.OpenAPIV3Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomResourceValidation.
|
||||
func (in *CustomResourceValidation) DeepCopy() *CustomResourceValidation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(CustomResourceValidation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ExternalDocumentation) DeepCopyInto(out *ExternalDocumentation) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalDocumentation.
|
||||
func (in *ExternalDocumentation) DeepCopy() *ExternalDocumentation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ExternalDocumentation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaProps) DeepCopyInto(out *JSONSchemaProps) {
|
||||
clone := in.DeepCopy()
|
||||
*out = *clone
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrArray) DeepCopyInto(out *JSONSchemaPropsOrArray) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.JSONSchemas != nil {
|
||||
in, out := &in.JSONSchemas, &out.JSONSchemas
|
||||
*out = make([]JSONSchemaProps, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrArray.
|
||||
func (in *JSONSchemaPropsOrArray) DeepCopy() *JSONSchemaPropsOrArray {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrArray)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrBool) DeepCopyInto(out *JSONSchemaPropsOrBool) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrBool.
|
||||
func (in *JSONSchemaPropsOrBool) DeepCopy() *JSONSchemaPropsOrBool {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrBool)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *JSONSchemaPropsOrStringArray) DeepCopyInto(out *JSONSchemaPropsOrStringArray) {
|
||||
*out = *in
|
||||
if in.Schema != nil {
|
||||
in, out := &in.Schema, &out.Schema
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(JSONSchemaProps)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.Property != nil {
|
||||
in, out := &in.Property, &out.Property
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JSONSchemaPropsOrStringArray.
|
||||
func (in *JSONSchemaPropsOrStringArray) DeepCopy() *JSONSchemaPropsOrStringArray {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(JSONSchemaPropsOrStringArray)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
@ -14,10 +14,14 @@ go_library(
|
||||
"customresource_handler.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/go-openapi/strfmt:go_default_library",
|
||||
"//vendor/github.com/go-openapi/validate:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/internalclientset:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions:go_default_library",
|
||||
@ -68,6 +72,9 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
@ -171,6 +171,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
||||
groupDiscoveryHandler,
|
||||
s.GenericAPIServer.RequestContextMapper(),
|
||||
s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions().Lister(),
|
||||
s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(),
|
||||
delegateHandler,
|
||||
c.CRDRESTOptionsGetter,
|
||||
c.GenericConfig.AdmissionControl,
|
||||
|
@ -26,6 +26,11 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
openapispec "github.com/go-openapi/spec"
|
||||
"github.com/go-openapi/strfmt"
|
||||
"github.com/go-openapi/validate"
|
||||
"github.com/golang/glog"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -44,8 +49,11 @@ import (
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
"k8s.io/client-go/discovery"
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
|
||||
informers "k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion/apiextensions/internalversion"
|
||||
listers "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion"
|
||||
"k8s.io/apiextensions-apiserver/pkg/controller/finalizer"
|
||||
"k8s.io/apiextensions-apiserver/pkg/registry/customresource"
|
||||
@ -84,6 +92,7 @@ func NewCustomResourceDefinitionHandler(
|
||||
groupDiscoveryHandler *groupDiscoveryHandler,
|
||||
requestContextMapper apirequest.RequestContextMapper,
|
||||
crdLister listers.CustomResourceDefinitionLister,
|
||||
crdInformer informers.CustomResourceDefinitionInformer,
|
||||
delegate http.Handler,
|
||||
restOptionsGetter generic.RESTOptionsGetter,
|
||||
admission admission.Interface) *crdHandler {
|
||||
@ -98,6 +107,10 @@ func NewCustomResourceDefinitionHandler(
|
||||
admission: admission,
|
||||
}
|
||||
|
||||
crdInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
UpdateFunc: ret.updateCustomResourceDefinition,
|
||||
})
|
||||
|
||||
ret.customStorage.Store(crdStorageMap{})
|
||||
return ret
|
||||
}
|
||||
@ -155,7 +168,12 @@ func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
terminating := apiextensions.IsCRDConditionTrue(crd, apiextensions.Terminating)
|
||||
|
||||
crdInfo := r.getServingInfoFor(crd)
|
||||
crdInfo, err := r.getServingInfoFor(crd)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
storage := crdInfo.storage
|
||||
requestScope := crdInfo.requestScope
|
||||
minRequestTimeout := 1 * time.Minute
|
||||
@ -250,15 +268,18 @@ func (r *crdHandler) removeDeadStorage() {
|
||||
// GetCustomResourceListerCollectionDeleter returns the ListerCollectionDeleter for
|
||||
// the given uid, or nil if one does not exist.
|
||||
func (r *crdHandler) GetCustomResourceListerCollectionDeleter(crd *apiextensions.CustomResourceDefinition) finalizer.ListerCollectionDeleter {
|
||||
info := r.getServingInfoFor(crd)
|
||||
info, err := r.getServingInfoFor(crd)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
}
|
||||
return info.storage
|
||||
}
|
||||
|
||||
func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefinition) *crdInfo {
|
||||
func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefinition) (*crdInfo, error) {
|
||||
storageMap := r.customStorage.Load().(crdStorageMap)
|
||||
ret, ok := storageMap[crd.UID]
|
||||
if ok {
|
||||
return ret
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
r.customStorageLock.Lock()
|
||||
@ -266,7 +287,7 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
|
||||
|
||||
ret, ok = storageMap[crd.UID]
|
||||
if ok {
|
||||
return ret
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// In addition to Unstructured objects (Custom Resources), we also may sometimes need to
|
||||
@ -287,6 +308,17 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
|
||||
unstructuredTyper: discovery.NewUnstructuredObjectTyper(nil),
|
||||
}
|
||||
creator := unstructuredCreator{}
|
||||
|
||||
// convert CRD schema to openapi schema
|
||||
openapiSchema := &openapispec.Schema{}
|
||||
if err := apiservervalidation.ConvertToOpenAPITypes(crd, openapiSchema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := openapispec.ExpandSchema(openapiSchema, nil, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
validator := validate.NewSchemaValidator(openapiSchema, nil, "", strfmt.Default)
|
||||
|
||||
storage := customresource.NewREST(
|
||||
schema.GroupResource{Group: crd.Spec.Group, Resource: crd.Spec.Names.Plural},
|
||||
schema.GroupVersionKind{Group: crd.Spec.Group, Version: crd.Spec.Version, Kind: crd.Spec.Names.ListKind},
|
||||
@ -295,6 +327,7 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
|
||||
typer,
|
||||
crd.Spec.Scope == apiextensions.NamespaceScoped,
|
||||
kind,
|
||||
validator,
|
||||
),
|
||||
r.restOptionsGetter,
|
||||
)
|
||||
@ -354,7 +387,27 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
|
||||
|
||||
storageMap2[crd.UID] = ret
|
||||
r.customStorage.Store(storageMap2)
|
||||
return ret
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (c *crdHandler) updateCustomResourceDefinition(oldObj, _ interface{}) {
|
||||
oldCRD := oldObj.(*apiextensions.CustomResourceDefinition)
|
||||
glog.V(4).Infof("Updating customresourcedefinition %s", oldCRD.Name)
|
||||
|
||||
c.customStorageLock.Lock()
|
||||
defer c.customStorageLock.Unlock()
|
||||
|
||||
storageMap := c.customStorage.Load().(crdStorageMap)
|
||||
storageMap2 := make(crdStorageMap, len(storageMap))
|
||||
|
||||
// Copy because we cannot write to storageMap without a race
|
||||
// as it is used without locking elsewhere
|
||||
for k, v := range storageMap {
|
||||
storageMap2[k] = v
|
||||
}
|
||||
|
||||
delete(storageMap2, oldCRD.UID)
|
||||
c.customStorage.Store(storageMap2)
|
||||
}
|
||||
|
||||
type unstructuredNegotiatedSerializer struct {
|
||||
|
@ -0,0 +1,32 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["validation.go"],
|
||||
tags = ["automanaged"],
|
||||
deps = [
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/go-openapi/validate:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
@ -0,0 +1,217 @@
|
||||
/*
|
||||
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/go-openapi/spec"
|
||||
"github.com/go-openapi/validate"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
)
|
||||
|
||||
// ValidateCustomResource validates the Custom Resource against the schema in the CustomResourceDefinition.
|
||||
// CustomResource is a JSON data structure.
|
||||
func ValidateCustomResource(customResource interface{}, validator *validate.SchemaValidator) error {
|
||||
result := validator.Validate(customResource)
|
||||
if result.AsError() != nil {
|
||||
return result.AsError()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertToOpenAPITypes is used to convert internal types to go-openapi types.
|
||||
func ConvertToOpenAPITypes(in *apiextensions.CustomResourceDefinition, out *spec.Schema) error {
|
||||
if in.Spec.Validation != nil {
|
||||
if err := convertJSONSchemaProps(in.Spec.Validation.OpenAPIV3Schema, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertJSONSchemaProps(in *apiextensions.JSONSchemaProps, out *spec.Schema) error {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
out.ID = in.ID
|
||||
out.Schema = spec.SchemaURL(in.Schema)
|
||||
out.Description = in.Description
|
||||
if in.Type != "" {
|
||||
out.Type = spec.StringOrArray([]string{in.Type})
|
||||
}
|
||||
out.Format = in.Format
|
||||
out.Title = in.Title
|
||||
out.ExclusiveMaximum = in.ExclusiveMaximum
|
||||
out.Minimum = in.Minimum
|
||||
out.ExclusiveMinimum = in.ExclusiveMinimum
|
||||
out.MaxLength = in.MaxLength
|
||||
out.MinLength = in.MinLength
|
||||
out.Pattern = in.Pattern
|
||||
out.MaxItems = in.MaxItems
|
||||
out.MinItems = in.MinItems
|
||||
out.UniqueItems = in.UniqueItems
|
||||
out.MultipleOf = in.MultipleOf
|
||||
out.MaxProperties = in.MaxProperties
|
||||
out.MinProperties = in.MinProperties
|
||||
out.Required = in.Required
|
||||
|
||||
if in.Default != nil {
|
||||
out.Default = *(in.Default)
|
||||
}
|
||||
if in.Example != nil {
|
||||
out.Example = *(in.Example)
|
||||
}
|
||||
|
||||
out.Enum = make([]interface{}, len(in.Enum))
|
||||
for k, v := range in.Enum {
|
||||
out.Enum[k] = v
|
||||
}
|
||||
|
||||
if err := convertJSONSchemaPropsOrArray(in.Items, out.Items); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convertSliceOfJSONSchemaProps(&in.AllOf, &out.AllOf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convertSliceOfJSONSchemaProps(&in.OneOf, &out.OneOf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convertSliceOfJSONSchemaProps(&in.AnyOf, &out.AnyOf); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := convertJSONSchemaProps(in.Not, out.Not); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var err error
|
||||
out.Properties, err = convertMapOfJSONSchemaProps(in.Properties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out.PatternProperties, err = convertMapOfJSONSchemaProps(in.PatternProperties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if in.Ref != nil {
|
||||
out.Ref, err = spec.NewRef(*in.Ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := convertJSONSchemaPropsorBool(in.AdditionalProperties, out.AdditionalProperties); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := convertJSONSchemaPropsorBool(in.AdditionalItems, out.AdditionalItems); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := convertJSONSchemaDependencies(in.Dependencies, out.Dependencies); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out.Definitions, err = convertMapOfJSONSchemaProps(in.Definitions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if in.ExternalDocs != nil {
|
||||
out.ExternalDocs = &spec.ExternalDocumentation{}
|
||||
out.ExternalDocs.Description = in.ExternalDocs.Description
|
||||
out.ExternalDocs.URL = in.ExternalDocs.URL
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertSliceOfJSONSchemaProps(in *[]apiextensions.JSONSchemaProps, out *[]spec.Schema) error {
|
||||
if in != nil {
|
||||
for _, jsonSchemaProps := range *in {
|
||||
schema := spec.Schema{}
|
||||
if err := convertJSONSchemaProps(&jsonSchemaProps, &schema); err != nil {
|
||||
return err
|
||||
}
|
||||
*out = append(*out, schema)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertMapOfJSONSchemaProps(in map[string]apiextensions.JSONSchemaProps) (map[string]spec.Schema, error) {
|
||||
out := make(map[string]spec.Schema)
|
||||
if len(in) != 0 {
|
||||
for k, jsonSchemaProps := range in {
|
||||
schema := spec.Schema{}
|
||||
if err := convertJSONSchemaProps(&jsonSchemaProps, &schema); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[k] = schema
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func convertJSONSchemaPropsOrArray(in *apiextensions.JSONSchemaPropsOrArray, out *spec.SchemaOrArray) error {
|
||||
if in != nil {
|
||||
out.Schema = &spec.Schema{}
|
||||
if err := convertJSONSchemaProps(in.Schema, out.Schema); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertJSONSchemaPropsorBool(in *apiextensions.JSONSchemaPropsOrBool, out *spec.SchemaOrBool) error {
|
||||
if in != nil {
|
||||
out = &spec.SchemaOrBool{}
|
||||
out.Allows = in.Allows
|
||||
out.Schema = &spec.Schema{}
|
||||
if err := convertJSONSchemaProps(in.Schema, out.Schema); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertJSONSchemaPropsOrStringArray(in *apiextensions.JSONSchemaPropsOrStringArray, out *spec.SchemaOrStringArray) error {
|
||||
if in != nil {
|
||||
out.Property = in.Property
|
||||
out.Schema = &spec.Schema{}
|
||||
if err := convertJSONSchemaProps(in.Schema, out.Schema); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertJSONSchemaDependencies(in apiextensions.JSONSchemaDependencies, out spec.Dependencies) error {
|
||||
if in != nil {
|
||||
for k, v := range in {
|
||||
schemaOrArray := spec.SchemaOrStringArray{}
|
||||
if err := convertJSONSchemaPropsOrStringArray(&v, &schemaOrArray); err != nil {
|
||||
return err
|
||||
}
|
||||
out[k] = schemaOrArray
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["kube_features.go"],
|
||||
deps = ["//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
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 features
|
||||
|
||||
import (
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
)
|
||||
|
||||
const (
|
||||
// Every feature gate should add method here following this template:
|
||||
//
|
||||
// // owner: @username
|
||||
// // alpha: v1.4
|
||||
// MyFeature() bool
|
||||
|
||||
// owner: @sttts, @nikhita
|
||||
// alpha: v1.8
|
||||
//
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources
|
||||
CustomResourceValidation utilfeature.Feature = "CustomResourceValidation"
|
||||
)
|
||||
|
||||
func init() {
|
||||
utilfeature.DefaultFeatureGate.Add(defaultKubernetesFeatureGates)
|
||||
}
|
||||
|
||||
// defaultKubernetesFeatureGates consists of all known Kubernetes-specific feature keys.
|
||||
// To add a new feature, define a key for it above and add it here. The features will be
|
||||
// available throughout Kubernetes binaries.
|
||||
var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureSpec{
|
||||
CustomResourceValidation: {Default: false, PreRelease: utilfeature.Alpha},
|
||||
}
|
@ -12,6 +12,8 @@ go_library(
|
||||
"strategy.go",
|
||||
],
|
||||
deps = [
|
||||
"//vendor/github.com/go-openapi/validate:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
|
@ -19,9 +19,12 @@ package customresource
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-openapi/validate"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/api/validation"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@ -30,6 +33,8 @@ import (
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
|
||||
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
|
||||
)
|
||||
|
||||
type customResourceDefinitionStorageStrategy struct {
|
||||
@ -40,7 +45,7 @@ type customResourceDefinitionStorageStrategy struct {
|
||||
validator customResourceValidator
|
||||
}
|
||||
|
||||
func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind) customResourceDefinitionStorageStrategy {
|
||||
func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.GroupVersionKind, validator *validate.SchemaValidator) customResourceDefinitionStorageStrategy {
|
||||
return customResourceDefinitionStorageStrategy{
|
||||
ObjectTyper: typer,
|
||||
NameGenerator: names.SimpleNameGenerator,
|
||||
@ -48,6 +53,7 @@ func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.Gr
|
||||
validator: customResourceValidator{
|
||||
namespaceScoped: namespaceScoped,
|
||||
kind: kind,
|
||||
validator: validator,
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -113,6 +119,7 @@ func (a customResourceDefinitionStorageStrategy) MatchCustomResourceDefinitionSt
|
||||
type customResourceValidator struct {
|
||||
namespaceScoped bool
|
||||
kind schema.GroupVersionKind
|
||||
validator *validate.SchemaValidator
|
||||
}
|
||||
|
||||
func (a customResourceValidator) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
|
||||
@ -131,6 +138,17 @@ func (a customResourceValidator) Validate(ctx genericapirequest.Context, obj run
|
||||
return field.ErrorList{field.Invalid(field.NewPath("apiVersion"), typeAccessor.GetKind(), fmt.Sprintf("must be %v", a.kind.Group+"/"+a.kind.Version))}
|
||||
}
|
||||
|
||||
customResourceObject, ok := obj.(*unstructured.Unstructured)
|
||||
// this will never happen.
|
||||
if !ok {
|
||||
return field.ErrorList{field.Invalid(field.NewPath(""), customResourceObject, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", customResourceObject))}
|
||||
}
|
||||
|
||||
customResource := customResourceObject.UnstructuredContent()
|
||||
if err = apiservervalidation.ValidateCustomResource(customResource, a.validator); err != nil {
|
||||
return field.ErrorList{field.Invalid(field.NewPath(""), customResource, err.Error())}
|
||||
}
|
||||
|
||||
return validation.ValidateObjectMetaAccessor(accessor, a.namespaceScoped, validation.NameIsDNSSubdomain, field.NewPath("metadata"))
|
||||
}
|
||||
|
||||
@ -154,5 +172,16 @@ func (a customResourceValidator) ValidateUpdate(ctx genericapirequest.Context, o
|
||||
return field.ErrorList{field.Invalid(field.NewPath("apiVersion"), typeAccessor.GetKind(), fmt.Sprintf("must be %v", a.kind.Group+"/"+a.kind.Version))}
|
||||
}
|
||||
|
||||
customResourceObject, ok := obj.(*unstructured.Unstructured)
|
||||
// this will never happen.
|
||||
if !ok {
|
||||
return field.ErrorList{field.Invalid(field.NewPath(""), customResourceObject, fmt.Sprintf("has type %T. Must be a pointer to an Unstructured type", customResourceObject))}
|
||||
}
|
||||
|
||||
customResource := customResourceObject.UnstructuredContent()
|
||||
if err = apiservervalidation.ValidateCustomResource(customResource, a.validator); err != nil {
|
||||
return field.ErrorList{field.Invalid(field.NewPath(""), customResource, err.Error())}
|
||||
}
|
||||
|
||||
return validation.ValidateObjectMetaAccessorUpdate(objAccessor, oldAccessor, field.NewPath("metadata"))
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ go_library(
|
||||
deps = [
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
@ -28,6 +29,7 @@ go_library(
|
||||
"//vendor/k8s.io/apiserver/pkg/storage:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/errors:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/names:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -28,9 +28,11 @@ import (
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
|
||||
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||
)
|
||||
|
||||
type strategy struct {
|
||||
@ -50,6 +52,11 @@ func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Obje
|
||||
crd := obj.(*apiextensions.CustomResourceDefinition)
|
||||
crd.Status = apiextensions.CustomResourceDefinitionStatus{}
|
||||
crd.Generation = 1
|
||||
|
||||
// if the feature gate is disabled, drop the feature.
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceValidation) {
|
||||
crd.Spec.Validation = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (strategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime.Object) {
|
||||
@ -68,6 +75,11 @@ func (strategy) PrepareForUpdate(ctx genericapirequest.Context, obj, old runtime
|
||||
if !apiequality.Semantic.DeepEqual(oldCRD.Spec, newCRD.Spec) {
|
||||
newCRD.Generation = oldCRD.Generation + 1
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(apiextensionsfeatures.CustomResourceValidation) {
|
||||
newCRD.Spec.Validation = nil
|
||||
oldCRD.Spec.Validation = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (strategy) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
|
||||
|
@ -32,6 +32,7 @@ go_test(
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -213,7 +213,7 @@ func checkForWatchCachePrimed(crd *apiextensionsv1beta1.CustomResourceDefinition
|
||||
return err
|
||||
}
|
||||
|
||||
instanceName := "foo"
|
||||
instanceName := "setup-instance"
|
||||
instance := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
||||
@ -222,6 +222,11 @@ func checkForWatchCachePrimed(crd *apiextensionsv1beta1.CustomResourceDefinition
|
||||
"namespace": ns,
|
||||
"name": instanceName,
|
||||
},
|
||||
"alpha": "foo_123",
|
||||
"beta": 10,
|
||||
"gamma": "bar",
|
||||
"delta": "hello",
|
||||
"epsilon": "foobar",
|
||||
},
|
||||
}
|
||||
if _, err := resourceClient.Create(instance); err != nil {
|
||||
|
@ -19,10 +19,15 @@ package integration
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func TestForProperValidationErrors(t *testing.T) {
|
||||
@ -79,3 +84,368 @@ func TestForProperValidationErrors(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newNoxuValidationCRD(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
|
||||
return &apiextensionsv1beta1.CustomResourceDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
|
||||
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
|
||||
Group: "mygroup.example.com",
|
||||
Version: "v1beta1",
|
||||
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
|
||||
Plural: "noxus",
|
||||
Singular: "nonenglishnoxu",
|
||||
Kind: "WishIHadChosenNoxu",
|
||||
ShortNames: []string{"foo", "bar", "abc", "def"},
|
||||
ListKind: "NoxuItemList",
|
||||
},
|
||||
Scope: apiextensionsv1beta1.NamespaceScoped,
|
||||
Validation: &apiextensionsv1beta1.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &apiextensionsv1beta1.JSONSchemaProps{
|
||||
Required: []string{"alpha", "beta"},
|
||||
AdditionalProperties: &apiextensionsv1beta1.JSONSchemaPropsOrBool{
|
||||
Allows: true,
|
||||
},
|
||||
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
|
||||
"alpha": {
|
||||
Description: "Alpha is an alphanumeric string with underscores",
|
||||
Type: "string",
|
||||
Pattern: "^[a-zA-Z0-9_]*$",
|
||||
},
|
||||
"beta": {
|
||||
Description: "Minimum value of beta is 10",
|
||||
Type: "number",
|
||||
Minimum: float64Ptr(10),
|
||||
},
|
||||
"gamma": {
|
||||
Description: "Gamma is restricted to foo, bar and baz",
|
||||
Type: "string",
|
||||
Enum: []apiextensionsv1beta1.JSON{
|
||||
{
|
||||
Raw: []byte(`"foo"`),
|
||||
},
|
||||
{
|
||||
Raw: []byte(`"bar"`),
|
||||
},
|
||||
{
|
||||
Raw: []byte(`"baz"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
"delta": {
|
||||
Description: "Delta is a string with a maximum length of 5 or a number with a minimum value of 0",
|
||||
AnyOf: []apiextensionsv1beta1.JSONSchemaProps{
|
||||
{
|
||||
Type: "string",
|
||||
MaxLength: int64Ptr(5),
|
||||
},
|
||||
{
|
||||
Type: "number",
|
||||
Minimum: float64Ptr(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newNoxuValidationInstance(namespace, name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "mygroup.example.com/v1beta1",
|
||||
"kind": "WishIHadChosenNoxu",
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": namespace,
|
||||
"name": name,
|
||||
},
|
||||
"alpha": "foo_123",
|
||||
"beta": 10,
|
||||
"gamma": "bar",
|
||||
"delta": "hello",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomResourceValidation(t *testing.T) {
|
||||
stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
// enable alpha feature CustomResourceValidation
|
||||
err = utilfeature.DefaultFeatureGate.Set("CustomResourceValidation=true")
|
||||
if err != nil {
|
||||
t.Errorf("failed to enable feature gate for CustomResourceValidation: %v", err)
|
||||
}
|
||||
|
||||
noxuDefinition := newNoxuValidationCRD(apiextensionsv1beta1.NamespaceScoped)
|
||||
noxuVersionClient, err := testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, noxuVersionClient, noxuDefinition)
|
||||
_, err = instantiateCustomResource(t, newNoxuValidationInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu instance: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomResourceUpdateValidation(t *testing.T) {
|
||||
stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
// enable alpha feature CustomResourceValidation
|
||||
err = utilfeature.DefaultFeatureGate.Set("CustomResourceValidation=true")
|
||||
if err != nil {
|
||||
t.Errorf("failed to enable feature gate for CustomResourceValidation: %v", err)
|
||||
}
|
||||
|
||||
noxuDefinition := newNoxuValidationCRD(apiextensionsv1beta1.NamespaceScoped)
|
||||
noxuVersionClient, err := testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, noxuVersionClient, noxuDefinition)
|
||||
_, err = instantiateCustomResource(t, newNoxuValidationInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu instance: %v", err)
|
||||
}
|
||||
|
||||
gottenNoxuInstance, err := noxuResourceClient.Get("foo", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// invalidate the instance
|
||||
gottenNoxuInstance.Object = map[string]interface{}{
|
||||
"apiVersion": "mygroup.example.com/v1beta1",
|
||||
"kind": "WishIHadChosenNoxu",
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": "not-the-default",
|
||||
"name": "foo",
|
||||
},
|
||||
"gamma": "bar",
|
||||
"delta": "hello",
|
||||
}
|
||||
|
||||
_, err = noxuResourceClient.Update(gottenNoxuInstance)
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error: alpha and beta should be present while updating %v", gottenNoxuInstance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomResourceValidationErrors(t *testing.T) {
|
||||
stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
// enable alpha feature CustomResourceValidation
|
||||
err = utilfeature.DefaultFeatureGate.Set("CustomResourceValidation=true")
|
||||
if err != nil {
|
||||
t.Errorf("failed to enable feature gate for CustomResourceValidation: %v", err)
|
||||
}
|
||||
|
||||
noxuDefinition := newNoxuValidationCRD(apiextensionsv1beta1.NamespaceScoped)
|
||||
noxuVersionClient, err := testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, noxuVersionClient, noxuDefinition)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
instanceFn func() *unstructured.Unstructured
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "bad alpha",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := newNoxuValidationInstance(ns, "foo")
|
||||
instance.Object["alpha"] = "foo_123!"
|
||||
return instance
|
||||
},
|
||||
expectedError: "alpha in body should match '^[a-zA-Z0-9_]*$'",
|
||||
},
|
||||
{
|
||||
name: "bad beta",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := newNoxuValidationInstance(ns, "foo")
|
||||
instance.Object["beta"] = 5
|
||||
return instance
|
||||
},
|
||||
expectedError: "beta in body should be greater than or equal to 10",
|
||||
},
|
||||
{
|
||||
name: "bad gamma",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := newNoxuValidationInstance(ns, "foo")
|
||||
instance.Object["gamma"] = "qux"
|
||||
return instance
|
||||
},
|
||||
expectedError: "gamma in body should be one of [foo bar baz]",
|
||||
},
|
||||
{
|
||||
name: "bad delta",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := newNoxuValidationInstance(ns, "foo")
|
||||
instance.Object["delta"] = "foobarbaz"
|
||||
return instance
|
||||
},
|
||||
expectedError: "must validate at least one schema (anyOf)\ndelta in body should be at most 5 chars long",
|
||||
},
|
||||
{
|
||||
name: "absent alpha and beta",
|
||||
instanceFn: func() *unstructured.Unstructured {
|
||||
instance := newNoxuValidationInstance(ns, "foo")
|
||||
instance.Object = map[string]interface{}{
|
||||
"apiVersion": "mygroup.example.com/v1beta1",
|
||||
"kind": "WishIHadChosenNoxu",
|
||||
"metadata": map[string]interface{}{
|
||||
"namespace": "not-the-default",
|
||||
"name": "foo",
|
||||
},
|
||||
"gamma": "bar",
|
||||
"delta": "hello",
|
||||
}
|
||||
return instance
|
||||
},
|
||||
expectedError: ".alpha in body is required\n.beta in body is required",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
_, err := noxuResourceClient.Create(tc.instanceFn())
|
||||
if err == nil {
|
||||
t.Errorf("%v: expected %v", tc.name, tc.expectedError)
|
||||
continue
|
||||
}
|
||||
// this only works when status errors contain the expect kind and version, so this effectively tests serializations too
|
||||
if !strings.Contains(err.Error(), tc.expectedError) {
|
||||
t.Errorf("%v: expected %v, got %v", tc.name, tc.expectedError, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCRValidationOnCRDUpdate(t *testing.T) {
|
||||
stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
// enable alpha feature CustomResourceValidation
|
||||
err = utilfeature.DefaultFeatureGate.Set("CustomResourceValidation=true")
|
||||
if err != nil {
|
||||
t.Errorf("failed to enable feature gate for CustomResourceValidation: %v", err)
|
||||
}
|
||||
|
||||
noxuDefinition := newNoxuValidationCRD(apiextensionsv1beta1.NamespaceScoped)
|
||||
|
||||
// set stricter schema
|
||||
noxuDefinition.Spec.Validation.OpenAPIV3Schema.Required = []string{"alpha", "beta", "epsilon"}
|
||||
|
||||
noxuVersionClient, err := testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, noxuVersionClient, noxuDefinition)
|
||||
|
||||
// CR is rejected
|
||||
_, err = instantiateCustomResource(t, newNoxuValidationInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error: CR should be rejected")
|
||||
}
|
||||
|
||||
gottenCRD, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get("noxus.mygroup.example.com", metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// update the CRD to a less stricter schema
|
||||
gottenCRD.Spec.Validation.OpenAPIV3Schema.Required = []string{"alpha", "beta"}
|
||||
|
||||
updatedCRD, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(gottenCRD)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// CR is now accepted
|
||||
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
|
||||
_, err = instantiateCustomResource(t, newNoxuValidationInstance(ns, "foo"), noxuResourceClient, updatedCRD)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForbiddenFieldsInSchema(t *testing.T) {
|
||||
stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer close(stopCh)
|
||||
|
||||
// enable alpha feature CustomResourceValidation
|
||||
err = utilfeature.DefaultFeatureGate.Set("CustomResourceValidation=true")
|
||||
if err != nil {
|
||||
t.Errorf("failed to enable feature gate for CustomResourceValidation: %v", err)
|
||||
}
|
||||
|
||||
noxuDefinition := newNoxuValidationCRD(apiextensionsv1beta1.NamespaceScoped)
|
||||
noxuDefinition.Spec.Validation.OpenAPIV3Schema.AdditionalProperties.Allows = false
|
||||
|
||||
_, err = testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error: additionalProperties cannot be set to false")
|
||||
}
|
||||
|
||||
noxuDefinition.Spec.Validation.OpenAPIV3Schema.Properties["zeta"] = apiextensionsv1beta1.JSONSchemaProps{
|
||||
Type: "array",
|
||||
UniqueItems: true,
|
||||
}
|
||||
noxuDefinition.Spec.Validation.OpenAPIV3Schema.AdditionalProperties.Allows = true
|
||||
|
||||
_, err = testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error: uniqueItems cannot be set to true")
|
||||
}
|
||||
|
||||
noxuDefinition.Spec.Validation.OpenAPIV3Schema.Properties["zeta"] = apiextensionsv1beta1.JSONSchemaProps{
|
||||
Type: "array",
|
||||
UniqueItems: false,
|
||||
}
|
||||
|
||||
_, err = testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func float64Ptr(f float64) *float64 {
|
||||
return &f
|
||||
}
|
||||
|
||||
func int64Ptr(f int64) *int64 {
|
||||
return &f
|
||||
}
|
||||
|
@ -27,14 +27,14 @@ const (
|
||||
// // alpha: v1.4
|
||||
// MyFeature() bool
|
||||
|
||||
// owner: tallclair
|
||||
// owner: @tallclair
|
||||
// alpha: v1.5
|
||||
//
|
||||
// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
|
||||
// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
|
||||
StreamingProxyRedirects utilfeature.Feature = "StreamingProxyRedirects"
|
||||
|
||||
// owner: tallclair
|
||||
// owner: @tallclair
|
||||
// alpha: v1.7
|
||||
//
|
||||
// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
|
||||
|
Loading…
Reference in New Issue
Block a user