Skip to content

Commit

Permalink
Add validation for example and enum values in ClusterClass
Browse files Browse the repository at this point in the history
Co-authored-by: Stefan Büringer [email protected]
Signed-off-by: killianmuldoon <[email protected]>
  • Loading branch information
killianmuldoon committed Dec 10, 2021
1 parent 203a0e3 commit d1a7295
Show file tree
Hide file tree
Showing 6 changed files with 450 additions and 30 deletions.
5 changes: 2 additions & 3 deletions internal/topology/variables/cluster_variable_defaulting.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,10 @@ func defaultClusterVariable(clusterVariable *clusterv1.ClusterVariable, clusterC
}

// Convert schema to Kubernetes APIExtensions schema.
apiExtensionsSchema, errs := convertToAPIExtensionsJSONSchemaProps(&clusterClassVariable.Schema.OpenAPIV3Schema, fldPath)
apiExtensionsSchema, errs := convertToAPIExtensionsJSONSchemaProps(&clusterClassVariable.Schema.OpenAPIV3Schema, field.NewPath("schema"))
if len(errs) > 0 {
return nil, errs
return nil, field.ErrorList{field.Invalid(fldPath, "",
fmt.Sprintf("invalid schema in ClusterClass for variable %q: error to convert schema %v", clusterVariable.Name, errs))}
fmt.Sprintf("invalid schema in ClusterClass for variable %q: error to convert schema %v", clusterClassVariable.Name, errs))}
}

var value interface{}
Expand Down
6 changes: 2 additions & 4 deletions internal/topology/variables/cluster_variable_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,10 @@ func ValidateClusterVariable(clusterVariable *clusterv1.ClusterVariable, cluster
}

// Convert schema to Kubernetes APIExtensions Schema.
apiExtensionsSchema, allErrs := convertToAPIExtensionsJSONSchemaProps(&clusterClassVariable.Schema.OpenAPIV3Schema, fldPath)
apiExtensionsSchema, allErrs := convertToAPIExtensionsJSONSchemaProps(&clusterClassVariable.Schema.OpenAPIV3Schema, field.NewPath("schema"))
if len(allErrs) > 0 {
return allErrs
return field.ErrorList{field.InternalError(fldPath,
fmt.Errorf("failed to convert schema definition for variable %q; ClusterClass should be checked: %v", clusterVariable.Name, allErrs))} // TODO: consider if to add ClusterClass name

fmt.Errorf("failed to convert schema definition for variable %q; ClusterClass should be checked: %v", clusterClassVariable.Name, allErrs))} // TODO: consider if to add ClusterClass name
}

// Create validator for schema.
Expand Down
39 changes: 31 additions & 8 deletions internal/topology/variables/clusterclass_variable_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func validateClusterClassVariable(variable *clusterv1.ClusterClassVariable, fldP
allErrs = append(allErrs, validateClusterClassVariableName(variable.Name, fldPath.Child("name"))...)

// Validate schema.
allErrs = append(allErrs, validateRootSchema(&variable.Schema.OpenAPIV3Schema, fldPath.Child("schema", "openAPIV3Schema"))...)
allErrs = append(allErrs, validateRootSchema(variable, fldPath.Child("schema", "openAPIV3Schema"))...)

return allErrs
}
Expand All @@ -103,12 +103,13 @@ func validateClusterClassVariableName(variableName string, fldPath *field.Path)
var validVariableTypes = sets.NewString("object", "array", "string", "number", "integer", "boolean")

// validateRootSchema validates the schema.
func validateRootSchema(schema *clusterv1.JSONSchemaProps, fldPath *field.Path) field.ErrorList {
func validateRootSchema(clusterClassVariable *clusterv1.ClusterClassVariable, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList

apiExtensionsSchema, errs := convertToAPIExtensionsJSONSchemaProps(schema, fldPath)
if len(errs) > 0 {
return append(allErrs, errs...)
apiExtensionsSchema, allErrs := convertToAPIExtensionsJSONSchemaProps(&clusterClassVariable.Schema.OpenAPIV3Schema, field.NewPath("schema"))
if len(allErrs) > 0 {
return field.ErrorList{field.InternalError(fldPath,
fmt.Errorf("failed to convert schema definition for variable %q; ClusterClass should be checked: %v", clusterClassVariable.Name, allErrs))} // TODO: consider if to add ClusterClass name
}

// Validate structural schema.
Expand Down Expand Up @@ -149,21 +150,43 @@ func validateRootSchema(schema *clusterv1.JSONSchemaProps, fldPath *field.Path)
}); err != nil {
return append(allErrs, field.Invalid(fldPath, "", fmt.Sprintf("failed to build validator: %v", err)))
}

allErrs = append(allErrs, validateSchema(apiExtensionsSchema, fldPath)...)
return allErrs
}

func validateSchema(schema *apiextensions.JSONSchemaProps, fldPath *field.Path) field.ErrorList {
var allErrs field.ErrorList

// Validate that type is one of the validVariableTypes.
switch {
case len(schema.Type) == 0:
return field.ErrorList{field.Required(fldPath.Child("type"), "openAPIV3Schema.type cannot be empty")}
case schema.Type == "":
return field.ErrorList{field.Required(fldPath.Child("type"), "type cannot be empty")}
case !validVariableTypes.Has(schema.Type):
return field.ErrorList{field.NotSupported(fldPath.Child("type"), schema.Type, validVariableTypes.List())}
}

// validate enums and example here.
// If the structural schema is valid, ensure a schema validator can be constructed.
validator, _, err := validation.NewSchemaValidator(&apiextensions.CustomResourceValidation{
OpenAPIV3Schema: schema,
})
if err != nil {
return append(allErrs, field.Invalid(fldPath, "", fmt.Sprintf("failed to build validator: %v", err)))
}

if schema.Example != nil {
if errs := validation.ValidateCustomResource(fldPath, *schema.Example, validator); len(errs) > 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("example"), schema.Example, fmt.Sprintf("invalid value in example: %v", errs)))
}
}

for i, enum := range schema.Enum {
if enum != nil {
if errs := validation.ValidateCustomResource(fldPath, enum, validator); len(errs) > 0 {
allErrs = append(allErrs, field.Invalid(fldPath.Child("enum").Index(i), enum, fmt.Sprintf("invalid value in enum: %v", errs)))
}
}
}

for propertyName, propertySchema := range schema.Properties {
p := propertySchema
Expand Down
Loading

0 comments on commit d1a7295

Please sign in to comment.