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

✨ crd: allow specifying spec.preserveUnknownFields #912

Merged
Show file tree
Hide file tree
Changes from all commits
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
34 changes: 33 additions & 1 deletion pkg/crd/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ type Generator struct {

// Year specifies the year to substitute for " YEAR" in the header file.
Year string `marker:",optional"`

// DeprecatedV1beta1CompatibilityPreserveUnknownFields indicates whether
// or not we should turn off field pruning for this resource.
//
// Specifies spec.preserveUnknownFields value that is false and omitted by default.
// This value can only be specified for CustomResourceDefinitions that were created with
// `apiextensions.k8s.io/v1beta1`.
//
// The field can be set for compatiblity reasons, although strongly discouraged, resource
// authors should move to a structural OpenAPI schema instead.
//
// See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning
// for more information about field pruning and v1beta1 resources compatibility.
DeprecatedV1beta1CompatibilityPreserveUnknownFields *bool `marker:",optional"`
}

func (Generator) CheckFilter() loader.NodeFilter {
Expand All @@ -100,6 +114,16 @@ func transformRemoveCRDStatus(obj map[string]interface{}) error {
return nil
}

// transformPreserveUnknownFields adds spec.preserveUnknownFields=value.
func transformPreserveUnknownFields(value bool) func(map[string]interface{}) error {
return func(obj map[string]interface{}) error {
if spec, ok := obj["spec"].(map[interface{}]interface{}); ok {
spec["preserveUnknownFields"] = value
}
return nil
}
}

func (g Generator) Generate(ctx *genall.GenerationContext) error {
parser := &Parser{
Collector: ctx.Collector,
Expand Down Expand Up @@ -146,6 +170,14 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
}
headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year)

yamlOpts := []*genall.WriteYAMLOptions{
genall.WithTransform(transformRemoveCRDStatus),
genall.WithTransform(genall.TransformRemoveCreationTimestamp),
}
if g.DeprecatedV1beta1CompatibilityPreserveUnknownFields != nil {
yamlOpts = append(yamlOpts, genall.WithTransform(transformPreserveUnknownFields(*g.DeprecatedV1beta1CompatibilityPreserveUnknownFields)))
}

for _, groupKind := range kubeKinds {
parser.NeedCRDFor(groupKind, g.MaxDescLen)
crdRaw := parser.CustomResourceDefinitions[groupKind]
Expand All @@ -171,7 +203,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
} else {
fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i])
}
if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, genall.WithTransform(transformRemoveCRDStatus), genall.WithTransform(genall.TransformRemoveCreationTimestamp)); err != nil {
if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, yamlOpts...); err != nil {
return err
}
}
Expand Down
37 changes: 37 additions & 0 deletions pkg/crd/gen_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,43 @@ var _ = Describe("CRD Generation proper defaulting", func() {
expectedOut := string(expectedFileFoos) + string(expectedFileZoos)
Expect(out.buf.String()).To(Equal(expectedOut), cmp.Diff(out.buf.String(), expectedOut))
})

It("should add preserveUnknownFields=false when specified", func() {
AlexanderYastrebov marked this conversation as resolved.
Show resolved Hide resolved
By("calling Generate")
no := false
gen := &crd.Generator{
CRDVersions: []string{"v1"},
DeprecatedV1beta1CompatibilityPreserveUnknownFields: &no,
}
Expect(gen.Generate(ctx)).NotTo(HaveOccurred())

By("searching preserveUnknownFields")
Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: false"))
})

It("should add preserveUnknownFields=true when specified", func() {
By("calling Generate")
yes := true
gen := &crd.Generator{
CRDVersions: []string{"v1"},
DeprecatedV1beta1CompatibilityPreserveUnknownFields: &yes,
}
Expect(gen.Generate(ctx)).NotTo(HaveOccurred())

By("searching preserveUnknownFields")
Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: true"))
})

It("should not add preserveUnknownFields when not specified", func() {
By("calling Generate")
gen := &crd.Generator{
CRDVersions: []string{"v1"},
}
Expect(gen.Generate(ctx)).NotTo(HaveOccurred())

By("searching preserveUnknownFields")
Expect(out.buf.String()).NotTo(ContainSubstring("preserveUnknownFields"))
})
})

// fixAnnotations fixes the attribution annotation for tests.
Expand Down