mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
Conformance tests for server side field validation
This commit is contained in:
parent
2ca95b4df9
commit
f45505d19a
28
test/conformance/testdata/conformance.yaml
vendored
28
test/conformance/testdata/conformance.yaml
vendored
@ -3264,4 +3264,32 @@
|
||||
was configured with a subpath.
|
||||
release: v1.12
|
||||
file: test/e2e/storage/subpath.go
|
||||
- testname: 'Server side field validation, typed object'
|
||||
codename: '[sig-api-machinery] Field validation should detect unknown/duplicate fields [Conformance]'
|
||||
description: It should reject the request if a typed object has unknown or duplicate fields.
|
||||
release: v1.27
|
||||
- testname: 'Server side field validation, typed unknown metadata'
|
||||
codename: '[sig-api-machinery] Field validation should detect unknown metadata fields [Conformance]'
|
||||
description: It should reject the request if a typed object has unknown fields in the metadata.
|
||||
release: v1.27
|
||||
- testname: 'Server side field validation, valid CR with validation schema'
|
||||
codename: '[sig-api-machinery] Field validation should allow valid CRs for CRDs with validation schema [Conformance]'
|
||||
description: When a CRD has a validation schema, it should succeed when a valid CR is applied.
|
||||
release: v1.27
|
||||
- testname: 'Server side field validation, unknown fields CR no validation schema'
|
||||
codename: '[sig-api-machinery] Field validation should allow CRs with unknown fields for CRDs without validation schema [Conformance]'
|
||||
description: When a CRD does not have a validation schema, it should succeed when a CR with unknown fields is applied.
|
||||
release: v1.27
|
||||
- testname: 'Server side field validation, unknown fields CR fails validation'
|
||||
codename: '[sig-api-machinery] Field validation should reject CRs with unknown fields for CRDs with validation schema [Conformance]'
|
||||
description: When a CRD does have a validation schema, it should reject CRs with unknown fields.
|
||||
release: v1.27
|
||||
- testname: 'Server side field validation, unknown metadata'
|
||||
codename: '[sig-api-machinery] Field validation should reject CRs with unknown metadata [Conformance]'
|
||||
description: The server should reject CRs with unknown metadata fields in both the root and embedded objects of a CR.
|
||||
release: v1.27
|
||||
- testname: 'Server side field validation, CR duplicates'
|
||||
codename: '[sig-api-machinery] Field validation should reject CRs with duplicate fields [Conformance]'
|
||||
description: The server should reject CRs with duplicate fields even when preserving unknown fields.
|
||||
release: v1.27
|
||||
|
||||
|
725
test/e2e/apimachinery/field_validation.go
Normal file
725
test/e2e/apimachinery/field_validation.go
Normal file
@ -0,0 +1,725 @@
|
||||
/*
|
||||
Copyright 2023 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 apimachinery
|
||||
|
||||
import (
|
||||
// ensure libs have a chance to initialize
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/onsi/ginkgo/v2"
|
||||
_ "github.com/stretchr/testify/assert"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/dynamic"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
admissionapi "k8s.io/pod-security-admission/api"
|
||||
)
|
||||
|
||||
var _ = SIGDescribe("FieldValidation", func() {
|
||||
f := framework.NewDefaultFramework("field-validation")
|
||||
f.NamespacePodSecurityEnforceLevel = admissionapi.LevelBaseline
|
||||
|
||||
var client clientset.Interface
|
||||
var ns string
|
||||
|
||||
ginkgo.BeforeEach(func() {
|
||||
client = f.ClientSet
|
||||
ns = f.Namespace.Name
|
||||
})
|
||||
|
||||
ginkgo.AfterEach(func(ctx context.Context) {
|
||||
_ = client.AppsV1().Deployments(ns).Delete(ctx, "deployment", metav1.DeleteOptions{})
|
||||
_ = client.AppsV1().Deployments(ns).Delete(ctx, "deployment-shared-unset", metav1.DeleteOptions{})
|
||||
_ = client.AppsV1().Deployments(ns).Delete(ctx, "deployment-shared-map-item-removal", metav1.DeleteOptions{})
|
||||
_ = client.CoreV1().Pods(ns).Delete(ctx, "test-pod", metav1.DeleteOptions{})
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, typed object
|
||||
Description: It should reject the request if a typed object has unknown or duplicate fields.
|
||||
*/
|
||||
framework.ConformanceIt("should detect unknown and duplicate fields of a typed object", func(ctx context.Context) {
|
||||
ginkgo.By("apply creating a deployment")
|
||||
invalidMetaDeployment := `{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": "my-dep",
|
||||
"labels": {"app": "nginx"}
|
||||
},
|
||||
"spec": {
|
||||
"unknownField": "foo",
|
||||
"replicas": 2,
|
||||
"replicas": 3,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
_, err := client.CoreV1().RESTClient().Post().
|
||||
AbsPath("/apis/apps/v1").
|
||||
Namespace(ns).
|
||||
Resource("deployments").
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body([]byte(invalidMetaDeployment)).
|
||||
Do(ctx).
|
||||
Get()
|
||||
if !(strings.Contains(err.Error(), `strict decoding error: unknown field "spec.unknownField", duplicate field "spec.replicas"`)) {
|
||||
framework.Failf("error missing unknown/duplicate field field, got: %v", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, typed unknown metadata
|
||||
Description: It should reject the request if a typed object has unknown fields in the metadata.
|
||||
*/
|
||||
framework.ConformanceIt("should detect unknown metadata fields of a typed object", func(ctx context.Context) {
|
||||
ginkgo.By("apply creating a deployment")
|
||||
invalidMetaDeployment := `{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": "my-dep",
|
||||
"unknownMeta": "foo",
|
||||
"labels": {"app": "nginx"}
|
||||
},
|
||||
"spec": {
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"app": "nginx"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [{
|
||||
"name": "nginx",
|
||||
"image": "nginx:latest"
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
_, err := client.CoreV1().RESTClient().Post().
|
||||
AbsPath("/apis/apps/v1").
|
||||
Namespace(ns).
|
||||
Resource("deployments").
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body([]byte(invalidMetaDeployment)).
|
||||
Do(ctx).
|
||||
Get()
|
||||
if !(strings.Contains(err.Error(), `strict decoding error: unknown field "metadata.unknownMeta"`)) {
|
||||
framework.Failf("error missing unknown metadata field, got: %v", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, valid CR with validation schema
|
||||
Description: When a CRD has a validation schema, it should succeed when a valid CR is applied.
|
||||
*/
|
||||
framework.ConformanceIt("should create/apply a valid CR for CRD with validation schema", func(ctx context.Context) {
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
|
||||
noxuDefinition := fixtures.NewRandomNameMultipleVersionCustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||
|
||||
var c apiextensionsv1.CustomResourceValidation
|
||||
err = json.Unmarshal([]byte(`{
|
||||
"openAPIV3Schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"spec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
},
|
||||
"cronSpec": {
|
||||
"type": "string",
|
||||
"pattern": "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$"
|
||||
},
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"x-kubernetes-list-map-keys": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"x-kubernetes-list-type": "map",
|
||||
"items": {
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`), &c)
|
||||
if err != nil {
|
||||
framework.Failf("%v", err)
|
||||
}
|
||||
for i := range noxuDefinition.Spec.Versions {
|
||||
noxuDefinition.Spec.Versions[i].Schema = &c
|
||||
}
|
||||
|
||||
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("cannot create crd %s", err)
|
||||
}
|
||||
|
||||
kind := noxuDefinition.Spec.Names.Kind
|
||||
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
|
||||
name := "mytest"
|
||||
|
||||
rest := apiExtensionClient.Discovery().RESTClient()
|
||||
yamlBody := []byte(fmt.Sprintf(`
|
||||
apiVersion: %s
|
||||
kind: %s
|
||||
metadata:
|
||||
name: %s
|
||||
finalizers:
|
||||
- test-finalizer
|
||||
spec:
|
||||
foo: foo1
|
||||
cronSpec: "* * * * */5"
|
||||
ports:
|
||||
- name: x
|
||||
containerPort: 80
|
||||
protocol: TCP`, apiVersion, kind, name))
|
||||
_, err = rest.Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||
Name(name).
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body(yamlBody).
|
||||
DoRaw(ctx)
|
||||
if err != nil {
|
||||
framework.Failf("%v", err)
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, unknown fields CR no validation schema
|
||||
Description: When a CRD does not have a validation schema, it should succeed when a CR with unknown fields is applied.
|
||||
*/
|
||||
framework.ConformanceIt("should create/apply a CR with unknown fields for CRD with no validation schema", func(ctx context.Context) {
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
|
||||
noxuDefinition := fixtures.NewRandomNameMultipleVersionCustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||
|
||||
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("cannot create crd %s", err)
|
||||
}
|
||||
|
||||
kind := noxuDefinition.Spec.Names.Kind
|
||||
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
|
||||
name := "mytest"
|
||||
|
||||
rest := apiExtensionClient.Discovery().RESTClient()
|
||||
yamlBody := []byte(fmt.Sprintf(`
|
||||
apiVersion: %s
|
||||
kind: %s
|
||||
metadata:
|
||||
name: %s
|
||||
finalizers:
|
||||
- test-finalizer
|
||||
spec:
|
||||
unknown: uk1
|
||||
cronSpec: "* * * * */5"
|
||||
ports:
|
||||
- name: x
|
||||
containerPort: 80
|
||||
protocol: TCP`, apiVersion, kind, name))
|
||||
_, err = rest.Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||
Name(name).
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body(yamlBody).
|
||||
DoRaw(ctx)
|
||||
if err != nil {
|
||||
framework.Failf("%v", err)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, unknown fields CR fails validation
|
||||
Description: When a CRD does have a validation schema, it should reject CRs with unknown fields.
|
||||
*/
|
||||
framework.ConformanceIt("should create/apply an invalid CR with extra properties for CRD with validation schema", func(ctx context.Context) {
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
|
||||
noxuDefinition := fixtures.NewRandomNameMultipleVersionCustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||
|
||||
var c apiextensionsv1.CustomResourceValidation
|
||||
err = json.Unmarshal([]byte(`{
|
||||
"openAPIV3Schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"spec": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
},
|
||||
"cronSpec": {
|
||||
"type": "string",
|
||||
"pattern": "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$"
|
||||
},
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"x-kubernetes-list-map-keys": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"x-kubernetes-list-type": "map",
|
||||
"items": {
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`), &c)
|
||||
if err != nil {
|
||||
framework.Failf("%v", err)
|
||||
}
|
||||
klog.Warningf("props: %v\n", c.OpenAPIV3Schema)
|
||||
for i := range noxuDefinition.Spec.Versions {
|
||||
noxuDefinition.Spec.Versions[i].Schema = &c
|
||||
}
|
||||
|
||||
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("cannot create crd %s", err)
|
||||
}
|
||||
|
||||
kind := noxuDefinition.Spec.Names.Kind
|
||||
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
|
||||
name := "mytest"
|
||||
|
||||
rest := apiExtensionClient.Discovery().RESTClient()
|
||||
yamlBody := []byte(fmt.Sprintf(`
|
||||
apiVersion: %s
|
||||
kind: %s
|
||||
metadata:
|
||||
name: %s
|
||||
finalizers:
|
||||
- test-finalizer
|
||||
unknownField: unknown
|
||||
spec:
|
||||
foo: foo1
|
||||
cronSpec: "* * * * */5"
|
||||
ports:
|
||||
- name: x
|
||||
containerPort: 80
|
||||
protocol: TCP`, apiVersion, kind, name))
|
||||
result, err := rest.Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||
Name(name).
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body(yamlBody).
|
||||
DoRaw(ctx)
|
||||
if !(strings.Contains(string(result), `.unknownField: field not declared in schema`)) {
|
||||
framework.Failf("error missing unknown field: %v:\n%v", err, string(result))
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, unknown metadata
|
||||
Description: The server should reject CRs with unknown metadata fields in both the root and embedded objects
|
||||
of a CR.
|
||||
*/
|
||||
framework.ConformanceIt("should detect unknown metadata fields in both the root and embedded object of a CR", func(ctx context.Context) {
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
|
||||
noxuDefinition := fixtures.NewRandomNameMultipleVersionCustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||
|
||||
var c apiextensionsv1.CustomResourceValidation
|
||||
err = json.Unmarshal([]byte(`{
|
||||
"openAPIV3Schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"spec": {
|
||||
"type": "object",
|
||||
"x-kubernetes-preserve-unknown-fields": true,
|
||||
"properties": {
|
||||
"template": {
|
||||
"type": "object",
|
||||
"x-kubernetes-embedded-resource": true,
|
||||
"properties": {
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
"foo": {
|
||||
"type": "string"
|
||||
},
|
||||
"cronSpec": {
|
||||
"type": "string",
|
||||
"pattern": "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$"
|
||||
},
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"x-kubernetes-list-map-keys": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"x-kubernetes-list-type": "map",
|
||||
"items": {
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`), &c)
|
||||
if err != nil {
|
||||
framework.Failf("%v", err)
|
||||
}
|
||||
for i := range noxuDefinition.Spec.Versions {
|
||||
noxuDefinition.Spec.Versions[i].Schema = &c
|
||||
}
|
||||
|
||||
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("cannot create crd %s", err)
|
||||
}
|
||||
|
||||
kind := noxuDefinition.Spec.Names.Kind
|
||||
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
|
||||
name := "mytest"
|
||||
|
||||
rest := apiExtensionClient.Discovery().RESTClient()
|
||||
yamlBody := []byte(fmt.Sprintf(`
|
||||
apiVersion: %s
|
||||
kind: %s
|
||||
metadata:
|
||||
name: %s
|
||||
unknownMeta: unknown
|
||||
finalizers:
|
||||
- test-finalizer
|
||||
spec:
|
||||
template:
|
||||
apiversion: foo/v1
|
||||
kind: Sub
|
||||
metadata:
|
||||
unknownSubMeta: unknown
|
||||
name: subobject
|
||||
namespace: %s
|
||||
foo: foo1
|
||||
cronSpec: "* * * * */5"
|
||||
ports:
|
||||
- name: x
|
||||
containerPort: 80
|
||||
protocol: TCP`, apiVersion, kind, name, ns))
|
||||
result, err := rest.Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||
Name(name).
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body(yamlBody).
|
||||
DoRaw(ctx)
|
||||
if !(strings.Contains(string(result), `.spec.template.metadata.unknownSubMeta: field not declared in schema`) || strings.Contains(string(result), `.metadata.unknownMeta: field not declared in schema`)) {
|
||||
framework.Failf("error missing duplicate field: %v:\n%v", err, string(result))
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
Release: v1.27
|
||||
Testname: Server side field validation, CR duplicates
|
||||
Description: The server should reject CRs with duplicate fields even when preserving unknown fields.
|
||||
*/
|
||||
framework.ConformanceIt("should detect duplicates in a CR when preserving unknown fields", func(ctx context.Context) {
|
||||
config, err := framework.LoadConfig()
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
|
||||
noxuDefinition := fixtures.NewRandomNameMultipleVersionCustomResourceDefinition(apiextensionsv1.ClusterScoped)
|
||||
|
||||
var c apiextensionsv1.CustomResourceValidation
|
||||
err = json.Unmarshal([]byte(`{
|
||||
"openAPIV3Schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"spec": {
|
||||
"type": "object",
|
||||
"x-kubernetes-preserve-unknown-fields": true,
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
},
|
||||
"cronSpec": {
|
||||
"type": "string",
|
||||
"pattern": "^(\\d+|\\*)(/\\d+)?(\\s+(\\d+|\\*)(/\\d+)?){4}$"
|
||||
},
|
||||
"ports": {
|
||||
"type": "array",
|
||||
"x-kubernetes-list-map-keys": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"x-kubernetes-list-type": "map",
|
||||
"items": {
|
||||
"properties": {
|
||||
"containerPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"hostIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"hostPort": {
|
||||
"format": "int32",
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"containerPort",
|
||||
"protocol"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}`), &c)
|
||||
if err != nil {
|
||||
framework.Failf("%s", err)
|
||||
}
|
||||
for i := range noxuDefinition.Spec.Versions {
|
||||
noxuDefinition.Spec.Versions[i].Schema = &c
|
||||
}
|
||||
|
||||
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
|
||||
if err != nil {
|
||||
framework.Failf("cannot create crd %s", err)
|
||||
}
|
||||
|
||||
kind := noxuDefinition.Spec.Names.Kind
|
||||
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
|
||||
name := "mytest"
|
||||
|
||||
rest := apiExtensionClient.Discovery().RESTClient()
|
||||
yamlBody := []byte(fmt.Sprintf(`
|
||||
apiVersion: %s
|
||||
kind: %s
|
||||
metadata:
|
||||
name: %s
|
||||
finalizers:
|
||||
- test-finalizer
|
||||
spec:
|
||||
unknown: uk1
|
||||
foo: foo1
|
||||
foo: foo2
|
||||
cronSpec: "* * * * */5"
|
||||
ports:
|
||||
- name: x
|
||||
containerPort: 80
|
||||
protocol: TCP`, apiVersion, kind, name))
|
||||
result, err := rest.Patch(types.ApplyPatchType).
|
||||
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
|
||||
Name(name).
|
||||
Param("fieldManager", "field_validation_mgr").
|
||||
Param("fieldValidation", "Strict").
|
||||
Body(yamlBody).
|
||||
DoRaw(ctx)
|
||||
if !(strings.Contains(string(result), `line 11: key \"foo\" already set in map`)) {
|
||||
framework.Failf("error missing duplicate field: %v:\n%v", err, string(result))
|
||||
}
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue
Block a user