controller-tools icon indicating copy to clipboard operation
controller-tools copied to clipboard

Flattening a schema drops the validation marker type overrides.

Open hugoShaka opened this issue 3 years ago • 0 comments

I'm using the tools from the crd package to generate an OpenAPI Schema and noticed the following behaviour:

  • The Type of a field X is set through the validation marker +kubebuilder:validation:Type=string (for example, forcing a metav1.Time to be a string instead of an object)
  • The Parser correctly discovers the type override and parser.Schemata[myTypeIdent] says the field X is a string
  • But parser.FlattenedSchemata[myTypeIdent] says the field X is an object

I'm not sure this behaviour is intended.

Here is a toy example reproducing the issue, the mis-typed field is LastTransitionTime. I would expect its type to be string in both the regular and the flattened schemas.

main.go

package main

import (
	"fmt"
	"sigs.k8s.io/controller-tools/pkg/crd"
	crdmarkers "sigs.k8s.io/controller-tools/pkg/crd/markers"
	"sigs.k8s.io/controller-tools/pkg/loader"
	"sigs.k8s.io/controller-tools/pkg/markers"
)

func main() {
	registry := &markers.Registry{}
	crdmarkers.Register(registry)
	parser := crd.Parser{
		Collector: &markers.Collector{Registry: registry},
		Checker:   &loader.TypeChecker{},
	}

	pkgs, err := loader.LoadRoots("./...")
	if err != nil {
		fmt.Printf("parser error: %s", err)
	}

	var statusType crd.TypeIdent

	pkg := pkgs[1]
	parser.NeedPackage(pkg)
	statusType = crd.TypeIdent{
		Package: pkg,
		Name:    "UserStatus",
	}

	parser.NeedFlattenedSchemaFor(statusType)
	fmt.Printf("Schemata %v \n", parser.Schemata[statusType])
	fmt.Printf("Flattened Schemata %v \n", parser.FlattenedSchemata[statusType])
}

v2/user_types.go

package v2

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/controller-runtime/pkg/scheme"
)

var (
	GroupVersion = schema.GroupVersion{Group: "myGroup", Version: "v2"}
	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
	AddToScheme = SchemeBuilder.AddToScheme
)

func init() {
	SchemeBuilder.Register(&User{}, &UserList{})
}

type UserStatus struct {
	// +required
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:Type=string
	// +kubebuilder:validation:Format=date-time
	LastTransitionTime metav1.Time `json:"lastTransitionTime" protobuf:"bytes,4,opt,name=lastTransitionTime"`
}

//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
type User struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Status UserStatus `json:"status,omitempty"`
}

The workaround is using known type overrides.

hugoShaka avatar Jul 04 '22 23:07 hugoShaka