apiextensions: validate that list-type set has atomic items

This commit is contained in:
Dr. Stefan Schimanski 2019-11-08 09:57:30 +01:00
parent 4a35ce37c1
commit e4e1c2cd80
2 changed files with 176 additions and 0 deletions

View File

@ -807,6 +807,18 @@ func ValidateCustomResourceDefinitionOpenAPISchema(schema *apiextensions.JSONSch
} else { } else {
allErrs = append(allErrs, field.Invalid(fldPath.Child("type"), schema.Type, "must be array if x-kubernetes-list-type is specified")) allErrs = append(allErrs, field.Invalid(fldPath.Child("type"), schema.Type, "must be array if x-kubernetes-list-type is specified"))
} }
} else if schema.XListType != nil && *schema.XListType == "set" && schema.Items != nil && schema.Items.Schema != nil { // by structural schema items are present
is := schema.Items.Schema
switch is.Type {
case "array":
if is.XListType != nil && *is.XListType != "atomic" { // atomic is the implicit default behaviour if unset, hence != atomic is wrong
allErrs = append(allErrs, field.Invalid(fldPath.Child("items").Child("x-kubernetes-list-type"), is.XListType, "must be atomic as item of a list with x-kubernetes-list-type=set"))
}
case "object":
if is.XMapType == nil || *is.XMapType != "atomic" { // granular is the implicit default behaviour if unset, hence nil and != atomic are wrong
allErrs = append(allErrs, field.Invalid(fldPath.Child("items").Child("x-kubernetes-map-type"), is.XListType, "must be atomic as item of a list with x-kubernetes-list-type=set"))
}
}
} }
if schema.XListType != nil && *schema.XListType != "atomic" && *schema.XListType != "set" && *schema.XListType != "map" { if schema.XListType != nil && *schema.XListType != "atomic" && *schema.XListType != "set" && *schema.XListType != "map" {

View File

@ -6300,6 +6300,170 @@ func TestValidateCustomResourceDefinitionValidation(t *testing.T) {
}, },
wantError: false, wantError: false,
}, },
{
name: "allowed list-type atomic",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("atomic"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "string",
},
},
},
},
wantError: false,
},
{
name: "allowed list-type atomic with non-atomic items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("atomic"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensions.JSONSchemaProps{},
},
},
},
},
wantError: false,
},
{
name: "allowed list-type set with scalar items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "string",
},
},
},
},
wantError: false,
},
{
name: "allowed list-type set with atomic map items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "object",
XMapType: strPtr("atomic"),
Properties: map[string]apiextensions.JSONSchemaProps{
"foo": {Type: "string"},
},
},
},
},
},
wantError: false,
},
{
name: "invalid list-type set with non-atomic map items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "object",
XMapType: strPtr("granular"),
Properties: map[string]apiextensions.JSONSchemaProps{
"foo": {Type: "string"},
},
},
},
},
},
wantError: true,
},
{
name: "invalid list-type set with unspecified map-type for map items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensions.JSONSchemaProps{
"foo": {Type: "string"},
},
},
},
},
},
wantError: true,
},
{
name: "allowed list-type set with atomic list items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("atomic"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "string",
},
},
},
},
},
},
wantError: false,
},
{
name: "allowed list-type set with unspecified list-type in list items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "array",
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "string",
},
},
},
},
},
},
wantError: false,
},
{
name: "invalid list-type set with with non-atomic list items",
input: apiextensions.CustomResourceValidation{
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "array",
XListType: strPtr("set"),
Items: &apiextensions.JSONSchemaPropsOrArray{
Schema: &apiextensions.JSONSchemaProps{
Type: "string",
},
},
},
},
},
},
wantError: true,
},
{ {
name: "invalid type with map type extension (granular)", name: "invalid type with map type extension (granular)",
input: apiextensions.CustomResourceValidation{ input: apiextensions.CustomResourceValidation{