mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 03:11:40 +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/cmd/server
|
||||||
staging/src/k8s.io/apiextensions-apiserver/pkg/controller/finalizer
|
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/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/customresource
|
||||||
staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition
|
staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition
|
||||||
staging/src/k8s.io/apiextensions-apiserver/test/integration/testserver
|
staging/src/k8s.io/apiextensions-apiserver/test/integration/testserver
|
||||||
|
@ -9,6 +9,7 @@ go_library(
|
|||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = ["kube_features.go"],
|
srcs = ["kube_features.go"],
|
||||||
deps = [
|
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/features:go_default_library",
|
||||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
],
|
],
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package features
|
package features
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||||
genericfeatures "k8s.io/apiserver/pkg/features"
|
genericfeatures "k8s.io/apiserver/pkg/features"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
)
|
)
|
||||||
@ -44,13 +45,6 @@ const (
|
|||||||
// alpha: v1.4
|
// alpha: v1.4
|
||||||
DynamicKubeletConfig utilfeature.Feature = "DynamicKubeletConfig"
|
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-
|
// owner: @pweil-
|
||||||
// alpha: v1.5
|
// alpha: v1.5
|
||||||
//
|
//
|
||||||
@ -158,11 +152,16 @@ var defaultKubernetesFeatureGates = map[utilfeature.Feature]utilfeature.FeatureS
|
|||||||
DebugContainers: {Default: false, PreRelease: utilfeature.Alpha},
|
DebugContainers: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
PodPriority: {Default: false, PreRelease: utilfeature.Alpha},
|
PodPriority: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
EnableEquivalenceClassCache: {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
|
// inherited features from generic apiserver, relisted here to get a conflict if it is changed
|
||||||
// unintentionally on either side:
|
// unintentionally on either side:
|
||||||
StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta},
|
genericfeatures.StreamingProxyRedirects: {Default: true, PreRelease: utilfeature.Beta},
|
||||||
genericfeatures.AdvancedAuditing: {Default: false, PreRelease: utilfeature.Alpha},
|
genericfeatures.AdvancedAuditing: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
TaintNodesByCondition: {Default: false, PreRelease: utilfeature.Alpha},
|
genericfeatures.APIResponseCompression: {Default: false, PreRelease: utilfeature.Alpha},
|
||||||
genericfeatures.Initializers: {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;
|
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/api/resource/generated.proto";
|
||||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||||
import "k8s.io/apimachinery/pkg/runtime/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/cmd/server:all-srcs",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/controller/finalizer: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/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/customresource:all-srcs",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition:all-srcs",
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition:all-srcs",
|
||||||
"//staging/src/k8s.io/apiextensions-apiserver/test/integration:all-srcs",
|
"//staging/src/k8s.io/apiextensions-apiserver/test/integration:all-srcs",
|
||||||
|
@ -22,6 +22,10 @@
|
|||||||
"ImportPath": "github.com/PuerkitoBio/urlesc",
|
"ImportPath": "github.com/PuerkitoBio/urlesc",
|
||||||
"Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
"Rev": "5bd2802263f21d8788851d5305584c82a5c75d7e"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/asaskevich/govalidator",
|
||||||
|
"Rev": "593d64559f7600f29581a3ee42177f5dbded27a9"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/beorn7/perks/quantile",
|
"ImportPath": "github.com/beorn7/perks/quantile",
|
||||||
"Rev": "3ac7bf7a47d159a033b107610db8a1b6575507a4"
|
"Rev": "3ac7bf7a47d159a033b107610db8a1b6575507a4"
|
||||||
@ -110,6 +114,14 @@
|
|||||||
"ImportPath": "github.com/ghodss/yaml",
|
"ImportPath": "github.com/ghodss/yaml",
|
||||||
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
"Rev": "73d445a93680fa1a78ae23a5839bad48f32ba1ee"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-openapi/analysis",
|
||||||
|
"Rev": "b44dc874b601d9e4e2f6e19140e794ba24bead3b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-openapi/errors",
|
||||||
|
"Rev": "d24ebc2075bad502fac3a8ae27aa6dd58e1952dc"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/go-openapi/jsonpointer",
|
"ImportPath": "github.com/go-openapi/jsonpointer",
|
||||||
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
"Rev": "46af16f9f7b149af66e5d1bd010e3574dc06de98"
|
||||||
@ -118,14 +130,30 @@
|
|||||||
"ImportPath": "github.com/go-openapi/jsonreference",
|
"ImportPath": "github.com/go-openapi/jsonreference",
|
||||||
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
"Rev": "13c6e3589ad90f49bd3e3bbe2c2cb3d7a4142272"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-openapi/loads",
|
||||||
|
"Rev": "18441dfa706d924a39a030ee2c3b1d8d81917b38"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-openapi/runtime",
|
||||||
|
"Rev": "11e322eeecc1032d5a0a96c566ed53f2b5c26e22"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/go-openapi/spec",
|
"ImportPath": "github.com/go-openapi/spec",
|
||||||
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
"Rev": "6aced65f8501fe1217321abf0749d354824ba2ff"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-openapi/strfmt",
|
||||||
|
"Rev": "d65c7fdb29eca313476e529628176fe17e58c488"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/go-openapi/swag",
|
"ImportPath": "github.com/go-openapi/swag",
|
||||||
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
|
"Rev": "1d0bd113de87027671077d3c71eb3ac5d7dbba72"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "github.com/go-openapi/validate",
|
||||||
|
"Rev": "deaf2c9013bc1a7f4c774662259a506ba874d80f"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/gogo/protobuf/proto",
|
"ImportPath": "github.com/gogo/protobuf/proto",
|
||||||
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
"Rev": "c0656edd0d9eab7c66d1eb0c568f9039345796f7"
|
||||||
|
@ -9,10 +9,12 @@ load(
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"deepcopy.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"helpers.go",
|
"helpers.go",
|
||||||
"register.go",
|
"register.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
|
"types_jsonschema.go",
|
||||||
"zz_generated.deepcopy.go",
|
"zz_generated.deepcopy.go",
|
||||||
],
|
],
|
||||||
deps = [
|
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
|
package fuzzer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/gofuzz"
|
"github.com/google/gofuzz"
|
||||||
@ -42,5 +43,65 @@ func Funcs(codecs runtimeserializer.CodecFactory) []interface{} {
|
|||||||
obj.Names.ListKind = obj.Names.Kind + "List"
|
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
|
Version string
|
||||||
// Names are the names used to describe this custom resource
|
// Names are the names used to describe this custom resource
|
||||||
Names CustomResourceDefinitionNames
|
Names CustomResourceDefinitionNames
|
||||||
|
|
||||||
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
||||||
Scope ResourceScope
|
Scope ResourceScope
|
||||||
|
// Validation describes the validation methods for CustomResources
|
||||||
|
Validation *CustomResourceValidation
|
||||||
}
|
}
|
||||||
|
|
||||||
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
||||||
@ -139,3 +140,9 @@ type CustomResourceDefinitionList struct {
|
|||||||
// Items individual CustomResourceDefinitions
|
// Items individual CustomResourceDefinitions
|
||||||
Items []CustomResourceDefinition
|
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(
|
load(
|
||||||
"@io_bazel_rules_go//go:def.bzl",
|
"@io_bazel_rules_go//go:def.bzl",
|
||||||
"go_library",
|
"go_library",
|
||||||
|
"go_test",
|
||||||
)
|
)
|
||||||
|
|
||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"conversion.go",
|
||||||
|
"deepcopy.go",
|
||||||
"defaults.go",
|
"defaults.go",
|
||||||
"doc.go",
|
"doc.go",
|
||||||
"generated.pb.go",
|
"generated.pb.go",
|
||||||
|
"marshal.go",
|
||||||
"register.go",
|
"register.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
|
"types_jsonschema.go",
|
||||||
"zz_generated.conversion.go",
|
"zz_generated.conversion.go",
|
||||||
"zz_generated.deepcopy.go",
|
"zz_generated.deepcopy.go",
|
||||||
"zz_generated.defaults.go",
|
"zz_generated.defaults.go",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/gogo/protobuf/proto:go_default_library",
|
"//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/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/conversion:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime: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/runtime/schema:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,3 +52,16 @@ filegroup(
|
|||||||
srcs = ["generated.proto"],
|
srcs = ["generated.proto"],
|
||||||
visibility = ["//visibility:public"],
|
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
|
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
||||||
optional string scope = 4;
|
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
|
// CustomResourceDefinitionStatus indicates the state of the CustomResourceDefinition
|
||||||
@ -115,3 +120,120 @@ message CustomResourceDefinitionStatus {
|
|||||||
optional CustomResourceDefinitionNames acceptedNames = 2;
|
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 (
|
var (
|
||||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
|
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs, addConversionFuncs)
|
||||||
localSchemeBuilder = &SchemeBuilder
|
localSchemeBuilder = &SchemeBuilder
|
||||||
AddToScheme = localSchemeBuilder.AddToScheme
|
AddToScheme = localSchemeBuilder.AddToScheme
|
||||||
)
|
)
|
||||||
@ -52,3 +52,10 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
|||||||
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
|
||||||
return nil
|
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"`
|
Version string `json:"version" protobuf:"bytes,2,opt,name=version"`
|
||||||
// Names are the names used to describe this custom resource
|
// Names are the names used to describe this custom resource
|
||||||
Names CustomResourceDefinitionNames `json:"names" protobuf:"bytes,3,opt,name=names"`
|
Names CustomResourceDefinitionNames `json:"names" protobuf:"bytes,3,opt,name=names"`
|
||||||
|
|
||||||
// Scope indicates whether this resource is cluster or namespace scoped. Default is namespaced
|
// 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"`
|
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
|
// CustomResourceDefinitionNames indicates the names to serve this CustomResourceDefinition
|
||||||
@ -139,3 +142,9 @@ type CustomResourceDefinitionList struct {
|
|||||||
// Items individual CustomResourceDefinitions
|
// Items individual CustomResourceDefinitions
|
||||||
Items []CustomResourceDefinition `json:"items" protobuf:"bytes,2,rep,name=items"`
|
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_apiextensions_CustomResourceDefinitionSpec_To_v1beta1_CustomResourceDefinitionSpec,
|
||||||
Convert_v1beta1_CustomResourceDefinitionStatus_To_apiextensions_CustomResourceDefinitionStatus,
|
Convert_v1beta1_CustomResourceDefinitionStatus_To_apiextensions_CustomResourceDefinitionStatus,
|
||||||
Convert_apiextensions_CustomResourceDefinitionStatus_To_v1beta1_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 {
|
func autoConvert_v1beta1_CustomResourceDefinitionList_To_apiextensions_CustomResourceDefinitionList(in *CustomResourceDefinitionList, out *apiextensions.CustomResourceDefinitionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
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
|
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 {
|
func autoConvert_apiextensions_CustomResourceDefinitionList_To_v1beta1_CustomResourceDefinitionList(in *apiextensions.CustomResourceDefinitionList, out *CustomResourceDefinitionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +201,15 @@ func autoConvert_v1beta1_CustomResourceDefinitionSpec_To_apiextensions_CustomRes
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Scope = apiextensions.ResourceScope(in.Scope)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,6 +225,15 @@ func autoConvert_apiextensions_CustomResourceDefinitionSpec_To_v1beta1_CustomRes
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
out.Scope = ResourceScope(in.Scope)
|
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
|
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 {
|
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)
|
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))
|
in.(*CustomResourceDefinitionStatus).DeepCopyInto(out.(*CustomResourceDefinitionStatus))
|
||||||
return nil
|
return nil
|
||||||
}, InType: reflect.TypeOf(&CustomResourceDefinitionStatus{})},
|
}, 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) {
|
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
in.Names.DeepCopyInto(&out.Names)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,3 +241,159 @@ func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionSt
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return 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",
|
name = "go_default_library",
|
||||||
srcs = ["validation.go"],
|
srcs = ["validation.go"],
|
||||||
deps = [
|
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/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/api/validation:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/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/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
|
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -20,10 +20,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
"github.com/go-openapi/spec"
|
||||||
|
|
||||||
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
genericvalidation "k8s.io/apimachinery/pkg/api/validation"
|
||||||
validationutil "k8s.io/apimachinery/pkg/util/validation"
|
validationutil "k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"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
|
// ValidateCustomResourceDefinition statically validates
|
||||||
@ -100,6 +105,12 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
|
|||||||
|
|
||||||
allErrs = append(allErrs, ValidateCustomResourceDefinitionNames(&spec.Names, fldPath.Child("names"))...)
|
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
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,3 +169,162 @@ func ValidateCustomResourceDefinitionNames(names *apiextensions.CustomResourceDe
|
|||||||
|
|
||||||
return allErrs
|
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))
|
in.(*CustomResourceDefinitionStatus).DeepCopyInto(out.(*CustomResourceDefinitionStatus))
|
||||||
return nil
|
return nil
|
||||||
}, InType: reflect.TypeOf(&CustomResourceDefinitionStatus{})},
|
}, 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) {
|
func (in *CustomResourceDefinitionSpec) DeepCopyInto(out *CustomResourceDefinitionSpec) {
|
||||||
*out = *in
|
*out = *in
|
||||||
in.Names.DeepCopyInto(&out.Names)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,3 +237,138 @@ func (in *CustomResourceDefinitionStatus) DeepCopy() *CustomResourceDefinitionSt
|
|||||||
in.DeepCopyInto(out)
|
in.DeepCopyInto(out)
|
||||||
return 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",
|
"customresource_handler.go",
|
||||||
],
|
],
|
||||||
deps = [
|
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/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:go_default_library",
|
||||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install: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/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/clientset:go_default_library",
|
||||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/internalclientset: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",
|
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions:go_default_library",
|
||||||
@ -68,6 +72,9 @@ filegroup(
|
|||||||
|
|
||||||
filegroup(
|
filegroup(
|
||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [":package-srcs"],
|
srcs = [
|
||||||
|
":package-srcs",
|
||||||
|
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/validation:all-srcs",
|
||||||
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
)
|
)
|
||||||
|
@ -171,6 +171,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
|
|||||||
groupDiscoveryHandler,
|
groupDiscoveryHandler,
|
||||||
s.GenericAPIServer.RequestContextMapper(),
|
s.GenericAPIServer.RequestContextMapper(),
|
||||||
s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions().Lister(),
|
s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions().Lister(),
|
||||||
|
s.Informers.Apiextensions().InternalVersion().CustomResourceDefinitions(),
|
||||||
delegateHandler,
|
delegateHandler,
|
||||||
c.CRDRESTOptionsGetter,
|
c.CRDRESTOptionsGetter,
|
||||||
c.GenericConfig.AdmissionControl,
|
c.GenericConfig.AdmissionControl,
|
||||||
|
@ -26,6 +26,11 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"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"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -44,8 +49,11 @@ import (
|
|||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||||
"k8s.io/client-go/discovery"
|
"k8s.io/client-go/discovery"
|
||||||
|
cache "k8s.io/client-go/tools/cache"
|
||||||
|
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
"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"
|
listers "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/internalversion"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/controller/finalizer"
|
"k8s.io/apiextensions-apiserver/pkg/controller/finalizer"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/registry/customresource"
|
"k8s.io/apiextensions-apiserver/pkg/registry/customresource"
|
||||||
@ -84,6 +92,7 @@ func NewCustomResourceDefinitionHandler(
|
|||||||
groupDiscoveryHandler *groupDiscoveryHandler,
|
groupDiscoveryHandler *groupDiscoveryHandler,
|
||||||
requestContextMapper apirequest.RequestContextMapper,
|
requestContextMapper apirequest.RequestContextMapper,
|
||||||
crdLister listers.CustomResourceDefinitionLister,
|
crdLister listers.CustomResourceDefinitionLister,
|
||||||
|
crdInformer informers.CustomResourceDefinitionInformer,
|
||||||
delegate http.Handler,
|
delegate http.Handler,
|
||||||
restOptionsGetter generic.RESTOptionsGetter,
|
restOptionsGetter generic.RESTOptionsGetter,
|
||||||
admission admission.Interface) *crdHandler {
|
admission admission.Interface) *crdHandler {
|
||||||
@ -98,6 +107,10 @@ func NewCustomResourceDefinitionHandler(
|
|||||||
admission: admission,
|
admission: admission,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crdInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||||
|
UpdateFunc: ret.updateCustomResourceDefinition,
|
||||||
|
})
|
||||||
|
|
||||||
ret.customStorage.Store(crdStorageMap{})
|
ret.customStorage.Store(crdStorageMap{})
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
@ -155,7 +168,12 @@ func (r *crdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
terminating := apiextensions.IsCRDConditionTrue(crd, apiextensions.Terminating)
|
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
|
storage := crdInfo.storage
|
||||||
requestScope := crdInfo.requestScope
|
requestScope := crdInfo.requestScope
|
||||||
minRequestTimeout := 1 * time.Minute
|
minRequestTimeout := 1 * time.Minute
|
||||||
@ -250,15 +268,18 @@ func (r *crdHandler) removeDeadStorage() {
|
|||||||
// GetCustomResourceListerCollectionDeleter returns the ListerCollectionDeleter for
|
// GetCustomResourceListerCollectionDeleter returns the ListerCollectionDeleter for
|
||||||
// the given uid, or nil if one does not exist.
|
// the given uid, or nil if one does not exist.
|
||||||
func (r *crdHandler) GetCustomResourceListerCollectionDeleter(crd *apiextensions.CustomResourceDefinition) finalizer.ListerCollectionDeleter {
|
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
|
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)
|
storageMap := r.customStorage.Load().(crdStorageMap)
|
||||||
ret, ok := storageMap[crd.UID]
|
ret, ok := storageMap[crd.UID]
|
||||||
if ok {
|
if ok {
|
||||||
return ret
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
r.customStorageLock.Lock()
|
r.customStorageLock.Lock()
|
||||||
@ -266,7 +287,7 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
|
|||||||
|
|
||||||
ret, ok = storageMap[crd.UID]
|
ret, ok = storageMap[crd.UID]
|
||||||
if ok {
|
if ok {
|
||||||
return ret
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// In addition to Unstructured objects (Custom Resources), we also may sometimes need to
|
// 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),
|
unstructuredTyper: discovery.NewUnstructuredObjectTyper(nil),
|
||||||
}
|
}
|
||||||
creator := unstructuredCreator{}
|
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(
|
storage := customresource.NewREST(
|
||||||
schema.GroupResource{Group: crd.Spec.Group, Resource: crd.Spec.Names.Plural},
|
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},
|
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,
|
typer,
|
||||||
crd.Spec.Scope == apiextensions.NamespaceScoped,
|
crd.Spec.Scope == apiextensions.NamespaceScoped,
|
||||||
kind,
|
kind,
|
||||||
|
validator,
|
||||||
),
|
),
|
||||||
r.restOptionsGetter,
|
r.restOptionsGetter,
|
||||||
)
|
)
|
||||||
@ -354,7 +387,27 @@ func (r *crdHandler) getServingInfoFor(crd *apiextensions.CustomResourceDefiniti
|
|||||||
|
|
||||||
storageMap2[crd.UID] = ret
|
storageMap2[crd.UID] = ret
|
||||||
r.customStorage.Store(storageMap2)
|
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 {
|
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",
|
"strategy.go",
|
||||||
],
|
],
|
||||||
deps = [
|
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/meta:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/validation:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
@ -19,9 +19,12 @@ package customresource
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-openapi/validate"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/api/validation"
|
"k8s.io/apimachinery/pkg/api/validation"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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/fields"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -30,6 +33,8 @@ import (
|
|||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
|
|
||||||
|
apiservervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
type customResourceDefinitionStorageStrategy struct {
|
type customResourceDefinitionStorageStrategy struct {
|
||||||
@ -40,7 +45,7 @@ type customResourceDefinitionStorageStrategy struct {
|
|||||||
validator customResourceValidator
|
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{
|
return customResourceDefinitionStorageStrategy{
|
||||||
ObjectTyper: typer,
|
ObjectTyper: typer,
|
||||||
NameGenerator: names.SimpleNameGenerator,
|
NameGenerator: names.SimpleNameGenerator,
|
||||||
@ -48,6 +53,7 @@ func NewStrategy(typer runtime.ObjectTyper, namespaceScoped bool, kind schema.Gr
|
|||||||
validator: customResourceValidator{
|
validator: customResourceValidator{
|
||||||
namespaceScoped: namespaceScoped,
|
namespaceScoped: namespaceScoped,
|
||||||
kind: kind,
|
kind: kind,
|
||||||
|
validator: validator,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,6 +119,7 @@ func (a customResourceDefinitionStorageStrategy) MatchCustomResourceDefinitionSt
|
|||||||
type customResourceValidator struct {
|
type customResourceValidator struct {
|
||||||
namespaceScoped bool
|
namespaceScoped bool
|
||||||
kind schema.GroupVersionKind
|
kind schema.GroupVersionKind
|
||||||
|
validator *validate.SchemaValidator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a customResourceValidator) Validate(ctx genericapirequest.Context, obj runtime.Object) field.ErrorList {
|
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))}
|
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"))
|
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))}
|
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"))
|
return validation.ValidateObjectMetaAccessorUpdate(objAccessor, oldAccessor, field.NewPath("metadata"))
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
"//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/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/equality:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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:go_default_library",
|
||||||
"//vendor/k8s.io/apiserver/pkg/storage/errors: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/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/registry/generic"
|
||||||
"k8s.io/apiserver/pkg/storage"
|
"k8s.io/apiserver/pkg/storage"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"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"
|
||||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
|
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
|
||||||
|
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||||
)
|
)
|
||||||
|
|
||||||
type strategy struct {
|
type strategy struct {
|
||||||
@ -50,6 +52,11 @@ func (strategy) PrepareForCreate(ctx genericapirequest.Context, obj runtime.Obje
|
|||||||
crd := obj.(*apiextensions.CustomResourceDefinition)
|
crd := obj.(*apiextensions.CustomResourceDefinition)
|
||||||
crd.Status = apiextensions.CustomResourceDefinitionStatus{}
|
crd.Status = apiextensions.CustomResourceDefinitionStatus{}
|
||||||
crd.Generation = 1
|
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) {
|
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) {
|
if !apiequality.Semantic.DeepEqual(oldCRD.Spec, newCRD.Spec) {
|
||||||
newCRD.Generation = oldCRD.Generation + 1
|
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 {
|
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/runtime:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/wait: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/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",
|
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -213,7 +213,7 @@ func checkForWatchCachePrimed(crd *apiextensionsv1beta1.CustomResourceDefinition
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceName := "foo"
|
instanceName := "setup-instance"
|
||||||
instance := &unstructured.Unstructured{
|
instance := &unstructured.Unstructured{
|
||||||
Object: map[string]interface{}{
|
Object: map[string]interface{}{
|
||||||
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
"apiVersion": crd.Spec.Group + "/" + crd.Spec.Version,
|
||||||
@ -222,6 +222,11 @@ func checkForWatchCachePrimed(crd *apiextensionsv1beta1.CustomResourceDefinition
|
|||||||
"namespace": ns,
|
"namespace": ns,
|
||||||
"name": instanceName,
|
"name": instanceName,
|
||||||
},
|
},
|
||||||
|
"alpha": "foo_123",
|
||||||
|
"beta": 10,
|
||||||
|
"gamma": "bar",
|
||||||
|
"delta": "hello",
|
||||||
|
"epsilon": "foobar",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if _, err := resourceClient.Create(instance); err != nil {
|
if _, err := resourceClient.Create(instance); err != nil {
|
||||||
|
@ -19,10 +19,15 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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"
|
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
"k8s.io/apiextensions-apiserver/test/integration/testserver"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestForProperValidationErrors(t *testing.T) {
|
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
|
// // alpha: v1.4
|
||||||
// MyFeature() bool
|
// MyFeature() bool
|
||||||
|
|
||||||
// owner: tallclair
|
// owner: @tallclair
|
||||||
// alpha: v1.5
|
// alpha: v1.5
|
||||||
//
|
//
|
||||||
// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
|
// StreamingProxyRedirects controls whether the apiserver should intercept (and follow)
|
||||||
// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
|
// redirects from the backend (Kubelet) for streaming requests (exec/attach/port-forward).
|
||||||
StreamingProxyRedirects utilfeature.Feature = "StreamingProxyRedirects"
|
StreamingProxyRedirects utilfeature.Feature = "StreamingProxyRedirects"
|
||||||
|
|
||||||
// owner: tallclair
|
// owner: @tallclair
|
||||||
// alpha: v1.7
|
// alpha: v1.7
|
||||||
//
|
//
|
||||||
// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
|
// AdvancedAuditing enables a much more general API auditing pipeline, which includes support for
|
||||||
|
Loading…
Reference in New Issue
Block a user