Skip to content

Commit ac11e93

Browse files
authored
fix parameter typo and clientSet conditional (#2902)
1 parent 3990b65 commit ac11e93

File tree

5 files changed

+515
-484
lines changed

5 files changed

+515
-484
lines changed

tools/scaffolder/internal/generate/controller.go

Lines changed: 2 additions & 356 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,6 @@ const (
2727
pkgCtrlState = "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/state"
2828
)
2929

30-
func getAPIPackage(apiVersion string) string {
31-
return fmt.Sprintf("github.com/mongodb/mongodb-atlas-kubernetes/v2/api/%s", apiVersion)
32-
}
33-
3430
// FromConfig generates controllers and handlers based on the parsed CRD result file
3531
func FromConfig(resultPath, crdKind, controllerOutDir, indexerOutDir, typesPath string, override bool) error {
3632
parsedConfig, err := ParseCRDConfig(resultPath, crdKind)
@@ -239,356 +235,6 @@ func generateControllerFileWithMultipleVersions(dir, controllerName, resourceNam
239235
return f.Save(fileName)
240236
}
241237

242-
func generatePackageLevelTranslationHelper(f *jen.File) {
243-
f.Comment("getTranslationRequest creates a translation request for converting entities between API and AKO.")
244-
f.Comment("This is a package-level function that can be called from any handler.")
245-
f.Func().Id("getTranslationRequest").Params(
246-
jen.Id("ctx").Qual("context", "Context"),
247-
jen.Id("kubeClient").Qual("sigs.k8s.io/controller-runtime/pkg/client", "Client"),
248-
jen.Id("crdName").String(),
249-
jen.Id("storageVersion").String(),
250-
jen.Id("targetVersion").String(),
251-
).Params(
252-
jen.Op("*").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/generated/translate", "Request"),
253-
jen.Error(),
254-
).Block(
255-
jen.Id("crd").Op(":=").Op("&").Qual("k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1", "CustomResourceDefinition").Values(),
256-
jen.Id("err").Op(":=").Id("kubeClient").Dot("Get").Call(
257-
jen.Id("ctx"),
258-
jen.Qual("sigs.k8s.io/controller-runtime/pkg/client", "ObjectKey").Values(jen.Dict{
259-
jen.Id("Name"): jen.Id("crdName"),
260-
}),
261-
jen.Id("crd"),
262-
),
263-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
264-
jen.Return(jen.Nil(), jen.Qual("fmt", "Errorf").Call(
265-
jen.Lit("failed to resolve CRD %s: %w"),
266-
jen.Id("crdName"),
267-
jen.Id("err"),
268-
)),
269-
),
270-
jen.Line(),
271-
jen.List(jen.Id("translator"), jen.Id("err")).Op(":=").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/generated/translate", "NewTranslator").Call(
272-
jen.Id("crd"),
273-
jen.Id("storageVersion"),
274-
jen.Id("targetVersion"),
275-
),
276-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
277-
jen.Return(jen.Nil(), jen.Qual("fmt", "Errorf").Call(
278-
jen.Lit("failed to setup translator: %w"),
279-
jen.Id("err"),
280-
)),
281-
),
282-
jen.Line(),
283-
jen.Return(jen.Op("&").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/generated/translate", "Request").Values(jen.Dict{
284-
jen.Id("Translator"): jen.Id("translator"),
285-
jen.Id("Dependencies"): jen.Nil(),
286-
}), jen.Nil()),
287-
)
288-
}
289-
290-
func generateMainHandlerFile(dir, resourceName, typesPath string, mappings []MappingWithConfig, refsByKind map[string][]ReferenceField, config *ParsedConfig) error {
291-
atlasResourceName := strings.ToLower(resourceName)
292-
apiPkg := typesPath
293-
294-
f := jen.NewFile(atlasResourceName)
295-
AddLicenseHeader(f)
296-
297-
f.ImportAlias(pkgCtrlState, "ctrlstate")
298-
f.ImportAlias("k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1", "apiextensionsv1")
299-
f.ImportAlias(apiPkg, "akov2generated")
300-
301-
f.Comment("getHandlerForResource selects the appropriate version-specific handler based on which resource spec version is set")
302-
f.Func().Params(jen.Id("h").Op("*").Id("Handler")).Id("getHandlerForResource").Params(
303-
jen.Id("ctx").Qual("context", "Context"),
304-
jen.Id(strings.ToLower(resourceName)).Op("*").Qual(apiPkg, resourceName),
305-
).Params(jen.Qual(pkgCtrlState, "StateHandler").Types(jen.Qual(apiPkg, resourceName)), jen.Error()).Block(
306-
jen.List(jen.Id("atlasClients"), jen.Id("err")).Op(":=").Id("h").Dot("getSDKClientSet").Call(
307-
jen.Id("ctx"),
308-
jen.Id("group"),
309-
),
310-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
311-
jen.Return(jen.Nil(), jen.Id("err")),
312-
),
313-
314-
jen.Comment("Check which resource spec version is set and validate that only one is specified"),
315-
jen.Var().Id("versionCount").Int(),
316-
jen.Var().Id("selectedHandler").Qual(pkgCtrlState, "StateHandler").Types(jen.Qual(apiPkg, resourceName)),
317-
jen.Line(),
318-
jen.CustomFunc(jen.Options{Multi: true}, func(g *jen.Group) {
319-
for _, mapping := range mappings {
320-
versionSuffix := mapping.Version
321-
// Capitalize first letter of version (e.g., v20250312 -> V20250312)
322-
capitalizedVersion := strings.ToUpper(string(versionSuffix[0])) + versionSuffix[1:]
323-
// Construct CRD name: {plural}.{group}
324-
crdName := config.PluralName + "." + config.CRDGroup
325-
sdkImportPathSplit := strings.Split(mapping.OpenAPIConfig.Package, "/")
326-
sdkVersionSuffix := strings.TrimPrefix(sdkImportPathSplit[len(sdkImportPathSplit)-2], "v")
327-
328-
g.If(jen.Id(strings.ToLower(resourceName)).Dot("Spec").Dot(capitalizedVersion).Op("!=").Nil()).Block(
329-
330-
jen.List(jen.Id("translationReq"), jen.Id("err")).Op(":=").Id("getTranslationRequest").Call(
331-
jen.Id("ctx"),
332-
jen.Id("h").Dot("Client"),
333-
jen.Lit(crdName),
334-
jen.Lit(config.StorageVersion),
335-
jen.Lit(versionSuffix),
336-
),
337-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
338-
jen.Return(jen.Nil(), jen.Id("err")),
339-
),
340-
jen.Id("versionCount").Op("++"),
341-
jen.Id("selectedHandler").
342-
Op("=").Id("h").
343-
Dot("handler"+versionSuffix).
344-
Call(
345-
jen.Id("h").
346-
Dot("Client"),
347-
jen.Id("atlasClients").Dot("SdkClient"+sdkVersionSuffix),
348-
jen.Id("translationReq"),
349-
),
350-
)
351-
}
352-
}),
353-
jen.Line(),
354-
jen.If(jen.Id("versionCount").Op("==").Lit(0)).Block(
355-
jen.Return(jen.Nil().Op(",").Qual("fmt", "Errorf").Call(jen.Lit("no resource spec version specified - please set one of the available spec versions"))),
356-
),
357-
jen.If(jen.Id("versionCount").Op(">").Lit(1)).Block(
358-
jen.Return(jen.Nil().Op(",").Qual("fmt", "Errorf").Call(jen.Lit("multiple resource spec versions specified - please set only one spec version"))),
359-
),
360-
jen.Return(jen.Id("selectedHandler").Op(",").Nil()),
361-
)
362-
363-
generateDelegatingStateHandlers(f, resourceName, apiPkg, refsByKind)
364-
// ClientSet and translation request helpers
365-
generateSDKClientSetMethod(f, resourceName, apiPkg)
366-
367-
// Generate package-level helper function attached to the handler
368-
generatePackageLevelTranslationHelper(f)
369-
370-
fileName := filepath.Join(dir, "handler.go")
371-
return f.Save(fileName)
372-
}
373-
374-
func generateDelegatingStateHandlers(f *jen.File, resourceName, apiPkg string, refsByKind map[string][]ReferenceField) {
375-
handlers := []string{
376-
"HandleInitial",
377-
"HandleImportRequested",
378-
"HandleImported",
379-
"HandleCreating",
380-
"HandleCreated",
381-
"HandleUpdating",
382-
"HandleUpdated",
383-
"HandleDeletionRequested",
384-
"HandleDeleting",
385-
}
386-
startStateMap := map[string]string{
387-
"HandleInitial": "StateInitial",
388-
"HandleImportRequested": "StateImportRequested",
389-
"HandleImported": "StateImported",
390-
"HandleCreating": "StateCreating",
391-
"HandleCreated": "StateCreated",
392-
"HandleUpdating": "StateUpdating",
393-
"HandleUpdated": "StateUpdated",
394-
"HandleDeletionRequested": "StateDeletionRequested",
395-
"HandleDeleting": "StateDeleting",
396-
}
397-
398-
for _, handlerName := range handlers {
399-
f.Comment(fmt.Sprintf("%s delegates to the version-specific handler", handlerName))
400-
f.Func().Params(jen.Id("h").Op("*").Id("Handler")).Id(handlerName).Params(
401-
jen.Id("ctx").Qual("context", "Context"),
402-
jen.Id(strings.ToLower(resourceName)).Op("*").Qual(apiPkg, resourceName),
403-
).Params(
404-
jen.Qual(pkgCtrlState, "Result"),
405-
jen.Error(),
406-
).Block(
407-
jen.List(jen.Id("handler"), jen.Id("err")).
408-
Op(":=").
409-
Id("h").
410-
Dot("getHandlerForResource").
411-
Call(jen.Id("ctx"), jen.Id(strings.ToLower(resourceName))),
412-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
413-
jen.Return(jen.Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/result", "Error").Call(
414-
jen.Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/state", startStateMap[handlerName]),
415-
jen.Id("err"),
416-
)),
417-
),
418-
jen.Return(jen.Id("handler").Dot(handlerName).Call(jen.Id("ctx"), jen.Id(strings.ToLower(resourceName)))),
419-
)
420-
}
421-
422-
f.Comment("For returns the resource and predicates for the controller")
423-
f.Func().Params(jen.Id("h").Op("*").Id("Handler")).Id("For").Params().Params(
424-
jen.Qual("sigs.k8s.io/controller-runtime/pkg/client", "Object"),
425-
jen.Qual("sigs.k8s.io/controller-runtime/pkg/builder", "Predicates"),
426-
).Block(
427-
jen.Id("obj").Op(":=").Op("&").Qual(apiPkg, resourceName).Values(),
428-
jen.Return(
429-
jen.Id("obj"),
430-
jen.Qual("sigs.k8s.io/controller-runtime/pkg/builder", "WithPredicates").Call(jen.Id("h").Dot("predicates").Op("...")),
431-
),
432-
)
433-
434-
generateMapperFunctions(f, resourceName, apiPkg, refsByKind)
435-
436-
generateSetupWithManager(f, resourceName, refsByKind)
437-
}
438-
439-
func generateSDKClientSetMethod(f *jen.File, resourceName, apiPkg string) {
440-
resourceLower := strings.ToLower(resourceName)
441-
442-
f.Comment("getSDKClientSet creates an Atlas SDK client set using credentials from the resource's connection secret")
443-
f.Func().Params(
444-
jen.Id("h").Op("*").Id("Handler"),
445-
).Id("getSDKClientSet").Params(
446-
jen.Id("ctx").Qual("context", "Context"),
447-
jen.Id(resourceLower).Op("*").Qual(apiPkg, resourceName),
448-
).Params(
449-
jen.Op("*").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/atlas", "ClientSet"),
450-
jen.Error(),
451-
).Block(
452-
jen.List(jen.Id("connectionConfig"), jen.Id("err")).Op(":=").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/controller/reconciler", "GetConnectionConfig").Call(
453-
jen.Id("ctx"),
454-
jen.Id("h").Dot("Client"),
455-
jen.Op("&").Qual("sigs.k8s.io/controller-runtime/pkg/client", "ObjectKey").Values(jen.Dict{
456-
jen.Id("Namespace"): jen.Id(resourceLower).Dot("Namespace"),
457-
jen.Id("Name"): jen.Id(resourceLower).Dot("Spec").Dot("ConnectionSecretRef").Dot("Name"),
458-
}),
459-
jen.Op("&").Id("h").Dot("GlobalSecretRef"),
460-
),
461-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
462-
jen.Return(jen.Nil(), jen.Qual("fmt", "Errorf").Call(
463-
jen.Lit("failed to resolve Atlas credentials: %w"),
464-
jen.Id("err"),
465-
)),
466-
),
467-
jen.Line(),
468-
jen.List(jen.Id("clientSet"), jen.Id("err")).Op(":=").Id("h").Dot("AtlasProvider").Dot("SdkClientSet").Call(
469-
jen.Id("ctx"),
470-
jen.Id("connectionConfig").Dot("Credentials"),
471-
jen.Id("h").Dot("Log"),
472-
),
473-
jen.If(jen.Id("err").Op("!=").Nil()).Block(
474-
jen.Return(jen.Nil(), jen.Qual("fmt", "Errorf").Call(
475-
jen.Lit("failed to setup Atlas SDK client: %w"),
476-
jen.Id("err"),
477-
)),
478-
),
479-
jen.Line(),
480-
jen.Return(jen.Id("clientSet"), jen.Nil()),
481-
)
482-
}
483-
484-
func generateVersionHandlerFile(dir, resourceName, typesPath string, mapping MappingWithConfig, override bool) error {
485-
atlasResourceName := strings.ToLower(resourceName)
486-
versionSuffix := mapping.Version
487-
apiPkg := typesPath
488-
sdkImportPath := mapping.OpenAPIConfig.Package
489-
490-
fileName := filepath.Join(dir, "handler_"+versionSuffix+".go")
491-
492-
// Check if a versioned handler file exists
493-
if !override {
494-
if _, err := os.Stat(fileName); err == nil {
495-
fmt.Printf("Skipping versioned handler %s (already exists, use --override to overwrite)\n", fileName)
496-
return nil
497-
}
498-
}
499-
500-
f := jen.NewFile(atlasResourceName)
501-
AddLicenseHeader(f)
502-
503-
f.ImportAlias(pkgCtrlState, "ctrlstate")
504-
f.ImportAlias(apiPkg, "akov2generated")
505-
f.ImportAlias(sdkImportPath, versionSuffix+"sdk")
506-
507-
f.Type().Id("Handler"+versionSuffix).Struct(
508-
jen.Id("kubeClient").Qual("sigs.k8s.io/controller-runtime/pkg/client", "Client"),
509-
jen.Id("atlasClient").Op("*").Qual(sdkImportPath, "APIClient"),
510-
jen.Id("translationRequest").Op("*").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/generated/translate", "Request"),
511-
)
512-
513-
f.Func().Id("NewHandler"+versionSuffix).Params(
514-
jen.Id("kubeClient").Qual("sigs.k8s.io/controller-runtime/pkg/client", "Client"),
515-
jen.Id("atlasClient").Op("*").Qual(sdkImportPath, "APIClient"),
516-
jen.Id("translationRequest").Op("*").Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/generated/translate", "Request"),
517-
).Op("*").Id("Handler" + versionSuffix).Block(
518-
jen.Return(jen.Op("&").Id("Handler" + versionSuffix).Values(jen.Dict{
519-
jen.Id("kubeClient"): jen.Id("kubeClient"),
520-
jen.Id("atlasClient"): jen.Id("atlasClient"),
521-
jen.Id("translationRequest"): jen.Id("translationRequest"),
522-
})),
523-
)
524-
525-
generateVersionStateHandlers(f, resourceName, apiPkg, versionSuffix)
526-
527-
// Generate For and SetupWithManager methods to satisfy StateHandler interface
528-
generateVersionInterfaceMethods(f, resourceName, apiPkg, versionSuffix)
529-
530-
return f.Save(fileName)
531-
}
532-
533-
func generateVersionStateHandlers(f *jen.File, resourceName, apiPkg, versionSuffix string) {
534-
handlers := []struct {
535-
name string
536-
nextState string
537-
message string
538-
}{
539-
{"HandleInitial", "StateUpdated", "Updated Atlas" + resourceName + "."},
540-
{"HandleImportRequested", "StateImported", "Import completed"},
541-
{"HandleImported", "StateUpdated", "Ready"},
542-
{"HandleCreating", "StateCreated", "Resource created"},
543-
{"HandleCreated", "StateUpdated", "Ready"},
544-
{"HandleUpdating", "StateUpdated", "Update completed"},
545-
{"HandleUpdated", "StateUpdated", "Ready"},
546-
{"HandleDeletionRequested", "StateDeleting", "Deletion started"},
547-
{"HandleDeleting", "StateDeleted", "Deleted"},
548-
}
549-
550-
for _, handler := range handlers {
551-
f.Comment(fmt.Sprintf("%s handles the %s state for version %s", handler.name, strings.ToLower(strings.TrimPrefix(handler.name, "Handle")), versionSuffix))
552-
f.Func().Params(jen.Id("h").Op("*").Id("Handler"+versionSuffix)).Id(handler.name).Params(
553-
jen.Id("ctx").Qual("context", "Context"),
554-
jen.Id(strings.ToLower(resourceName)).Op("*").Qual(apiPkg, resourceName),
555-
).Params(
556-
jen.Qual(pkgCtrlState, "Result"),
557-
jen.Error(),
558-
).Block(
559-
jen.Comment("TODO: Implement "+strings.ToLower(strings.TrimPrefix(handler.name, "Handle"))+" state logic"),
560-
jen.Comment("TODO: Use h.atlasProvider.SdkClientSet(ctx, h.globalSecretRef, h.log) to get Atlas SDK client"),
561-
jen.Return(jen.Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/result", "NextState").Call(
562-
jen.Qual("github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/state", handler.nextState),
563-
jen.Lit(handler.message),
564-
)),
565-
)
566-
}
567-
}
568-
569-
// generateVersionInterfaceMethods generates For and SetupWithManager methods for version-specific handlers
570-
func generateVersionInterfaceMethods(f *jen.File, resourceName, apiPkg, versionSuffix string) {
571-
// For method
572-
f.Comment("For returns the resource and predicates for the controller")
573-
f.Func().Params(jen.Id("h").Op("*").Id("Handler"+versionSuffix)).Id("For").Params().Params(
574-
jen.Qual("sigs.k8s.io/controller-runtime/pkg/client", "Object"),
575-
jen.Qual("sigs.k8s.io/controller-runtime/pkg/builder", "Predicates"),
576-
).Block(
577-
jen.Return(jen.Op("&").Qual(apiPkg, resourceName).Values(), jen.Qual("sigs.k8s.io/controller-runtime/pkg/builder", "WithPredicates").Call()),
578-
)
579-
580-
// SetupWithManager method
581-
f.Comment("SetupWithManager sets up the controller with the Manager")
582-
f.Func().Params(jen.Id("h").Op("*").Id("Handler"+versionSuffix)).Id("SetupWithManager").Params(
583-
jen.Id("mgr").Qual("sigs.k8s.io/controller-runtime", "Manager"),
584-
jen.Id("rec").Qual("sigs.k8s.io/controller-runtime/pkg/reconcile", "Reconciler"),
585-
jen.Id("defaultOptions").Qual("sigs.k8s.io/controller-runtime/pkg/controller", "Options"),
586-
).Error().Block(
587-
jen.Comment("This method is not used for version-specific handlers but required by StateHandler interface"),
588-
jen.Return(jen.Nil()),
589-
)
590-
}
591-
592238
func generateSetupWithManager(f *jen.File, resourceName string, refsByKind map[string][]ReferenceField) {
593239
f.Comment("SetupWithManager sets up the controller with the Manager")
594240

@@ -642,7 +288,7 @@ func generateMapperFunctions(f *jen.File, resourceName, apiPkg string, refsByKin
642288
case "credentials":
643289
generateIndexerBasedMapperFunction(f, resourceName, apiPkg, kind, mapperFuncName, "CredentialsIndexMapperFunc")
644290
case "resource":
645-
generateResourceMapperFunction(f, resourceName, apiPkg, kind, mapperFuncName, refs)
291+
generateResourceMapperFunction(f, resourceName, apiPkg, kind, mapperFuncName)
646292
}
647293
}
648294
}
@@ -666,7 +312,7 @@ func generateIndexerBasedMapperFunction(f *jen.File, resourceName, apiPkg, refer
666312
)
667313
}
668314

669-
func generateResourceMapperFunction(f *jen.File, resourceName, apiPkg, referencedKind, mapperFuncName string, refs []ReferenceField) {
315+
func generateResourceMapperFunction(f *jen.File, resourceName, apiPkg, referencedKind, mapperFuncName string) {
670316
indexName := fmt.Sprintf("%sBy%sIndex", resourceName, referencedKind)
671317
listTypeName := fmt.Sprintf("%sList", resourceName)
672318
watchedType := getWatchedType(referencedKind)

0 commit comments

Comments
 (0)