diff --git a/staging/src/k8s.io/apiextensions-apiserver/test/integration/validation_test.go b/staging/src/k8s.io/apiextensions-apiserver/test/integration/validation_test.go index a25f9f3b813..38b41ffb6db 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/test/integration/validation_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/test/integration/validation_test.go @@ -27,6 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/yaml" @@ -780,21 +781,25 @@ spec: if v := "spec.versions[0].schema.openAPIV3Schema.properties[a].type: Required value: must not be empty for specified object fields"; !strings.Contains(cond.Message, v) { t.Fatalf("expected violation %q, but got: %v", v, cond.Message) } + if v := "spec.preserveUnknownFields: Invalid value: true: must be false"; !strings.Contains(cond.Message, v) { + t.Fatalf("expected violation %q, but got: %v", v, cond.Message) + } // remove schema t.Log("Remove schema") for retry := 0; retry < 5; retry++ { - crd, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{}) - if err != nil { - t.Fatalf("unexpected get error: %v", err) - } - crd.Spec.Validation = nil - if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{}); apierrors.IsConflict(err) { + // This patch fixes two fields to resolve + // 1. property type validation error + // 2. preserveUnknownFields validation error + patch := []byte("[{\"op\":\"add\",\"path\":\"/spec/validation/openAPIV3Schema/properties/a/type\",\"value\":\"int\"}," + + "{\"op\":\"replace\",\"path\":\"/spec/preserveUnknownFields\",\"value\":false}]") + if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Patch(context.TODO(), name, types.JSONPatchType, patch, metav1.PatchOptions{}); apierrors.IsConflict(err) { continue } if err != nil { t.Fatalf("unexpected update error: %v", err) } + break } if err != nil { t.Fatalf("unexpected update error: %v", err) @@ -821,6 +826,7 @@ spec: if err != nil { t.Fatalf("unexpected get error: %v", err) } + crd.Spec.PreserveUnknownFields = nil crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{OpenAPIV3Schema: origSchema} if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{}); apierrors.IsConflict(err) { continue @@ -828,6 +834,7 @@ spec: if err != nil { t.Fatalf("unexpected update error: %v", err) } + break } if err != nil { t.Fatalf("unexpected update error: %v", err) @@ -849,6 +856,9 @@ spec: if v := "spec.versions[0].schema.openAPIV3Schema.properties[a].type: Required value: must not be empty for specified object fields"; !strings.Contains(cond.Message, v) { t.Fatalf("expected violation %q, but got: %v", v, cond.Message) } + if v := "spec.preserveUnknownFields: Invalid value: true: must be false"; !strings.Contains(cond.Message, v) { + t.Fatalf("expected violation %q, but got: %v", v, cond.Message) + } } func TestNonStructuralSchemaCondition(t *testing.T) { @@ -862,6 +872,7 @@ func TestNonStructuralSchemaCondition(t *testing.T) { apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition spec: + preserveUnknownFields: PRESERVE_UNKNOWN_FIELDS version: v1beta1 names: plural: foos @@ -882,6 +893,7 @@ spec: type Test struct { desc string + preserveUnknownFields string globalSchema, v1Schema, v1beta1Schema string expectedCreateErrors []string unexpectedCreateErrors []string @@ -889,7 +901,19 @@ spec: unexpectedViolations []string } tests := []Test{ - {"empty", "", "", "", nil, nil, nil, nil}, + { + desc: "empty", + expectedViolations: []string{ + "spec.preserveUnknownFields: Invalid value: true: must be false", + }, + }, + { + desc: "preserve unknown fields is false", + preserveUnknownFields: "false", + globalSchema: ` +type: object +`, + }, { desc: "int-or-string and preserve-unknown-fields true", globalSchema: ` @@ -922,7 +946,8 @@ x-kubernetes-embedded-resource: true }, }, { - desc: "embedded-resource without preserve-unknown-fields, but properties", + desc: "embedded-resource without preserve-unknown-fields, but properties", + preserveUnknownFields: "false", globalSchema: ` type: object x-kubernetes-embedded-resource: true @@ -934,16 +959,15 @@ properties: metadata: type: object `, - expectedViolations: []string{}, }, { - desc: "embedded-resource with preserve-unknown-fields", + desc: "embedded-resource with preserve-unknown-fields", + preserveUnknownFields: "false", globalSchema: ` type: object x-kubernetes-embedded-resource: true x-kubernetes-preserve-unknown-fields: true `, - expectedViolations: []string{}, }, { desc: "embedded-resource with wrong type", @@ -1330,7 +1354,8 @@ oneOf: }, }, { - desc: "structural complete", + desc: "structural complete", + preserveUnknownFields: "false", globalSchema: ` type: object properties: @@ -1391,7 +1416,6 @@ oneOf: - properties: g: {} `, - expectedViolations: nil, }, { desc: "invalid v1beta1 schema", @@ -1472,7 +1496,8 @@ properties: }, }, { - desc: "metadata with name property", + desc: "metadata with name property", + preserveUnknownFields: "false", globalSchema: ` type: object properties: @@ -1483,10 +1508,10 @@ properties: type: string pattern: "^[a-z]+$" `, - expectedViolations: []string{}, }, { - desc: "metadata with generateName property", + desc: "metadata with generateName property", + preserveUnknownFields: "false", globalSchema: ` type: object properties: @@ -1497,10 +1522,10 @@ properties: type: string pattern: "^[a-z]+$" `, - expectedViolations: []string{}, }, { - desc: "metadata with name and generateName property", + desc: "metadata with name and generateName property", + preserveUnknownFields: "false", globalSchema: ` type: object properties: @@ -1514,7 +1539,6 @@ properties: type: string pattern: "^[a-z]+$" `, - expectedViolations: []string{}, }, { desc: "metadata under junctors", @@ -1597,6 +1621,7 @@ properties: "GLOBAL_SCHEMA", toValidationJSON(tst.globalSchema), "V1BETA1_SCHEMA", toValidationJSON(tst.v1beta1Schema), "V1_SCHEMA", toValidationJSON(tst.v1Schema), + "PRESERVE_UNKNOWN_FIELDS", tst.preserveUnknownFields, ).Replace(tmpl) // decode CRD manifest