diff --git a/dev/tools/controllerbuilder/README.md b/dev/tools/controllerbuilder/README.md index bcc338bff3..1651dacc48 100644 --- a/dev/tools/controllerbuilder/README.md +++ b/dev/tools/controllerbuilder/README.md @@ -15,8 +15,7 @@ go run . generate-mapper \ # To scaffold generate the SecretManagerSecretVersion controller go run . generate-direct-reconciler \ - --kind SecretManagerSecretVersion \ - --proto-resource SecretVersion \ + --resource SecretManagerSecretVersion:SecretVersion \ --api-version "secretmanager.cnrm.cloud.google.com/v1beta1" \ --service "google.cloud.secretmanager.v1" diff --git a/dev/tools/controllerbuilder/pkg/commands/generatecontroller/generatecontrollercommand.go b/dev/tools/controllerbuilder/pkg/commands/generatecontroller/generatecontrollercommand.go index f07119b009..b5cedefbca 100644 --- a/dev/tools/controllerbuilder/pkg/commands/generatecontroller/generatecontrollercommand.go +++ b/dev/tools/controllerbuilder/pkg/commands/generatecontroller/generatecontrollercommand.go @@ -29,13 +29,11 @@ import ( type GenerateControllerOptions struct { *options.GenerateOptions - Kind string - ProtoName string + Resource options.Resource } func (o *GenerateControllerOptions) BindFlags(cmd *cobra.Command) { - cmd.Flags().StringVarP(&o.ProtoName, "proto-resource", "p", "", "the GCP resource proto name. It should match the name in the proto apis. i.e. For resource google.storage.v1.bucket, the `--proto-resource` should be `Bucket`.") - cmd.Flags().StringVarP(&o.Kind, "kind", "k", "", "the KCC resource Kind. requires `--proto-resource`.") + cmd.Flags().Var(&o.Resource, "resource", "the KRM Kind and the equivalent proto resource separated with a colon. e.g. for resource google.storage.v1.Bucket, the flag should be `StorageBucket:Bucket`.") } func BuildCommand(baseOptions *options.GenerateOptions) *cobra.Command { @@ -47,11 +45,14 @@ func BuildCommand(baseOptions *options.GenerateOptions) *cobra.Command { Use: "generate-controller", Short: "generate the direct controller", PreRunE: func(cmd *cobra.Command, args []string) error { - if opt.Kind == "" { - return fmt.Errorf("--kind is required") + if opt.Resource == (options.Resource{}) { + return fmt.Errorf("--resource flag is required") } - if opt.ProtoName == "" { - return fmt.Errorf("--proto-resource is required") + if opt.Resource.Kind == "" { + return fmt.Errorf("need to specify KRM Kind in --resource") + } + if opt.Resource.ProtoName == "" { + return fmt.Errorf("need to specify proto resource name in --resource") } if baseOptions.APIVersion == "" { @@ -92,9 +93,9 @@ func RunController(ctx context.Context, o *GenerateControllerOptions) error { cArgs := &cctemplate.ControllerArgs{ KCCService: serviceName, KCCVersion: gv.Version, - Kind: o.Kind, - ProtoResource: o.ProtoName, + Kind: o.Resource.Kind, + ProtoResource: o.Resource.ProtoName, ProtoVersion: version, } - return scaffold.Scaffold(serviceName, o.ProtoName, cArgs) + return scaffold.Scaffold(serviceName, o.Resource.ProtoName, cArgs) } diff --git a/dev/tools/controllerbuilder/pkg/commands/generatedirectreconciler/command.go b/dev/tools/controllerbuilder/pkg/commands/generatedirectreconciler/command.go index f2e63bba9e..a77e2d6cc2 100644 --- a/dev/tools/controllerbuilder/pkg/commands/generatedirectreconciler/command.go +++ b/dev/tools/controllerbuilder/pkg/commands/generatedirectreconciler/command.go @@ -29,9 +29,7 @@ import ( type GenerateBasicReconcilerOptions struct { *options.GenerateOptions - Kind string - ProtoName string - // OutputAPIDirectory string + Resource options.Resource APIGoPackagePath string APIDirectory string @@ -39,9 +37,7 @@ type GenerateBasicReconcilerOptions struct { } func (o *GenerateBasicReconcilerOptions) BindFlags(cmd *cobra.Command) { - cmd.Flags().StringVarP(&o.ProtoName, "proto-resource", "p", "", "the GCP resource proto name. It should match the name in the proto apis. i.e. For resource google.storage.v1.bucket, the `--proto-resource` should be `bucket`. If `--kind` is not given, the `--proto-resource` value will also be used as the kind name with a capital letter `Storage`.") - cmd.Flags().StringVarP(&o.Kind, "kind", "k", "", "the KCC resource Kind. requires `--proto-resource`.") - // cmd.Flags().StringVar(&o.OutputAPIDirectory, "output-api", o.OutputAPIDirectory, "base directory for writing APIs") + cmd.Flags().Var(&o.Resource, "resource", "the KRM Kind and the equivalent proto resource separated with a colon. e.g. for resource google.storage.v1.Bucket, the flag should be `StorageBucket:Bucket`") cmd.Flags().StringVar(&o.APIGoPackagePath, "api-go-package-path", o.APIGoPackagePath, "package path") cmd.Flags().StringVar(&o.APIDirectory, "api-dir", o.APIDirectory, "base directory for reading APIs") cmd.Flags().StringVar(&o.OutputMapperDirectory, "output-dir", o.OutputMapperDirectory, "base directory for writing mappers") @@ -73,12 +69,16 @@ func BuildCommand(baseOptions *options.GenerateOptions) *cobra.Command { Use: "generate-direct-reconciler", Short: "[ALPHA] generate a basic direct reconciler that is up and run", PreRunE: func(cmd *cobra.Command, args []string) error { - if opt.Kind == "" { - return fmt.Errorf("--kind is required") + if opt.Resource == (options.Resource{}) { + return fmt.Errorf("--resource flag is required") } - if opt.ProtoName == "" { - return fmt.Errorf("--proto-resource is required") + if opt.Resource.Kind == "" { + return fmt.Errorf("need to specify KRM Kind in --resource") } + if opt.Resource.ProtoName == "" { + return fmt.Errorf("need to specify proto resource name in --resource") + } + if baseOptions.APIVersion == "" { return fmt.Errorf("--api-version is required") } @@ -109,9 +109,7 @@ func RunGenerateBasicReconciler(ctx context.Context, o *GenerateBasicReconcilerO crdOps := &generatetypes.GenerateCRDOptions{ GenerateOptions: o.GenerateOptions, OutputAPIDirectory: o.APIDirectory, - Resources: generatetypes.ResourceList{ - generatetypes.Resource{Kind: o.Kind, ProtoName: o.ProtoName}, - }, + Resources: options.ResourceList{o.Resource}, } if err := generatetypes.RunGenerateCRD(ctx, crdOps); err != nil { return fmt.Errorf("generate types: %w", err) @@ -127,8 +125,7 @@ func RunGenerateBasicReconciler(ctx context.Context, o *GenerateBasicReconcilerO } controllerOps := &generatecontroller.GenerateControllerOptions{ GenerateOptions: o.GenerateOptions, - Kind: o.Kind, - ProtoName: o.ProtoName, + Resource: o.Resource, } if err := generatecontroller.RunController(ctx, controllerOps); err != nil { return fmt.Errorf("generate types: %w", err) diff --git a/dev/tools/controllerbuilder/pkg/commands/generatetypes/generatetypescommand.go b/dev/tools/controllerbuilder/pkg/commands/generatetypes/generatetypescommand.go index 6f7e9cda83..c1deb583af 100644 --- a/dev/tools/controllerbuilder/pkg/commands/generatetypes/generatetypescommand.go +++ b/dev/tools/controllerbuilder/pkg/commands/generatetypes/generatetypescommand.go @@ -29,7 +29,6 @@ import ( "k8s.io/klog/v2" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) type GenerateCRDOptions struct { @@ -38,38 +37,7 @@ type GenerateCRDOptions struct { OutputAPIDirectory string SkipScaffoldFiles bool - Resources ResourceList -} - -type Resource struct { - Kind string - ProtoName string -} - -type ResourceList []Resource - -var _ pflag.Value = &ResourceList{} - -func (r *ResourceList) Type() string { return "resources" } - -func (r *ResourceList) String() string { - var sb strings.Builder - for _, res := range *r { - fmt.Fprintf(&sb, "%s:%s", res.Kind, res.ProtoName) - } - return sb.String() -} - -func (r *ResourceList) Set(s string) error { - tokens := strings.Split(s, ":") - if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" { - return fmt.Errorf("expected [KRMKind]:[ProtoResourceName], got %q", s) - } - *r = append(*r, Resource{ - Kind: tokens[0], - ProtoName: tokens[1], - }) - return nil + Resources options.ResourceList } func (o *GenerateCRDOptions) InitDefaults() error { diff --git a/dev/tools/controllerbuilder/pkg/options/resource.go b/dev/tools/controllerbuilder/pkg/options/resource.go new file mode 100644 index 0000000000..08f908eb9a --- /dev/null +++ b/dev/tools/controllerbuilder/pkg/options/resource.go @@ -0,0 +1,71 @@ +// 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 options + +import ( + "fmt" + "strings" + + "github.com/spf13/pflag" +) + +type Resource struct { + Kind string + ProtoName string +} + +var _ pflag.Value = &Resource{} + +func (r *Resource) Type() string { return "resource" } + +func (r *Resource) String() string { + return fmt.Sprintf("%s:%s", r.Kind, r.ProtoName) +} + +func (r *Resource) Set(s string) error { + tokens := strings.Split(s, ":") + if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" { + return fmt.Errorf("expected [KRMKind]:[ProtoResourceName], got %q", s) + } + r.Kind = tokens[0] + r.ProtoName = tokens[1] + return nil +} + +type ResourceList []Resource + +var _ pflag.Value = &ResourceList{} + +func (r *ResourceList) Type() string { return "resources" } + +func (r *ResourceList) String() string { + var sb strings.Builder + for _, res := range *r { + fmt.Fprintf(&sb, "%s:%s", res.Kind, res.ProtoName) + } + return sb.String() +} + +func (r *ResourceList) Set(s string) error { + tokens := strings.Split(s, ":") + if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" { + return fmt.Errorf("expected [KRMKind]:[ProtoResourceName], got %q", s) + } + *r = append(*r, Resource{ + Kind: tokens[0], + ProtoName: tokens[1], + }) + return nil +} diff --git a/docs/develop-resources/deep-dives/4-add-controller.md b/docs/develop-resources/deep-dives/4-add-controller.md index 7ec6a8e5bc..7044261aab 100644 --- a/docs/develop-resources/deep-dives/4-add-controller.md +++ b/docs/develop-resources/deep-dives/4-add-controller.md @@ -4,7 +4,7 @@ Run the following command to generate a controller template ``` cd dev/tools/controllerbuilder -go run main.go generate-controller --service --api-version --kind --proto-resource +go run main.go generate-controller --service --api-version --resource : ``` Fix the generated code to make your SciFi running!