apiextensions: forbid false x-kubernetes-preserve-unknown-fields

This commit is contained in:
Dr. Stefan Schimanski 2019-05-10 19:48:55 +02:00
parent 6897c68de5
commit d014591a11
11 changed files with 83 additions and 9 deletions

View File

@ -258,5 +258,15 @@ func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
}
}
if in.XPreserveUnknownFields != nil {
in, out := &in.XPreserveUnknownFields, &out.XPreserveUnknownFields
if *in == nil {
*out = nil
} else {
*out = new(bool)
**out = **in
}
}
return out
}

View File

@ -61,7 +61,8 @@ type JSONSchemaProps struct {
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
XPreserveUnknownFields bool
// This can either be true or undefined. False is forbidden.
XPreserveUnknownFields *bool
// x-kubernetes-embedded-resource defines that the value is an
// embedded Kubernetes runtime.Object, with TypeMeta and

View File

@ -234,5 +234,15 @@ func (in *JSONSchemaProps) DeepCopy() *JSONSchemaProps {
}
}
if in.XPreserveUnknownFields != nil {
in, out := &in.XPreserveUnknownFields, &out.XPreserveUnknownFields
if *in == nil {
*out = nil
} else {
*out = new(bool)
**out = **in
}
}
return out
}

View File

@ -449,6 +449,7 @@ message JSONSchemaProps {
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
// This can either be true or undefined. False is forbidden.
optional bool xKubernetesPreserveUnknownFields = 38;
// x-kubernetes-embedded-resource defines that the value is an

View File

@ -61,7 +61,8 @@ type JSONSchemaProps struct {
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
XPreserveUnknownFields bool `json:"x-kubernetes-preserve-unknown-fields,omitempty" protobuf:"bytes,38,opt,name=xKubernetesPreserveUnknownFields"`
// This can either be true or undefined. False is forbidden.
XPreserveUnknownFields *bool `json:"x-kubernetes-preserve-unknown-fields,omitempty" protobuf:"bytes,38,opt,name=xKubernetesPreserveUnknownFields"`
// x-kubernetes-embedded-resource defines that the value is an
// embedded Kubernetes runtime.Object, with TypeMeta and

View File

@ -34,6 +34,7 @@ go_test(
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
],
)

View File

@ -673,6 +673,10 @@ func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSch
}
}
if schema.XPreserveUnknownFields != nil && *schema.XPreserveUnknownFields == false {
allErrs = append(allErrs, field.Invalid(fldPath.Child("x-kubernetes-preserve-unknown-fields"), *schema.XPreserveUnknownFields, "must be true or undefined"))
}
return allErrs
}

View File

@ -22,6 +22,7 @@ import (
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/utils/pointer"
)
type validationMatch struct {
@ -935,6 +936,41 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
invalid("spec", "versions"),
},
},
{
name: "x-kubernetes-preserve-unknown-field: false",
resource: &apiextensions.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
Spec: apiextensions.CustomResourceDefinitionSpec{
Group: "group.com",
Version: "version",
Validation: &apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
XPreserveUnknownFields: pointer.BoolPtr(false),
},
},
Versions: []apiextensions.CustomResourceDefinitionVersion{
{
Name: "version",
Served: true,
Storage: true,
},
},
Scope: apiextensions.NamespaceScoped,
Names: apiextensions.CustomResourceDefinitionNames{
Plural: "plural",
Singular: "singular",
Kind: "Plural",
ListKind: "PluralList",
},
},
Status: apiextensions.CustomResourceDefinitionStatus{
StoredVersions: []string{"version"},
},
},
errors: []validationMatch{
invalid("spec", "validation", "openAPIV3Schema", "x-kubernetes-preserve-unknown-fields"),
},
},
}
for _, tc := range tests {

View File

@ -241,11 +241,19 @@ func newExtensions(s *apiextensions.JSONSchemaProps) (*Extensions, error) {
return nil, nil
}
return &Extensions{
XPreserveUnknownFields: s.XPreserveUnknownFields,
ret := &Extensions{
XEmbeddedResource: s.XEmbeddedResource,
XIntOrString: s.XIntOrString,
}, nil
}
if s.XPreserveUnknownFields != nil {
if !*s.XPreserveUnknownFields {
return nil, fmt.Errorf("'x-kubernetes-preserve-unknown-fields' must be true or undefined")
}
ret.XPreserveUnknownFields = true
}
return ret, nil
}
// validateUnsupportedFields checks that those fields rejected by validation are actually unset.

View File

@ -66,6 +66,8 @@ type Extensions struct {
// in the validation schema. This affects fields recursively,
// but switches back to normal pruning behaviour if nested
// properties or additionalProperties are specified in the schema.
// False means that the pruning behaviour is inherited from the parent.
// False does not mean to activate pruning.
XPreserveUnknownFields bool
// x-kubernetes-embedded-resource defines that the value is an

View File

@ -195,8 +195,8 @@ func ConvertJSONSchemaPropsWithPostProcess(in *apiextensions.JSONSchemaProps, ou
}
}
if in.XPreserveUnknownFields {
out.VendorExtensible.AddExtension("x-kubernetes-preserve-unknown-fields", true)
if in.XPreserveUnknownFields != nil {
out.VendorExtensible.AddExtension("x-kubernetes-preserve-unknown-fields", *in.XPreserveUnknownFields)
}
if in.XEmbeddedResource {
out.VendorExtensible.AddExtension("x-kubernetes-embedded-resource", true)