Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add crd:validation:Schemaless marker #528

Merged
merged 2 commits into from
Jan 29, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
run:
modules-download-mode: readonly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That had fixed an error I was having running the linter. It's been a while, so I can't remember what the error was.

Testing again with this line re-added doesn't cause a problem anymore. I wonder if it only breaks if your go modules aren't already up-to-date?

In any case, not really in scope for this PR, so reverting.


# Increase the default deadline from 1m as some module operations can take a
# while if uncached!
deadline: 5m
17 changes: 17 additions & 0 deletions pkg/crd/markers/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import (
"sigs.k8s.io/controller-tools/pkg/markers"
)

const (
SchemalessName = "kubebuilder:validation:Schemaless"
)

// ValidationMarkers lists all available markers that affect CRD schema generation,
// except for the few that don't make sense as type-level markers (see FieldOnlyMarkers).
// All markers start with `+kubebuilder:validation:`, and continue with their type name.
Expand Down Expand Up @@ -82,6 +86,9 @@ var FieldOnlyMarkers = []*definitionWithHelp{

must(markers.MakeDefinition("kubebuilder:validation:EmbeddedResource", markers.DescribesField, XEmbeddedResource{})).
WithHelp(XEmbeddedResource{}.Help()),

must(markers.MakeDefinition(SchemalessName, markers.DescribesField, Schemaless{})).
WithHelp(Schemaless{}.Help()),
}

// ValidationIshMarkers are field-and-type markers that don't fall under the
Expand Down Expand Up @@ -225,6 +232,16 @@ type XPreserveUnknownFields struct{}
// field, yet it is possible. This can be combined with PreserveUnknownFields.
type XEmbeddedResource struct{}

// +controllertools:marker:generateHelp:category="CRD validation"
// Schemaless marks a field as being a schemaless object.
//
// Schemaless objects are not introspected, so you must provide
// any type and validation information yourself. One use for this
// tag is for embedding fields that hold JSONSchema typed objects.
// Because this field disables all type checking, it is recommended
// to be used only as a last resort.
type Schemaless struct{}

func (m Maximum) ApplyToSchema(schema *apiext.JSONSchemaProps) error {
if schema.Type != "integer" {
return fmt.Errorf("must apply maximum to an integer")
Expand Down
11 changes: 11 additions & 0 deletions pkg/crd/markers/zz_generated.markerhelp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion pkg/crd/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"strings"

apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers"

"sigs.k8s.io/controller-tools/pkg/loader"
"sigs.k8s.io/controller-tools/pkg/markers"
Expand Down Expand Up @@ -378,7 +379,12 @@ func structToSchema(ctx *schemaContext, structType *ast.StructType) *apiext.JSON
}
}

propSchema := typeToSchema(ctx.ForInfo(&markers.TypeInfo{}), field.RawField.Type)
var propSchema *apiext.JSONSchemaProps
if field.Markers.Get(crdmarkers.SchemalessName) != nil {
propSchema = &apiext.JSONSchemaProps{}
} else {
propSchema = typeToSchema(ctx.ForInfo(&markers.TypeInfo{}), field.RawField.Type)
}
propSchema.Description = field.Doc

applyMarkers(ctx, field.Markers, propSchema, field.RawField)
Expand Down
9 changes: 7 additions & 2 deletions pkg/crd/testdata/cronjob_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,19 @@ type CronJobSpec struct {

// This tests that min/max properties work
MinMaxProperties MinMaxObject `json:"minMaxProperties,omitempty"`

// This tests that the schemaless marker works
// +kubebuilder:validation:Schemaless
Schemaless []byte `json:"schemaless,omitempty"`
}

// +kubebuilder:validation:Type=object
// +kubebuilder:pruning:PreserveUnknownFields
type Preserved struct {
ConcreteField string `json:"concreteField"`
Rest map[string]interface{} `json:"-"`
ConcreteField string `json:"concreteField"`
Rest map[string]interface{} `json:"-"`
}

func (p *Preserved) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &p.Rest); err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions pkg/crd/testdata/testdata.kubebuilder.io_cronjobs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5071,6 +5071,8 @@ spec:
schedule:
description: The schedule in Cron format, see https://en.wikipedia.org/wiki/Cron.
type: string
schemaless:
description: This tests that the schemaless marker works
startingDeadlineSeconds:
description: Optional deadline in seconds for starting the job if
it misses scheduled time for any reason. Missed jobs executions
Expand Down
4 changes: 2 additions & 2 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,13 @@ fetch_kb_tools
# setup testing env
setup_envs

header_text "running golangci-lint"

header_text "generating marker help"
pushd cmd/controller-gen > /dev/null
go generate
popd > /dev/null

header_text "running golangci-lint"

golangci-lint run --disable-all \
--enable=misspell \
--enable=golint \
Expand Down