Skip to content

Commit a730752

Browse files
✨ Add support for external ApplyConfiguration mappings (#1327)
* Add support for external apply configurations * Generate help for external AC marker Using: ``` go generate ./cmd/controller-gen/... ``` * Add `testdata/external` and `testdata/externalac` Add packages under `testdata` that define an external type to be used for testing applyconfiguration generation for types that reference external types. * Add `EmbeddedExternalSpec` to `cronjob_types.go` This type is used to test generation of ACs for types that embed external types. * Update `testdata` with generated ACs Run the tests with `UPDATE=1` to regenerate the testdata files. * Update existing AC generator tests Pass the `externalApplyConfigurations` option to the `applyconfiguration` generator in the other tests so that they correctly generate `ApplyConfiguration` types now that an external type is used in the `CronJob`.
1 parent 33e5fdc commit a730752

File tree

9 files changed

+166
-8
lines changed

9 files changed

+166
-8
lines changed

pkg/applyconfiguration/applyconfiguration_integration_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ var _ = Describe("ApplyConfiguration generation from API types", func() {
109109
Expect(optionsRegistry.Register(markers.Must(markers.MakeDefinition("applyconfiguration", markers.DescribesPackage, Generator{})))).To(Succeed())
110110

111111
rt, err := genall.FromOptions(optionsRegistry, []string{
112-
"applyconfiguration",
112+
"applyconfiguration:externalApplyConfigurations=sigs.k8s.io/controller-tools/pkg/applyconfiguration/testdata/cronjob/external.ExternalData@sigs.k8s.io/controller-tools/pkg/applyconfiguration/testdata/cronjob/externalac",
113113
"paths=./api/v1",
114114
})
115115
Expect(err).NotTo(HaveOccurred())
@@ -218,7 +218,7 @@ var _ = Describe("ApplyConfiguration generation from API types", func() {
218218

219219
rt, err := genall.FromOptions(optionsRegistry, []string{
220220
"crd:allowDangerousTypes=true,ignoreUnexportedFields=true", // Run another generator first to make sure they don't interfere; see also: the comment on cronjob_types.go:UntypedBlob
221-
"applyconfiguration",
221+
"applyconfiguration:externalApplyConfigurations=sigs.k8s.io/controller-tools/pkg/applyconfiguration/testdata/cronjob/external.ExternalData@sigs.k8s.io/controller-tools/pkg/applyconfiguration/testdata/cronjob/externalac",
222222
"paths=./api/v1",
223223
})
224224
Expect(err).NotTo(HaveOccurred())

pkg/applyconfiguration/gen.go

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ import (
2020
"errors"
2121
"fmt"
2222
"go/ast"
23+
"maps"
2324
"os"
2425
"path/filepath"
26+
"strings"
27+
28+
"k8s.io/gengo/v2/types"
2529

2630
"k8s.io/apimachinery/pkg/util/sets"
2731
"k8s.io/code-generator/cmd/applyconfiguration-gen/args"
@@ -56,6 +60,16 @@ const defaultOutputPackage = "applyconfiguration"
5660
type Generator struct {
5761
// HeaderFile specifies the header text (e.g. license) to prepend to generated files.
5862
HeaderFile string `marker:",optional"`
63+
64+
// ExternalApplyConfigurations provides mappings between external types and their applyconfiguration packages.
65+
//
66+
// Use this to reference apply configuration types for external types referenced
67+
// by the Go structs provided as input. Each entry should be in the format:
68+
// <package>.<TypeName>@<applyconfiguration-package>
69+
//
70+
// For example, to reference the apply configuration for corev1.LocalObjectReference:
71+
// k8s.io/api/core/v1.LocalObjectReference@k8s.io/client-go/applyconfigurations/core/v1
72+
ExternalApplyConfigurations []string `marker:",optional"`
5973
}
6074

6175
func (Generator) CheckFilter() loader.NodeFilter {
@@ -143,10 +157,22 @@ func (d Generator) Generate(ctx *genall.GenerationContext) error {
143157
headerFilePath = tmpFile.Name()
144158
}
145159

160+
// Parse external apply configurations
161+
externalACs := make(map[types.Name]string)
162+
for _, ext := range d.ExternalApplyConfigurations {
163+
parts := strings.SplitN(ext, "@", 2)
164+
if len(parts) != 2 {
165+
return fmt.Errorf("invalid external apply configuration format %q, expected <package>.<TypeName>@<applyconfiguration-package>", ext)
166+
}
167+
typeName := types.ParseFullyQualifiedName(parts[0])
168+
externalACs[typeName] = parts[1]
169+
}
170+
146171
objGenCtx := ObjectGenCtx{
147-
Collector: ctx.Collector,
148-
Checker: ctx.Checker,
149-
HeaderFilePath: headerFilePath,
172+
Collector: ctx.Collector,
173+
Checker: ctx.Checker,
174+
HeaderFilePath: headerFilePath,
175+
ExternalApplyConfigurations: externalACs,
150176
}
151177

152178
errs := []error{}
@@ -167,9 +193,10 @@ func (d Generator) Generate(ctx *genall.GenerationContext) error {
167193
// It mostly exists so that generating for a package can be easily tested without
168194
// requiring a full set of output rules, etc.
169195
type ObjectGenCtx struct {
170-
Collector *markers.Collector
171-
Checker *loader.TypeChecker
172-
HeaderFilePath string
196+
Collector *markers.Collector
197+
Checker *loader.TypeChecker
198+
HeaderFilePath string
199+
ExternalApplyConfigurations map[types.Name]string
173200
}
174201

175202
// generateForPackage generates apply configuration implementations for
@@ -186,6 +213,9 @@ func (ctx *ObjectGenCtx) generateForPackage(root *loader.Package) error {
186213
arguments := args.New()
187214
arguments.GoHeaderFile = ctx.HeaderFilePath
188215

216+
// Set external apply configurations
217+
maps.Copy(arguments.ExternalApplyConfigurations, ctx.ExternalApplyConfigurations)
218+
189219
outpkg := outputPkg(ctx.Collector, root)
190220

191221
arguments.OutputDir = filepath.Join(root.Dir, outpkg)

pkg/applyconfiguration/testdata/cronjob/api/v1/applyconfiguration/api/v1/cronjobspec.go

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/applyconfiguration/testdata/cronjob/api/v1/applyconfiguration/api/v1/embeddedexternalspec.go

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/applyconfiguration/testdata/cronjob/api/v1/applyconfiguration/utils.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/applyconfiguration/testdata/cronjob/api/v1/cronjob_types.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import (
3636
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3737
"k8s.io/apimachinery/pkg/runtime"
3838
"k8s.io/apimachinery/pkg/util/intstr"
39+
40+
"sigs.k8s.io/controller-tools/pkg/applyconfiguration/testdata/cronjob/external"
3941
)
4042

4143
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
@@ -390,6 +392,10 @@ type CronJobSpec struct {
390392
// Test that we can add a field that can only be set to a non-default value on updates using XValidation OptionalOldSelf.
391393
// +kubebuilder:validation:XValidation:rule="oldSelf.hasValue() || self == 0",message="must be set to 0 on creation. can be set to any value on an update.",optionalOldSelf=true
392394
OnlyAllowSettingOnUpdate int32 `json:"onlyAllowSettingOnUpdate,omitempty"`
395+
396+
// EmbeddedExternal tests the ExternalApplyConfigurations feature.
397+
// +optional
398+
EmbeddedExternal *EmbeddedExternalSpec `json:"embeddedExternal,omitempty"`
393399
}
394400

395401
type InlineAlias = EmbeddedStruct
@@ -766,3 +772,12 @@ type CronJobList struct {
766772
metav1.ListMeta `json:"metadata,omitempty"`
767773
Items []CronJob `json:"items"`
768774
}
775+
776+
// EmbeddedExternalSpec embeds an external type with json:",inline".
777+
// Used to test the ExternalApplyConfigurations feature.
778+
type EmbeddedExternalSpec struct {
779+
external.ExternalData `json:",inline"`
780+
781+
// Extra is an additional field.
782+
Extra string `json:"extra,omitempty"`
783+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package external
18+
19+
// ExternalData is a type defined outside the API package,
20+
// used to test generation of apply configurations for types
21+
// that reference external types.
22+
type ExternalData struct {
23+
Key string `json:"key,omitempty"`
24+
Value string `json:"value,omitempty"`
25+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package externalac
18+
19+
// ExternalDataApplyConfiguration is a placeholder AC type for testing.
20+
// In real usage, this would be a generated apply configuration type.
21+
type ExternalDataApplyConfiguration struct {
22+
Key *string `json:"key,omitempty"`
23+
Value *string `json:"value,omitempty"`
24+
}

pkg/applyconfiguration/zz_generated.markerhelp.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)