Skip to content

Commit

Permalink
Merge pull request #1996 from yuwenma/controller-builder
Browse files Browse the repository at this point in the history
feat: templating tool for direct controller builder
  • Loading branch information
google-oss-prow[bot] committed Jun 22, 2024
2 parents bcb4e37 + 6766368 commit 04064f0
Show file tree
Hide file tree
Showing 6 changed files with 571 additions and 0 deletions.
64 changes: 64 additions & 0 deletions dev/tools/controllerbuilder/cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
"fmt"
"os"
"strings"

"github.com/GoogleCloudPlatform/k8s-config-connector/dev/tools/controllerbuilder/scaffold"
"github.com/GoogleCloudPlatform/k8s-config-connector/dev/tools/controllerbuilder/template"
"github.com/spf13/cobra"
)

var (
serviceName string
// TODO: Resource and kind name should be the same. Validation the uppercase/lowercase.
kind string
apiVersion string

addCmd = &cobra.Command{
Use: "add",
Short: "add direct controller",
RunE: func(cmd *cobra.Command, args []string) error {
// TODO(check kcc root)
cArgs := &template.ControllerArgs{
Service: serviceName,
Version: apiVersion,
Kind: kind,
KindToLower: strings.ToLower(kind),
}
path, err := scaffold.BuildControllerPath(serviceName, kind)
if err != nil {
return err
}
return scaffold.Scaffold(path, cArgs)
},
}
)

func init() {
addCmd.PersistentFlags().StringVarP(&apiVersion, "version", "v", "v1alpha1", "the KRM API version. used to import the KRM API")
addCmd.PersistentFlags().StringVarP(&serviceName, "service", "s", "", "the GCP service name")
addCmd.PersistentFlags().StringVarP(&kind, "resourceInKind", "r", "", "the GCP resource name under the GCP service. should be in camel case ")
}

func Execute() {
if err := addCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
18 changes: 18 additions & 0 deletions dev/tools/controllerbuilder/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module github.com/GoogleCloudPlatform/k8s-config-connector/dev/tools/controllerbuilder

go 1.23

require (
github.com/fatih/color v1.17.0
github.com/spf13/cobra v1.8.0
golang.org/x/tools v0.21.0
)

require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.20.0 // indirect
)
27 changes: 27 additions & 0 deletions dev/tools/controllerbuilder/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions dev/tools/controllerbuilder/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import "github.com/GoogleCloudPlatform/k8s-config-connector/dev/tools/controllerbuilder/cmd"

func main() {
cmd.Execute()
}
102 changes: 102 additions & 0 deletions dev/tools/controllerbuilder/scaffold/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package scaffold

import (
"bytes"
"fmt"
"os"
"path/filepath"
"strings"
"text/template"

ccTemplate "github.com/GoogleCloudPlatform/k8s-config-connector/dev/tools/controllerbuilder/template"
"github.com/fatih/color"
"golang.org/x/tools/imports"
)

const (
currRelPath = "dev/tools/controllerbuilder"
directControllerRelPath = "pkg/controller/direct"
)

func Scaffold(path 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 {
return err
}
// Write the generated controller.go to pkg/controller/direct/<service>/<resource>_controller.go
if err := WriteToFile(path, out.Bytes()); err != nil {
return err
}
// Format and adjust the go imports in the generated controller file.
if err := FormatImports(path, out.Bytes()); err != nil {
return err
}
color.HiGreen("New controller %s\nEnjoy it!\n", path)
return nil
}

func BuildControllerPath(service, kind string) (string, error) {
pwd, err := os.Getwd()
if err != nil {
return "", fmt.Errorf("get current working directory: %w", err)
}
abs, err := filepath.Abs(pwd)
if err != nil {
return "", fmt.Errorf("get absolute path %s: %w", pwd, err)
}
seg := strings.Split(abs, currRelPath)
controllerDir := filepath.Join(seg[0], directControllerRelPath, service)
err = os.MkdirAll(controllerDir, os.ModePerm)
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 {
return "", fmt.Errorf("controller file %s may already exist: %w", controllerFilePath, err)
}
return controllerFilePath, nil
}

func FormatImports(path string, out []byte) error {
importOps := &imports.Options{
Comments: true,
AllErrors: true,
Fragment: true}
formatedOut, err := imports.Process(path, out, importOps)
if err != nil {
return fmt.Errorf("format controller file %s: %w", path, err)
}
return WriteToFile(path, formatedOut)
}

func WriteToFile(path string, out []byte) error {
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("create controller file %s: %w", path, err)
}
err = os.WriteFile(path, out, 0644)
if err != nil {
return fmt.Errorf("write controller file %s: %w", path, err)
}
defer f.Close()
return nil
}
Loading

0 comments on commit 04064f0

Please sign in to comment.