diff --git a/cmd/internal/codegen/parse/parser.go b/cmd/internal/codegen/parse/parser.go index 8d5b5289912..0199a91fe8b 100644 --- a/cmd/internal/codegen/parse/parser.go +++ b/cmd/internal/codegen/parse/parser.go @@ -81,6 +81,11 @@ func NewAPIs(context *generator.Context, arguments *args.GeneratorArgs) *APIs { // e.g. if there is an // +kubebuilder:informer annotation for Pods, then there // should also be a // +kubebuilder:rbac annotation for Pods func (b *APIs) verifyRBACAnnotations() { + parseOption := b.arguments.CustomArgs.(*ParseOptions) + if parseOption.SkipRBACValidation { + log.Println("skipping RBAC validations") + return + } err := rbacMatchesInformers(b.Informers, b.Rules) if err != nil { log.Fatal(err) @@ -141,7 +146,8 @@ func rbacMatchesInformers(informers map[v1.GroupVersionKind]bool, rbacRules []rb } if !found { return fmt.Errorf("Missing rbac rule for %s.%s. Add with // +kubebuilder:rbac:groups=%s,"+ - "resources=%s,verbs=get;list;watch", gvk.Group, gvk.Kind, gvk.Group, + "resources=%s,verbs=get;list;watch comment on controller struct "+ + "or run the command with '--skip-rbac-validation' arg", gvk.Group, gvk.Kind, gvk.Group, inflect.NewDefaultRuleset().Pluralize(strings.ToLower(gvk.Kind))) } } diff --git a/cmd/internal/codegen/parse/util.go b/cmd/internal/codegen/parse/util.go index f4fd31a80b0..2f5cf00b4d5 100644 --- a/cmd/internal/codegen/parse/util.go +++ b/cmd/internal/codegen/parse/util.go @@ -27,7 +27,11 @@ import ( ) type ParseOptions struct { - SkipMapValidation bool + SkipMapValidation bool + + // SkipRBACValidation flag determines whether to check RBAC annotations + // for the controller or not at parse stage. + SkipRBACValidation bool } // IsAPIResource returns true if t has a +resource/+kubebuilder:resource comment tag diff --git a/cmd/kubebuilder-gen/codegen/run/generator.go b/cmd/kubebuilder-gen/codegen/run/generator.go index b1090808adc..55c5c03f123 100644 --- a/cmd/kubebuilder-gen/codegen/run/generator.go +++ b/cmd/kubebuilder-gen/codegen/run/generator.go @@ -20,9 +20,9 @@ import ( "github.com/golang/glog" "github.com/kubernetes-sigs/kubebuilder/cmd/internal/codegen/parse" "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder-gen/codegen" + "github.com/spf13/pflag" "k8s.io/gengo/args" "k8s.io/gengo/generator" - "github.com/spf13/pflag" ) // CodeGenerator generates code for Kubernetes resources and controllers @@ -54,6 +54,8 @@ func (g *CodeGenerator) Execute() error { customArgs := &parse.ParseOptions{} pflag.CommandLine.BoolVar(&customArgs.SkipMapValidation, "skip-map-validation", true, "if set to true, skip generating validation schema for map type in CRD.") + pflag.CommandLine.BoolVar(&customArgs.SkipRBACValidation, "skip-rbac-validation", false, + "if set to true, skip validation for RBAC annotations for the controller.") arguments.CustomArgs = customArgs arguments.OutputFileBaseName = g.OutputFileBaseName diff --git a/cmd/kubebuilder/create/controller/run.go b/cmd/kubebuilder/create/controller/run.go index 07f60326052..e0cc5b45950 100644 --- a/cmd/kubebuilder/create/controller/run.go +++ b/cmd/kubebuilder/create/controller/run.go @@ -21,18 +21,20 @@ import ( "log" "os" + "strings" + createutil "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/create/util" generatecmd "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/generate" "github.com/kubernetes-sigs/kubebuilder/cmd/kubebuilder/util" "github.com/markbates/inflect" "github.com/spf13/cobra" - "strings" ) type ControllerArguments struct { - nonNamespacedKind bool - generate bool - CoreType bool + nonNamespacedKind bool + generate bool + CoreType bool + SkipRBACValidation bool } func AddCreateController(cmd *cobra.Command) { @@ -59,6 +61,7 @@ kubebuilder create controller --group apps --version v1beta2 --kind Deployment - createControllerCmd.Flags().BoolVar(&c.nonNamespacedKind, "non-namespaced", false, "if set, the API kind will be non namespaced") createControllerCmd.Flags().BoolVar(&c.generate, "generate", true, "generate controller code") createControllerCmd.Flags().BoolVar(&c.CoreType, "core-type", false, "generate controller for core type") + createControllerCmd.Flags().BoolVar(&c.SkipRBACValidation, "skip-rbac-validation", false, "if set to true, skip validation for RBAC annotations for the controller.") cmd.AddCommand(createControllerCmd) } @@ -77,6 +80,9 @@ func (c *ControllerArguments) RunCreateController(cmd *cobra.Command, args []str if c.generate { fmt.Printf("Generating code for new controller... " + "Regenerate after editing controller files by running `kubebuilder generate clean; kubebuilder generate`.\n") + if c.SkipRBACValidation { + args = append(args, "--skip-rbac-validation") + } generatecmd.RunGenerate(cmd, args) } fmt.Printf("Next: Run the controller and create an instance with:\n" + diff --git a/cmd/kubebuilder/create/resource/run.go b/cmd/kubebuilder/create/resource/run.go index f698670aab9..1723c80c0af 100644 --- a/cmd/kubebuilder/create/resource/run.go +++ b/cmd/kubebuilder/create/resource/run.go @@ -30,9 +30,12 @@ import ( "github.com/spf13/cobra" ) -var nonNamespacedKind bool -var controller bool -var generate bool +var ( + nonNamespacedKind bool + controller bool + generate bool + skipRBACValidation bool +) var createResourceCmd = &cobra.Command{ Use: "resource", @@ -63,6 +66,7 @@ func AddCreateResource(cmd *cobra.Command) { createResourceCmd.Flags().BoolVar(&controller, "controller", true, "if true, generate the controller code for the resource") createResourceCmd.Flags().BoolVar(&generate, "generate", true, "generate source code") createResourceCmd.Flags().BoolVar(&createutil.AllowPluralKind, "plural-kind", false, "allow the kind to be plural") + createResourceCmd.Flags().BoolVar(&skipRBACValidation, "skip-rbac-validation", false, "if set to true, skip validation for RBAC annotations") cmd.AddCommand(createResourceCmd) } @@ -83,6 +87,9 @@ func RunCreateResource(cmd *cobra.Command, args []string) { if generate { fmt.Printf("Generating code for new resource... " + "Regenerate after editing resources files by running `kubebuilder build generated`.\n") + if skipRBACValidation { + args = append(args, "--skip-rbac-validation") + } generatecmd.RunGenerate(cmd, args) } fmt.Printf("Next: Install the API, run the controller and create an instance with:\n" + @@ -115,7 +122,10 @@ func createResource(boilerplate string) { if controller { fmt.Printf("Creating controller ...\n") - c := controllerct.ControllerArguments{CoreType: false} + c := controllerct.ControllerArguments{ + CoreType: false, + SkipRBACValidation: skipRBACValidation, + } c.CreateController(boilerplate) } diff --git a/cmd/kubebuilder/generate/generate.go b/cmd/kubebuilder/generate/generate.go index d66fe0219de..b2f71988fac 100644 --- a/cmd/kubebuilder/generate/generate.go +++ b/cmd/kubebuilder/generate/generate.go @@ -31,14 +31,17 @@ import ( "k8s.io/apimachinery/pkg/util/sets" ) -var versionedAPIs []string -var unversionedAPIs []string -var Codegenerators []string -var copyright string -var generators = sets.String{} -var vendorDir string -var Docscopyright string -var Docstitle string +var ( + versionedAPIs []string + unversionedAPIs []string + Codegenerators []string + copyright string + generators = sets.String{} + vendorDir string + Docscopyright string + Docstitle string + skipRBACValidation bool +) var generateCmd = &cobra.Command{ Use: "generate", @@ -59,6 +62,7 @@ func AddGenerate(cmd *cobra.Command) { cmd.AddCommand(generateCmd) generateCmd.Flags().StringVar(©right, "copyright", filepath.Join("hack", "boilerplate.go.txt"), "Location of copyright boilerplate file.") generateCmd.Flags().StringVar(&vendorDir, "vendor-dir", "", "Location of directory containing vendor files.") + generateCmd.Flags().BoolVar(&skipRBACValidation, "skip-rbac-validation", false, "if set to true, skip validation for RBAC annotations for the controller.") generateCmd.Flags().StringArrayVar(&versionedAPIs, "api-versions", []string{}, "API version to generate code for. Can be specified multiple times. e.g. --api-versions foo/v1beta1 --api-versions bar/v1 defaults to all versions found under directories pkg/apis//") generateCmd.Flags().StringArrayVar(&Codegenerators, "generator", []string{}, "list of generators to run. e.g. --generator kubebuilder --generator conversion Valid values: [kubebuilder,client,openapi]") generateCmd.Flags().StringVar(&Docscopyright, "docs-copyright", "Copyright 2018 The Kubernetes Authors.", "html for the copyright text on the docs") @@ -126,12 +130,16 @@ func RunGenerate(cmd *cobra.Command, args []string) { } if doGen("kubebuilder-gen") { - c := exec.Command(filepath.Join(root, "kubebuilder-gen"), + genArgs := []string{ "--go-header-file", copyright, "--input-dirs", filepath.Join(util.Repo, "pkg", "apis", "..."), "--input-dirs", filepath.Join(util.Repo, "pkg", "controller", "..."), "--input-dirs", filepath.Join(util.Repo, "pkg", "inject", "..."), - ) + } + if skipRBACValidation { + genArgs = append(genArgs, "--skip-rbac-validation") + } + c := exec.Command(filepath.Join(root, "kubebuilder-gen"), genArgs...) glog.V(4).Infof("%s\n", strings.Join(c.Args, " ")) out, err := c.CombinedOutput() if err != nil {