Skip to content

Commit 52c9171

Browse files
committed
chore: update client generation to generate multiple CRD versions
1 parent ff1832d commit 52c9171

File tree

5 files changed

+68
-41
lines changed

5 files changed

+68
-41
lines changed

pkg/crd/fielddesc/fielddesc.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ type FieldDescription struct {
4242
AdditionalProperties []FieldDescription
4343
}
4444

45-
func GetSpecDescription(crd *apiextensions.CustomResourceDefinition) FieldDescription {
46-
crdDesc := getCRDFieldDescription(crd)
45+
func GetSpecDescription(crd *apiextensions.CustomResourceDefinition, version string) FieldDescription {
46+
crdDesc := getCRDFieldDescription(crd, version)
4747
spec, ok := getChildFieldDesc(crdDesc, "spec")
4848
if !ok {
4949
// this occurs when a CRD has an empty spec, such as ComputeSharedVPCHostProject
@@ -56,9 +56,9 @@ func GetSpecDescription(crd *apiextensions.CustomResourceDefinition) FieldDescri
5656
return *spec
5757
}
5858

59-
func GetStatusDescription(crd *apiextensions.CustomResourceDefinition) (FieldDescription, error) {
59+
func GetStatusDescription(crd *apiextensions.CustomResourceDefinition, version string) (FieldDescription, error) {
6060
statusPropertyName := "status"
61-
crdDesc := getCRDFieldDescription(crd)
61+
crdDesc := getCRDFieldDescription(crd, version)
6262
status, ok := getChildFieldDesc(crdDesc, statusPropertyName)
6363
if !ok {
6464
return FieldDescription{}, fmt.Errorf("unexpected missing '%v' on crd '%v'", statusPropertyName, crd.Spec.Names.Kind)
@@ -75,13 +75,13 @@ func getChildFieldDesc(description FieldDescription, childName string) (*FieldDe
7575
return nil, false
7676
}
7777

78-
func getCRDFieldDescription(crd *apiextensions.CustomResourceDefinition) FieldDescription {
78+
func getCRDFieldDescription(crd *apiextensions.CustomResourceDefinition, version string) FieldDescription {
7979
customResourceDesc := FieldDescription{
8080
Type: "object",
8181
RequirementLevel: RequiredRequirementLevel,
8282
}
83-
schema := k8s.GetOpenAPIV3SchemaFromCRD(crd)
84-
return propsToDescription(*schema, customResourceDesc, "", true)
83+
crdVersionDefinition := k8s.GetCRDVersionDefinition(crd, version)
84+
return propsToDescription(*crdVersionDefinition.Schema.OpenAPIV3Schema, customResourceDesc, "", true)
8585
}
8686

8787
func propsToDescription(props apiextensions.JSONSchemaProps, parent FieldDescription, name string, required bool) FieldDescription {

pkg/crd/fielddesc/fielddesc_test.go

+16-12
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/crd/crdloader"
2323
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/crd/fielddesc"
24+
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
2425
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test"
2526

2627
"gopkg.in/yaml.v2"
@@ -33,14 +34,16 @@ func TestAllCRDsGetSpecAndStatusDescription(t *testing.T) {
3334
t.Fatalf("error loading crds: %v", err)
3435
}
3536
for _, crd := range crds {
36-
fd := fielddesc.GetSpecDescription(&crd)
37-
expectedType := "object"
38-
if fd.Type != expectedType {
39-
t.Fatalf("unexpected type: got '%v', want' %v'", fd.Type, expectedType)
40-
}
41-
fd = getStatusDescription(t, &crd)
42-
if fd.Type != expectedType {
43-
t.Fatalf("unexpected type: got '%v', want' %v'", fd.Type, expectedType)
37+
for _, version := range crd.Spec.Versions {
38+
fd := fielddesc.GetSpecDescription(&crd, version.Name)
39+
expectedType := "object"
40+
if fd.Type != expectedType {
41+
t.Fatalf("unexpected type: got '%v', want' %v'", fd.Type, expectedType)
42+
}
43+
fd = getStatusDescription(t, &crd, version.Name)
44+
if fd.Type != expectedType {
45+
t.Fatalf("unexpected type: got '%v', want' %v'", fd.Type, expectedType)
46+
}
4447
}
4548
}
4649
}
@@ -58,16 +61,17 @@ func testOutputMatches(t *testing.T, resourceKind string) {
5861
if err != nil {
5962
t.Fatalf("error getting crd '%v': %v", resourceKind, err)
6063
}
61-
fd := fielddesc.GetSpecDescription(crd)
64+
version := k8s.PreferredVersion(crd)
65+
fd := fielddesc.GetSpecDescription(crd, version.Name)
6266
fieldDescYAML := fieldDescToYAML(t, fd)
6367
test.CompareGoldenFile(t, fmt.Sprintf("testdata/%v-spec.golden.yaml", strings.ToLower(resourceKind)), string(fieldDescYAML), test.IgnoreLeadingComments)
64-
fd = getStatusDescription(t, crd)
68+
fd = getStatusDescription(t, crd, version.Name)
6569
fieldDescYAML = fieldDescToYAML(t, fd)
6670
test.CompareGoldenFile(t, fmt.Sprintf("testdata/%v-status.golden.yaml", strings.ToLower(resourceKind)), string(fieldDescYAML), test.IgnoreLeadingComments)
6771
}
6872

69-
func getStatusDescription(t *testing.T, crd *apiextensions.CustomResourceDefinition) fielddesc.FieldDescription {
70-
fd, err := fielddesc.GetStatusDescription(crd)
73+
func getStatusDescription(t *testing.T, crd *apiextensions.CustomResourceDefinition, version string) fielddesc.FieldDescription {
74+
fd, err := fielddesc.GetStatusDescription(crd, version)
7175
if err != nil {
7276
t.Fatalf("error getting status description")
7377
}

pkg/k8s/crds.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,17 @@ func GetVersionFromCRD(crd *apiextensions.CustomResourceDefinition) string {
6565
return PreferredVersion(crd).Name
6666
}
6767

68+
func GetCRDVersionDefinition(crd *apiextensions.CustomResourceDefinition, version string) *apiextensions.CustomResourceDefinitionVersion {
69+
for _, v := range crd.Spec.Versions {
70+
if v.Name == version {
71+
return &v
72+
}
73+
}
74+
panic(fmt.Sprintf("version %q not found", version))
75+
}
76+
77+
// Deprecated: only returns the preferred version
6878
func GetOpenAPIV3SchemaFromCRD(crd *apiextensions.CustomResourceDefinition) *apiextensions.JSONSchemaProps {
69-
panicIfNoVersionPresent(crd)
7079
// Currently KCC CRDs only support one version.
7180
return PreferredVersion(crd).Schema.OpenAPIV3Schema
7281
}

scripts/generate-go-crd-clients/generate-types-file.go

+31-17
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
3434
"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/util/repo"
3535
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
36+
"k8s.io/apimachinery/pkg/util/sets"
3637
"k8s.io/klog/v2"
3738
)
3839

@@ -74,7 +75,7 @@ type svkMap struct {
7475
}
7576

7677
func main() {
77-
resources := make(map[string]*resourceDefinition)
78+
var resources []*resourceDefinition
7879
registerKinds := make(map[string]*svkMap)
7980
crdsDir := repo.GetCRDsPath()
8081
crdsPath, err := filepath.Abs(crdsDir)
@@ -87,8 +88,7 @@ func main() {
8788
}
8889

8990
for _, crdFile := range crdFiles {
90-
fileName := strings.TrimSuffix(crdFile.Name(), ".yaml")
91-
resources[fileName] = constructResourceDefinition(crdsPath, crdFile.Name())
91+
resources = append(resources, constructResourceDefinitions(crdsPath, crdFile.Name())...)
9292
}
9393

9494
for _, rd := range resources {
@@ -261,8 +261,7 @@ func checkAndCreateFolder(dir string) {
261261
}
262262
}
263263

264-
func constructResourceDefinition(crdsPath, crdFile string) *resourceDefinition {
265-
r := &resourceDefinition{}
264+
func constructResourceDefinitions(crdsPath, crdFile string) []*resourceDefinition {
266265
crdFilePath, err := filepath.Abs(path.Join(crdsPath, crdFile))
267266
if err != nil {
268267
log.Fatalf("error getting the absolute representation of path for directory '%v': %v", crdFile, err)
@@ -272,25 +271,40 @@ func constructResourceDefinition(crdsPath, crdFile string) *resourceDefinition {
272271
log.Fatalf("error loading crd from filepath %v: %v", crdFilePath, err)
273272
}
274273

275-
r.CRD = crd
276-
r.Name = crd.Spec.Names.Kind
277-
if err = buildFieldProperties(r, crd); err != nil {
278-
log.Fatalf("error building field properties for %v: %v", r.Name, err)
274+
versionNames := sets.NewString()
275+
for _, crdVersion := range crd.Spec.Versions {
276+
versionNames.Insert(crdVersion.Name)
279277
}
280-
r.Service = strings.TrimSuffix(crd.Spec.Group, k8s.APIDomainSuffix)
281-
r.Kind = strings.ToLower(crd.Spec.Names.Kind)
282278

283-
// TODO: Should we handle multiple versions?
284-
r.Version = k8s.PreferredVersion(crd)
285-
return r
279+
var resources []*resourceDefinition
280+
for _, versionName := range versionNames.List() {
281+
// Don't generate alpha version if we have a beta
282+
if versionName == "v1alpha1" && versionNames.Has("v1beta1") {
283+
continue
284+
}
285+
crdVersionDefinition := k8s.GetCRDVersionDefinition(crd, versionName)
286+
287+
r := &resourceDefinition{}
288+
r.CRD = crd
289+
r.Name = crd.Spec.Names.Kind
290+
if err = buildFieldProperties(r, crd, crdVersionDefinition.Name); err != nil {
291+
log.Fatalf("error building field properties for %v: %v", r.Name, err)
292+
}
293+
r.Service = strings.TrimSuffix(crd.Spec.Group, k8s.APIDomainSuffix)
294+
r.Kind = strings.ToLower(crd.Spec.Names.Kind)
295+
296+
r.Version = crdVersionDefinition
297+
resources = append(resources, r)
298+
}
299+
return resources
286300
}
287301

288-
func buildFieldProperties(r *resourceDefinition, crd *apiextensions.CustomResourceDefinition) error {
289-
specDesc := fielddesc.GetSpecDescription(crd)
302+
func buildFieldProperties(r *resourceDefinition, crd *apiextensions.CustomResourceDefinition, version string) error {
303+
specDesc := fielddesc.GetSpecDescription(crd, version)
290304
specDescriptions := dropRootAndFlattenChildrenDescriptions(specDesc)
291305
r.SpecNestedStructs = make(map[string][]*fieldProperties)
292306
organizeSpecFieldDescriptions(specDescriptions, r)
293-
statusDesc, err := fielddesc.GetStatusDescription(crd)
307+
statusDesc, err := fielddesc.GetStatusDescription(crd, version)
294308
if err != nil {
295309
return fmt.Errorf("error getting status descriptions: %w", err)
296310
}

scripts/generate-google3-docs/resource-reference/main.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ func constructResourceForGVK(gvk schema.GroupVersionKind, smLoader *servicemappi
286286
return nil, fmt.Errorf("error converting status to YAML: %w", err)
287287
}
288288
r.Status = string(statusYaml)
289-
if err = buildFieldDescriptions(r, crd); err != nil {
289+
if err = buildFieldDescriptions(r, crd, gvk.Version); err != nil {
290290
return nil, fmt.Errorf("buildFieldDescriptions: %w", err)
291291
}
292292
r.DefaultReconcileInterval = uint32(reconciliationinterval.MeanReconcileReenqueuePeriod(gvk, smLoader, serviceMetadataLoader).Seconds())
@@ -545,12 +545,12 @@ func stripHeader(sample string) string {
545545
return strings.Trim(res, "\n")
546546
}
547547

548-
func buildFieldDescriptions(r *resource, crd *apiextensions.CustomResourceDefinition) error {
549-
specDesc := fielddesc.GetSpecDescription(crd)
548+
func buildFieldDescriptions(r *resource, crd *apiextensions.CustomResourceDefinition, version string) error {
549+
specDesc := fielddesc.GetSpecDescription(crd, version)
550550
specDescriptions := dropRootAndFlattenChildrenDescriptions(specDesc)
551551
r.SpecDescriptions = fieldDescriptionsToHumanReadable(specDescriptions)
552552
r.SpecDescriptionContainsRequiredIfParentPresent = atLeastOneFieldHasRequiredWhenParentPresentRequirementLevel(specDesc)
553-
statusDesc, err := fielddesc.GetStatusDescription(crd)
553+
statusDesc, err := fielddesc.GetStatusDescription(crd, version)
554554
if err != nil {
555555
return fmt.Errorf("error getting status descriptions: %w", err)
556556
}

0 commit comments

Comments
 (0)