Skip to content

Commit e159968

Browse files
✨ crd: allow specifying spec.preserveUnknownFields (#912)
* crd: allow specifying spec.preserveUnknownFields Reinstate crd:preserveUnknownFields option removed by #607 to allow specifying the value of deprecated spec.preserveUnknownFields CRD field. This is useful for updating CRDs that were automatically converted from v1beta1 version which had true as a default value and resulted in: ``` $ kubectl get crd foo.bar -o yaml | grep preserveUnknownFields preserveUnknownFields: true message: 'spec.preserveUnknownFields: Invalid value: true: must be false' ``` For #476 * crd: rename marker to DeprecatedV1beta1CompatibilityPreserveUnknownFields
1 parent 8cc57e3 commit e159968

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

pkg/crd/gen.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,20 @@ type Generator struct {
8585

8686
// Year specifies the year to substitute for " YEAR" in the header file.
8787
Year string `marker:",optional"`
88+
89+
// DeprecatedV1beta1CompatibilityPreserveUnknownFields indicates whether
90+
// or not we should turn off field pruning for this resource.
91+
//
92+
// Specifies spec.preserveUnknownFields value that is false and omitted by default.
93+
// This value can only be specified for CustomResourceDefinitions that were created with
94+
// `apiextensions.k8s.io/v1beta1`.
95+
//
96+
// The field can be set for compatiblity reasons, although strongly discouraged, resource
97+
// authors should move to a structural OpenAPI schema instead.
98+
//
99+
// See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#field-pruning
100+
// for more information about field pruning and v1beta1 resources compatibility.
101+
DeprecatedV1beta1CompatibilityPreserveUnknownFields *bool `marker:",optional"`
88102
}
89103

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

117+
// transformPreserveUnknownFields adds spec.preserveUnknownFields=value.
118+
func transformPreserveUnknownFields(value bool) func(map[string]interface{}) error {
119+
return func(obj map[string]interface{}) error {
120+
if spec, ok := obj["spec"].(map[interface{}]interface{}); ok {
121+
spec["preserveUnknownFields"] = value
122+
}
123+
return nil
124+
}
125+
}
126+
103127
func (g Generator) Generate(ctx *genall.GenerationContext) error {
104128
parser := &Parser{
105129
Collector: ctx.Collector,
@@ -146,6 +170,14 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
146170
}
147171
headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year)
148172

173+
yamlOpts := []*genall.WriteYAMLOptions{
174+
genall.WithTransform(transformRemoveCRDStatus),
175+
genall.WithTransform(genall.TransformRemoveCreationTimestamp),
176+
}
177+
if g.DeprecatedV1beta1CompatibilityPreserveUnknownFields != nil {
178+
yamlOpts = append(yamlOpts, genall.WithTransform(transformPreserveUnknownFields(*g.DeprecatedV1beta1CompatibilityPreserveUnknownFields)))
179+
}
180+
149181
for _, groupKind := range kubeKinds {
150182
parser.NeedCRDFor(groupKind, g.MaxDescLen)
151183
crdRaw := parser.CustomResourceDefinitions[groupKind]
@@ -171,7 +203,7 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
171203
} else {
172204
fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i])
173205
}
174-
if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, genall.WithTransform(transformRemoveCRDStatus), genall.WithTransform(genall.TransformRemoveCreationTimestamp)); err != nil {
206+
if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, yamlOpts...); err != nil {
175207
return err
176208
}
177209
}

pkg/crd/gen_integration_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,43 @@ var _ = Describe("CRD Generation proper defaulting", func() {
119119
expectedOut := string(expectedFileFoos) + string(expectedFileZoos)
120120
Expect(out.buf.String()).To(Equal(expectedOut), cmp.Diff(out.buf.String(), expectedOut))
121121
})
122+
123+
It("should add preserveUnknownFields=false when specified", func() {
124+
By("calling Generate")
125+
no := false
126+
gen := &crd.Generator{
127+
CRDVersions: []string{"v1"},
128+
DeprecatedV1beta1CompatibilityPreserveUnknownFields: &no,
129+
}
130+
Expect(gen.Generate(ctx)).NotTo(HaveOccurred())
131+
132+
By("searching preserveUnknownFields")
133+
Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: false"))
134+
})
135+
136+
It("should add preserveUnknownFields=true when specified", func() {
137+
By("calling Generate")
138+
yes := true
139+
gen := &crd.Generator{
140+
CRDVersions: []string{"v1"},
141+
DeprecatedV1beta1CompatibilityPreserveUnknownFields: &yes,
142+
}
143+
Expect(gen.Generate(ctx)).NotTo(HaveOccurred())
144+
145+
By("searching preserveUnknownFields")
146+
Expect(out.buf.String()).To(ContainSubstring("preserveUnknownFields: true"))
147+
})
148+
149+
It("should not add preserveUnknownFields when not specified", func() {
150+
By("calling Generate")
151+
gen := &crd.Generator{
152+
CRDVersions: []string{"v1"},
153+
}
154+
Expect(gen.Generate(ctx)).NotTo(HaveOccurred())
155+
156+
By("searching preserveUnknownFields")
157+
Expect(out.buf.String()).NotTo(ContainSubstring("preserveUnknownFields"))
158+
})
122159
})
123160

124161
// fixAnnotations fixes the attribution annotation for tests.

0 commit comments

Comments
 (0)