From f1cb630bb8dc858d6cc8e21d689f2e77db8ae889 Mon Sep 17 00:00:00 2001 From: Harvey Xia Date: Thu, 19 Jan 2023 09:30:34 -0500 Subject: [PATCH] add support for oneOf --- pkg/crd/markers/validation.go | 3 +++ pkg/crd/schema.go | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/pkg/crd/markers/validation.go b/pkg/crd/markers/validation.go index 5d1496189..d1e61516d 100644 --- a/pkg/crd/markers/validation.go +++ b/pkg/crd/markers/validation.go @@ -80,6 +80,9 @@ var FieldOnlyMarkers = []*definitionWithHelp{ must(markers.MakeDefinition("optional", markers.DescribesField, struct{}{})). WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is optional, if fields are required by default.")), + must(markers.MakeDefinition("kubebuilder:validation:OneOf", markers.DescribesField, struct{}{})). + WithHelp(markers.SimpleHelp("CRD validation", "specifies that this field is part of a oneOf group")), + must(markers.MakeDefinition("nullable", markers.DescribesField, Nullable{})). WithHelp(Nullable{}.Help()), diff --git a/pkg/crd/schema.go b/pkg/crd/schema.go index e76d3ea88..c4470d3cf 100644 --- a/pkg/crd/schema.go +++ b/pkg/crd/schema.go @@ -378,22 +378,34 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON defaultMode = "optional" } + fieldMarkedOptional := (field.Markers.Get("kubebuilder:validation:Optional") != nil || field.Markers.Get("optional") != nil) + fieldMarkedRequired := (field.Markers.Get("kubebuilder:validation:Required") != nil) + fieldMarkedOneOf := (field.Markers.Get("kubebuilder:validation:OneOf") != nil) + switch defaultMode { // if this package isn't set to optional default... case "required": - // ...everything that's not inline, omitempty, or explicitly optional is required - if !inline && !omitEmpty && field.Markers.Get("kubebuilder:validation:Optional") == nil && field.Markers.Get("optional") == nil { + // ...everything that's not inline, not omitempty, not part of a oneOf group, and not explicitly optional is required + if !inline && !omitEmpty && !fieldMarkedOneOf && !fieldMarkedOptional { props.Required = append(props.Required, fieldName) } // if this package isn't set to required default... case "optional": - // ...everything that isn't explicitly required is optional - if field.Markers.Get("kubebuilder:validation:Required") != nil { + // ...everything that's part of a oneOf group, or not explicitly required is optional + if !fieldMarkedOneOf && fieldMarkedRequired { props.Required = append(props.Required, fieldName) } } + // process oneOf groups + if field.Markers.Get("kubebuilder:validation:OneOf") != nil { + props.OneOf = append(props.OneOf, apiext.JSONSchemaProps{ + Properties: map[string]apiext.JSONSchemaProps{fieldName: {}}, + Required: []string{fieldName}, + }) + } + var propSchema *apiext.JSONSchemaProps if field.Markers.Get(crdmarkers.SchemalessName) != nil { propSchema = &apiext.JSONSchemaProps{}