Skip to content

Commit 3f6e80a

Browse files
authored
Make CRD version configurable (#266)
- Fixes #1089 - Adds config.ResourceConfig.APIVersion to be able to override the generated version for a CRD Issue #, if available: [#1089](aws-controllers-k8s/community#1089) Description of changes: This PR proposes a new configuration field named `APIVersion` (JSON-serialized name `api_version`) in `config.ResourceConfig` that allows overriding versions of specific CRDs generated by the Crossplane codegen pipeline. If a specific version string is not configured for a CRD-type, the default version specified with the `--version` command-line argument is used for backwards-compatibility. An [example configuration](https://github.com/crossplane/provider-aws/blob/master/apis/cloudfront/v1alpha1/generator-config.yaml) overriding the version for the CloudFront Distribution resource is as follows: ``` resources: "Distribution": api_versions: - name: "v1beta1" storage: true ignore: resource_names: - FieldLevelEncryptionProfile - Invalidation - KeyGroup - OriginRequestPolicy - PublicKey - StreamingDistribution - RealtimeLogConfig - MonitoringSubscription - FieldLevelEncryptionConfig field_paths: - DistributionConfig.CallerReference - Origins.Quantity - OriginAccessIdentityConfig.CallerReference ``` **This PR now introduces a backward-incompatible behavior change in the Crossplane pipeline:** Because the generator configuration is per API group (service) and because we may now have resources belonging to different API versions in a single group, this PR changes the default path of the `generator-config.yaml` file from: `apis/<API group>/<API version>/generator-config.yaml` to `apis/<API group>/generator-config.yaml` An example invocation `ack-generate crossplane cloudfront --output <output path> --generator-config-path generator-config.yaml` using the above configuration yields the following file structure: ```console ❯ tree . ├── apis │   └── cloudfront │   ├── v1alpha1 │   │   ├── zz_cache_policy.go │   │   ├── zz_cloud_front_origin_access_identity.go [0/941] │   │   ├── zz_doc.go │   │   ├── zz_enums.go │   │   ├── zz_function.go │   │   ├── zz_groupversion_info.go │   │   ├── zz_response_headers_policy.go │   │   └── zz_types.go │   └── v1beta1 │   ├── zz_distribution.go │   ├── zz_doc.go │   ├── zz_enums.go │   ├── zz_groupversion_info.go │   └── zz_types.go ├── generator-config.yaml ├── go.mod ├── go.sum └── pkg └── controller └── cloudfront ├── cachepolicy │   ├── zz_controller.go │   └── zz_conversions.go ├── cloudfrontoriginaccessidentity │   ├── zz_controller.go │   └── zz_conversions.go ├── distribution │   ├── zz_controller.go │   └── zz_conversions.go ├── function │   ├── zz_controller.go │   └── zz_conversions.go └── responseheaderspolicy ├── zz_controller.go └── zz_conversions.go 12 directories, 26 files ``` Without the `resources` configuration block, all resources are under `v1alpha1` version as expected: ```console ❯ tree . . ├── apis [0/1036] │   └── cloudfront │   └── v1alpha1 │   ├── zz_cache_policy.go │   ├── zz_cloud_front_origin_access_identity.go │   ├── zz_distribution.go │   ├── zz_doc.go │   ├── zz_enums.go │   ├── zz_function.go │   ├── zz_groupversion_info.go │   ├── zz_response_headers_policy.go │   └── zz_types.go ├── generator-config.yaml ├── go.mod ├── go.sum └── pkg └── controller └── cloudfront ├── cachepolicy │   ├── zz_controller.go │   └── zz_conversions.go ├── cloudfrontoriginaccessidentity │   ├── zz_controller.go │   └── zz_conversions.go ├── distribution │   ├── zz_controller.go │   └── zz_conversions.go ├── function │   ├── zz_controller.go │   └── zz_conversions.go └── responseheaderspolicy ├── zz_controller.go └── zz_conversions.go 11 directories, 22 files ``` By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 4c88d33 commit 3f6e80a

File tree

5 files changed

+91
-16
lines changed

5 files changed

+91
-16
lines changed

cmd/ack-generate/command/crossplane.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ func generateCrossplane(_ *cobra.Command, args []string) error {
4949
return err
5050
}
5151
svcAlias := strings.ToLower(args[0])
52-
optGeneratorConfigPath = filepath.Join(optOutputPath, "apis", svcAlias, optGenVersion, "generator-config.yaml")
52+
if optGeneratorConfigPath == "" {
53+
// default generator configuration file path is now: apis/<service>/<generator-config.yaml>
54+
// as this configuration is per API group (per service), and
55+
// resources can exist in multiple versions.
56+
optGeneratorConfigPath = filepath.Join(optOutputPath, "apis", svcAlias, "generator-config.yaml")
57+
}
5358
m, err := loadModel(svcAlias, optGenVersion, "aws.crossplane.io", cpgenerate.DefaultConfig)
5459
if err != nil {
5560
return err

pkg/generate/config/resource.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@ type ResourceConfig struct {
7878
// All ShortNames must be distinct from any other ShortNames installed into the cluster,
7979
// otherwise the CRD will fail to install.
8080
ShortNames []string `json:"shortNames,omitempty"`
81+
// APIVersions represents the API versions defined for the generated CRD.
82+
// Default version to be used is the one specified via the "--version"
83+
// command-line argument, if none is specified here.
84+
// For the Crossplane pipeline, the generation target is the version
85+
// marked as the storage version.
86+
APIVersions []APIVersion `json:"api_versions,omitempty"`
8187
// IsAdoptable determines whether the CRD should be accepted by the adoption reconciler.
8288
// If set to false, the user will be given an error if they attempt to adopt a resource
8389
// with this type.

pkg/generate/config/version.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License"). You may
4+
// not use this file except in compliance with the License. A copy of the
5+
// License is located at
6+
//
7+
// http://aws.amazon.com/apache2.0/
8+
//
9+
// or in the "license" file accompanying this file. This file is distributed
10+
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11+
// express or implied. See the License for the specific language governing
12+
// permissions and limitations under the License.
13+
14+
package config
15+
16+
// APIVersion represents an API version of the generated CRD.
17+
type APIVersion struct {
18+
// Name of the API version, e.g. v1beta1
19+
Name string `json:"name"`
20+
// Served whether this version is enabled or not
21+
Served *bool `json:"served,omitempty"`
22+
// Storage whether this version is the storage version.
23+
// One and only one version can be set as the storage version.
24+
Storage *bool `json:"storage,omitempty"`
25+
}

pkg/generate/crossplane/crossplane.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -135,33 +135,49 @@ func Crossplane(
135135
)
136136

137137
metaVars := m.MetaVars()
138+
detectedCRDVersions := make(map[string]bool)
139+
for _, crd := range crds {
140+
v, err := crd.GetStorageVersion(metaVars.APIVersion)
141+
if err != nil {
142+
return nil, err
143+
}
144+
detectedCRDVersions[v] = true
145+
}
138146

139147
// First add all the CRDs and API types
140-
apiVars := &templateAPIVars{
141-
metaVars,
142-
enumDefs,
143-
typeDefs,
144-
}
145-
for _, path := range apisGenericTemplatesPaths {
146-
outPath := filepath.Join(
147-
"apis",
148-
metaVars.ServicePackageName,
149-
metaVars.APIVersion,
150-
"zz_"+strings.TrimSuffix(filepath.Base(path), ".tpl"),
151-
)
152-
if err = ts.Add(outPath, path, apiVars); err != nil {
153-
return nil, err
148+
for apiVersion := range detectedCRDVersions {
149+
for _, path := range apisGenericTemplatesPaths {
150+
apiVars := &templateAPIVars{
151+
metaVars,
152+
enumDefs,
153+
typeDefs,
154+
}
155+
apiVars.APIVersion = apiVersion
156+
outPath := filepath.Join(
157+
"apis",
158+
metaVars.ServicePackageName,
159+
apiVersion,
160+
"zz_"+strings.TrimSuffix(filepath.Base(path), ".tpl"),
161+
)
162+
if err = ts.Add(outPath, path, apiVars); err != nil {
163+
return nil, err
164+
}
154165
}
155166
}
156167
for _, crd := range crds {
168+
v, err := crd.GetStorageVersion(metaVars.APIVersion)
169+
if err != nil {
170+
return nil, err
171+
}
157172
crdFileName := filepath.Join(
158-
"apis", metaVars.ServicePackageName, metaVars.APIVersion,
173+
"apis", metaVars.ServicePackageName, v,
159174
"zz_"+strcase.ToSnake(crd.Kind)+".go",
160175
)
161176
crdVars := &templateCRDVars{
162177
metaVars,
163178
crd,
164179
}
180+
crdVars.APIVersion = v
165181
if err = ts.Add(crdFileName, crdTemplatePath, crdVars); err != nil {
166182
return nil, err
167183
}
@@ -177,6 +193,9 @@ func Crossplane(
177193
metaVars,
178194
crd,
179195
}
196+
if crdVars.APIVersion, err = crd.GetStorageVersion(metaVars.APIVersion); err != nil {
197+
return nil, err
198+
}
180199
if err = ts.Add(outPath, controllerTmplPath, crdVars); err != nil {
181200
return nil, err
182201
}
@@ -188,6 +207,9 @@ func Crossplane(
188207
metaVars,
189208
crd,
190209
}
210+
if crdVars.APIVersion, err = crd.GetStorageVersion(metaVars.APIVersion); err != nil {
211+
return nil, err
212+
}
191213
if err = ts.Add(outPath, conversionsTmplPath, crdVars); err != nil {
192214
return nil, err
193215
}

pkg/model/crd.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ func (r *CRD) Config() *ackgenconfig.Config {
9696
return r.cfg
9797
}
9898

99+
// GetStorageVersion returns the configured storage API version for the CRD, or
100+
// the specified default version.
101+
func (r *CRD) GetStorageVersion(defaultVersion string) (string, error) {
102+
// if not configured
103+
if r.cfg == nil || len(r.cfg.Resources[r.Names.Original].APIVersions) == 0 {
104+
return defaultVersion, nil
105+
}
106+
107+
for _, v := range r.cfg.Resources[r.Names.Original].APIVersions {
108+
if v.Storage != nil && *v.Storage {
109+
return v.Name, nil
110+
}
111+
}
112+
return "", fmt.Errorf("exactly one configured version must be marked as the storage version for the %q CRD",
113+
r.Names.Original)
114+
}
115+
99116
// SDKAPIPackageName returns the aws-sdk-go package name used for this
100117
// resource's API
101118
func (r *CRD) SDKAPIPackageName() string {

0 commit comments

Comments
 (0)