Skip to content

Commit

Permalink
Generate helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
gemmahou committed Aug 14, 2024
1 parent fa015b8 commit fd8800e
Show file tree
Hide file tree
Showing 6 changed files with 394 additions and 26 deletions.
6 changes: 1 addition & 5 deletions dev/tools/controllerbuilder/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,7 @@ func buildAddCommand(baseOptions *options.GenerateOptions) *cobra.Command {
Kind: kind,
KindToLower: strings.ToLower(kind),
}
path, err := scaffold.BuildControllerPath(baseOptions.ServiceName, kind)
if err != nil {
return err
}
return scaffold.Scaffold(path, cArgs)
return scaffold.Scaffold(baseOptions.ServiceName, kind, cArgs)
},
}
addCmd.PersistentFlags().StringVarP(&kind, "resourceInKind", "r", "", "the GCP resource name under the GCP service. should be in camel case ")
Expand Down
85 changes: 71 additions & 14 deletions dev/tools/controllerbuilder/scaffold/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,29 +34,78 @@ const (
directControllerRelPath = "pkg/controller/direct"
)

func Scaffold(path string, cArgs *ccTemplate.ControllerArgs) error {
func Scaffold(service, kind string, cArgs *ccTemplate.ControllerArgs) error {
var errs []error
if err := generateController(service, kind, cArgs); err != nil {
errs = append(errs, err)
}
if err := generateControllerHelpers(service, kind, cArgs); err != nil {
errs = append(errs, err)
}
if len(errs) != 0 {
var finalError []string
for _, err := range errs {
finalError = append(finalError, err.Error())
}
return fmt.Errorf("multiple errors occurred:\n%s", strings.Join(finalError, "\n"))
}
return nil
}

func generateController(service, kind string, cArgs *ccTemplate.ControllerArgs) error {
tmpl, err := template.New(cArgs.Kind).Parse(ccTemplate.ControllerTemplate)
if err != nil {
return fmt.Errorf("parse controller template: %s", err)
}
// Apply the `service` and `resource` args to the controller template
out := &bytes.Buffer{}
if err := tmpl.Execute(out, cArgs); err != nil {
// Apply the `service` and `resource` args to the controller and external resource templates
controllerOutput := &bytes.Buffer{}
if err := tmpl.Execute(controllerOutput, cArgs); err != nil {
return err
}

controllerFilePath, err := buildControllerPath(service, kind)
if err != nil {
return err
}

// Write the generated controller.go to pkg/controller/direct/<service>/<resource>_controller.go
if err := WriteToFile(path, out.Bytes()); err != nil {
if err := WriteToFile(controllerFilePath, controllerOutput.Bytes()); err != nil {
return err
}
// Format and adjust the go imports in the generated controller file.
if err := FormatImports(path, out.Bytes()); err != nil {
if err := FormatImports(controllerFilePath, controllerOutput.Bytes()); err != nil {
return err
}
color.HiGreen("New controller %s\nEnjoy it!\n", path)
color.HiGreen("New controller %s has been generated. \nEnjoy it!\n", kind)
return nil
}

func BuildControllerPath(service, kind string) (string, error) {
func generateControllerHelpers(service, kind string, cArgs *ccTemplate.ControllerArgs) error {
// Generate externalresourece.go used for the controller
externalResourcetmpl, err := template.New(cArgs.Kind).Parse(ccTemplate.ExternalResourceTemplate)
if err != nil {
return fmt.Errorf("parse external resource template: %s", externalResourcetmpl)
}
externalResourceOutput := &bytes.Buffer{}
if err := externalResourcetmpl.Execute(externalResourceOutput, cArgs); err != nil {
return err
}
externalResourceFilePath, err := buildExternalResourcePath(service, kind)
if err != nil {
return err
}
// Write the generated <resource>_externalresource.go to pkg/controller/direct/<service>/<resource>_externalresource.go
if err := WriteToFile(externalResourceFilePath, externalResourceOutput.Bytes()); err != nil {
return err
}
if err := FormatImports(externalResourceFilePath, externalResourceOutput.Bytes()); err != nil {
return err
}
color.HiGreen("New helpers for controller %s has been generated.", kind)
return nil
}

func buildResourcePath(service, filename string) (string, error) {
pwd, err := os.Getwd()
if err != nil {
return "", fmt.Errorf("get current working directory: %w", err)
Expand All @@ -71,16 +120,23 @@ func BuildControllerPath(service, kind string) (string, error) {
if err != nil {
return "", fmt.Errorf("create controller directory %s: %w", controllerDir, err)
}
controllerFilePath := filepath.Join(controllerDir, strings.ToLower(kind)+"_controller.go")
if _, err = os.Stat(controllerFilePath); err != nil {
resourceFilePath := filepath.Join(controllerDir, filename)
if _, err = os.Stat(resourceFilePath); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return "", fmt.Errorf("could not stat path %s: %w", controllerFilePath, err)
return "", fmt.Errorf("could not stat path %s: %w", resourceFilePath, err)
}
// otherwise create the file
return controllerFilePath, nil
return resourceFilePath, nil
}
return "", fmt.Errorf("file %s already exist", resourceFilePath)
}

func buildControllerPath(service, kind string) (string, error) {
return buildResourcePath(service, strings.ToLower(kind)+"_controller.go")
}

return "", fmt.Errorf("controller file %s may already exist:", controllerFilePath)
func buildExternalResourcePath(service, kind string) (string, error) {
return buildResourcePath(service, strings.ToLower(kind)+"_externalresource.go")
}

func FormatImports(path string, out []byte) error {
Expand All @@ -99,7 +155,8 @@ func WriteToFile(path string, out []byte) error {
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return fmt.Errorf("failed to create directory %q: %w", filepath.Dir(path), err)
}
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
// Use O_TRUNC to truncate the file
f, err := os.OpenFile(path, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
Expand Down
7 changes: 6 additions & 1 deletion dev/tools/controllerbuilder/template/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
const ctrlName = "{{.Service}}-controller"
const (
ctrlName = "{{.Service}}-controller"
// TODO(user): Confirm service domain
serviceDomain = "//{{.Service}}.googleapis.com"
)
func init() {
registry.RegisterModel(krm.GroupVersionKind, NewModel)
Expand Down Expand Up @@ -323,3 +327,4 @@ func SetStatus(u *unstructured.Unstructured, typedStatus any) error {
return nil
}
`
8 changes: 2 additions & 6 deletions dev/tools/controllerbuilder/template/externalresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ import (
"strings"
)
const (
// TODO(user): Add service domain
serviceDomain = "//{{.Service}}.googleapis.com"
)

// TODO(user): Define resource identity
type {{.Kind}}Identity struct {
project string
Expand All @@ -51,7 +46,7 @@ func (c *{{.Kind}}Identity) ExternalRef() *string {
}
// BuildIDFromExternal builds a {{.Kind}}Identity from a external reference
func BuildIDFromExternal(external string) (*{{.Kind}}Identity, error) {
func BuildIDFromExternal(externalRef string) (*{{.Kind}}Identity, error) {
// TODO(user): Build resource identity from external reference
if !strings.HasPrefix(externalRef, serviceDomain) {
return nil, fmt.Errorf("externalRef should have prefix %s, got %s", serviceDomain, externalRef)
Expand Down Expand Up @@ -80,3 +75,4 @@ func BuildID(project, location string) *{{.Kind}}Identity {
{{.KindToLower}}: {{.KindToLower}},
}
}
`
Loading

0 comments on commit fd8800e

Please sign in to comment.