diff --git a/cmd/apiserver-boot/boot/create/resource.go b/cmd/apiserver-boot/boot/create/resource.go index cb51b90ada..1a8583c0c6 100644 --- a/cmd/apiserver-boot/boot/create/resource.go +++ b/cmd/apiserver-boot/boot/create/resource.go @@ -17,6 +17,7 @@ limitations under the License. package create import ( + "bufio" "fmt" "log" "os" @@ -37,7 +38,9 @@ import ( var kindName string var resourceName string var nonNamespacedKind bool -var generateAdmissionController bool +var skipGenerateAdmissionController bool +var skipGenerateResource bool +var skipGenerateController bool var createResourceCmd = &cobra.Command{ Use: "resource", @@ -53,7 +56,10 @@ func AddCreateResource(cmd *cobra.Command) { RegisterResourceFlags(createResourceCmd) createResourceCmd.Flags().BoolVar(&nonNamespacedKind, "non-namespaced", false, "if set, the API kind will be non namespaced") - createResourceCmd.Flags().BoolVar(&generateAdmissionController, "admission-controller", false, "if set, an admission controller for the resources will be generated") + + createResourceCmd.Flags().BoolVar(&skipGenerateResource, "skip-resource", false, "if set, the resources will not be generated") + createResourceCmd.Flags().BoolVar(&skipGenerateController, "skip-controller", false, "if set, the controller will not be generated") + createResourceCmd.Flags().BoolVar(&skipGenerateAdmissionController, "skip-admission-controller", false, "if set, the admission controller will not be generated") cmd.AddCommand(createResourceCmd) } @@ -66,6 +72,23 @@ func RunCreateResource(cmd *cobra.Command, args []string) { util.GetDomain() ValidateResourceFlags() + reader := bufio.NewReader(os.Stdin) + + if !cmd.Flag("skip-resource").Changed { + fmt.Println("Create Resource [y/n]") + skipGenerateResource = !Yesno(reader) + } + + if !cmd.Flag("skip-controller").Changed { + fmt.Println("Create Controller [y/n]") + skipGenerateController = !Yesno(reader) + } + + if !cmd.Flag("skip-admission-controller").Changed { + fmt.Println("Create Admission Controller [y/n]") + skipGenerateAdmissionController = !Yesno(reader) + } + cr := util.GetCopyright(copyright) ignoreGroupExists = true @@ -97,74 +120,76 @@ func createResource(boilerplate string) { found := false - strategyFileName := fmt.Sprintf("%s_strategy.go", strings.ToLower(kindName)) - unversionedPath := filepath.Join(dir, "pkg", "apis", groupName, strategyFileName) - created := util.WriteIfNotFound(unversionedPath, "unversioned-strategy-template", unversionedStrategyTemplate, a) - if !created { - if !found { - log.Printf("API group version kind %s/%s/%s already exists.", - groupName, versionName, kindName) - found = true + if !skipGenerateResource { + strategyFileName := fmt.Sprintf("%s_strategy.go", strings.ToLower(kindName)) + unversionedPath := filepath.Join(dir, "pkg", "apis", groupName, strategyFileName) + created := util.WriteIfNotFound(unversionedPath, "unversioned-strategy-template", unversionedStrategyTemplate, a) + if !created { + if !found { + log.Printf("API group version kind %s/%s/%s already exists.", + groupName, versionName, kindName) + found = true + } } - } - typesFileName := fmt.Sprintf("%s_types.go", strings.ToLower(kindName)) - path := filepath.Join(dir, "pkg", "apis", groupName, versionName, typesFileName) - created = util.WriteIfNotFound(path, "versioned-resource-template", versionedResourceTemplate, a) - if !created { - if !found { - log.Printf("API group version kind %s/%s/%s already exists.", - groupName, versionName, kindName) - found = true + typesFileName := fmt.Sprintf("%s_types.go", strings.ToLower(kindName)) + path := filepath.Join(dir, "pkg", "apis", groupName, versionName, typesFileName) + created = util.WriteIfNotFound(path, "versioned-resource-template", versionedResourceTemplate, a) + if !created { + if !found { + log.Printf("API group version kind %s/%s/%s already exists.", + groupName, versionName, kindName) + found = true + } } - } - os.MkdirAll(filepath.Join("docs", "examples"), 0700) - docpath := filepath.Join("docs", "examples", strings.ToLower(kindName), fmt.Sprintf("%s.yaml", strings.ToLower(kindName))) - created = util.WriteIfNotFound(docpath, "example-template", exampleTemplate, a) - if !created { - if !found { - log.Printf("Example %s already exists.", docpath) - found = true + os.MkdirAll(filepath.Join("docs", "examples"), 0700) + docpath := filepath.Join("docs", "examples", strings.ToLower(kindName), fmt.Sprintf("%s.yaml", strings.ToLower(kindName))) + created = util.WriteIfNotFound(docpath, "example-template", exampleTemplate, a) + if !created { + if !found { + log.Printf("Example %s already exists.", docpath) + found = true + } } - } - os.MkdirAll("sample", 0700) - samplepath := filepath.Join("sample", fmt.Sprintf("%s.yaml", strings.ToLower(kindName))) - created = util.WriteIfNotFound(samplepath, "sample-template", sampleTemplate, a) - if !created { - if !found { - log.Printf("Sample %s already exists.", docpath) - found = true + os.MkdirAll("sample", 0700) + samplepath := filepath.Join("sample", fmt.Sprintf("%s.yaml", strings.ToLower(kindName))) + created = util.WriteIfNotFound(samplepath, "sample-template", sampleTemplate, a) + if !created { + if !found { + log.Printf("Sample %s already exists.", docpath) + found = true + } } - } - // write the suite if it is missing - typesFileName = fmt.Sprintf("%s_suite_test.go", strings.ToLower(versionName)) - path = filepath.Join(dir, "pkg", "apis", groupName, versionName, typesFileName) - util.WriteIfNotFound(path, "version-suite-test-template", resourceSuiteTestTemplate, a) - - typesFileName = fmt.Sprintf("%s_types_test.go", strings.ToLower(kindName)) - path = filepath.Join(dir, "pkg", "apis", groupName, versionName, typesFileName) - created = util.WriteIfNotFound(path, "resource-test-template", resourceTestTemplate, a) - if !created { - if !found { - log.Printf("API group version kind %s/%s/%s test already exists.", - groupName, versionName, kindName) - found = true + // write the suite if it is missing + typesFileName = fmt.Sprintf("%s_suite_test.go", strings.ToLower(versionName)) + path = filepath.Join(dir, "pkg", "apis", groupName, versionName, typesFileName) + util.WriteIfNotFound(path, "version-suite-test-template", resourceSuiteTestTemplate, a) + + typesFileName = fmt.Sprintf("%s_types_test.go", strings.ToLower(kindName)) + path = filepath.Join(dir, "pkg", "apis", groupName, versionName, typesFileName) + created = util.WriteIfNotFound(path, "resource-test-template", resourceTestTemplate, a) + if !created { + if !found { + log.Printf("API group version kind %s/%s/%s test already exists.", + groupName, versionName, kindName) + found = true + } } } - if generateAdmissionController { + if !skipGenerateAdmissionController { // write the admission-controller initializer if it is missing os.MkdirAll(filepath.Join("plugin", "admission"), 0700) admissionInitializerFileName := "initializer.go" - path = filepath.Join(dir, "plugin", "admission", admissionInitializerFileName) - created = util.WriteIfNotFound(path, "admission-initializer-template", admissionControllerInitializerTemplate, a) + path := filepath.Join(dir, "plugin", "admission", admissionInitializerFileName) + created := util.WriteIfNotFound(path, "admission-initializer-template", admissionControllerInitializerTemplate, a) if !created { if !found { log.Printf("admission initializer already exists.") - found = true + // found = true } } @@ -181,56 +206,58 @@ func createResource(boilerplate string) { } } - // write controller-runtime scaffolding templates - r := &resource.Resource{ - Namespaced: !nonNamespacedKind, - Group: groupName, - Version: versionName, - Kind: kindName, - Resource: resourceName, - } - - err = (&scaffold.Scaffold{}).Execute(input.Options{ - BoilerplatePath: "boilerplate.go.txt", - }, &Controller{ - Resource: r, - Input: input.Input{ - IfExistsAction: input.Skip, - }, - }) - if err != nil { - klog.Warningf("failed generating %v controller: %v", kindName, err) - } + if !skipGenerateController { + // write controller-runtime scaffolding templates + r := &resource.Resource{ + Namespaced: !nonNamespacedKind, + Group: groupName, + Version: versionName, + Kind: kindName, + Resource: resourceName, + } - err = (&scaffold.Scaffold{}).Execute(input.Options{ - BoilerplatePath: "boilerplate.go.txt", - }, - &manager.Controller{ - Input: input.Input{ - IfExistsAction: input.Skip, - }, - }, - &controller.AddController{ + err = (&scaffold.Scaffold{}).Execute(input.Options{ + BoilerplatePath: "boilerplate.go.txt", + }, &Controller{ Resource: r, Input: input.Input{ IfExistsAction: input.Skip, }, + }) + if err != nil { + klog.Warningf("failed generating %v controller: %v", kindName, err) + } + + err = (&scaffold.Scaffold{}).Execute(input.Options{ + BoilerplatePath: "boilerplate.go.txt", }, - &SuiteTest{ - Resource: r, - Input: input.Input{ - IfExistsAction: input.Skip, + &manager.Controller{ + Input: input.Input{ + IfExistsAction: input.Skip, + }, }, - }, - &controller.Test{ - Resource: r, - Input: input.Input{ - IfExistsAction: input.Skip, + &controller.AddController{ + Resource: r, + Input: input.Input{ + IfExistsAction: input.Skip, + }, }, - }, - ) - if err != nil { - klog.Warningf("failed generating controller basic packages: %v", err) + &SuiteTest{ + Resource: r, + Input: input.Input{ + IfExistsAction: input.Skip, + }, + }, + &controller.Test{ + Resource: r, + Input: input.Input{ + IfExistsAction: input.Skip, + }, + }, + ) + if err != nil { + klog.Warningf("failed generating controller basic packages: %v", err) + } } if found { diff --git a/cmd/apiserver-boot/boot/create/util.go b/cmd/apiserver-boot/boot/create/util.go index 416ba0af91..818a3e9a3b 100644 --- a/cmd/apiserver-boot/boot/create/util.go +++ b/cmd/apiserver-boot/boot/create/util.go @@ -17,6 +17,8 @@ limitations under the License. package create import ( + "bufio" + "fmt" "log" "regexp" "strings" @@ -66,3 +68,29 @@ func RegisterResourceFlags(cmd *cobra.Command) { cmd.Flags().StringVar(&kindName, "kind", "", "name of the API kind. **Must be CamelCased (match ^[A-Z]+[A-Za-z0-9]*$)**") cmd.Flags().StringVar(&resourceName, "resource", "", "optional name of the API resource, defaults to the plural name of the lowercase kind") } + +// Yesno reads from stdin looking for one of "y", "yes", "n", "no" and returns +// true for "y" and false for "n" +func Yesno(reader *bufio.Reader) bool { + for { + text := readstdin(reader) + switch text { + case "y", "yes": + return true + case "n", "no": + return false + default: + fmt.Printf("invalid input %q, should be [y/n]", text) + } + } +} + +// Readstdin reads a line from stdin trimming spaces, and returns the value. +// log.Fatal's if there is an error. +func readstdin(reader *bufio.Reader) string { + text, err := reader.ReadString('\n') + if err != nil { + log.Fatalf("Error when reading input: %v", err) + } + return strings.TrimSpace(text) +} \ No newline at end of file diff --git a/test/Makefile b/test/Makefile index dc3a4d1591..9d237ed790 100644 --- a/test/Makefile +++ b/test/Makefile @@ -16,6 +16,8 @@ all: test +NON_INTERACTIVE_FLAG=--skip-resource=false --skip-controller=false --skip-admission-controller=false + test: build go test ./pkg/apis/... go test ./pkg/controller/volumeclaim @@ -26,10 +28,10 @@ test: build skeleton: cmds apiserver-boot init repo --domain sample.kubernetes.io - apiserver-boot create group version resource --group storage --version v1 --kind VolumeClaim - apiserver-boot create group version resource --group storage --version v1 --kind SnapshotClaim - apiserver-boot create group version resource --group storage --version v1 --kind Volume --non-namespaced - apiserver-boot create group version resource --group storage --version v1 --kind Snapshot --non-namespaced + apiserver-boot create group version resource --group storage --version v1 --kind VolumeClaim $(NON_INTERACTIVE_FLAG) + apiserver-boot create group version resource --group storage --version v1 --kind SnapshotClaim $(NON_INTERACTIVE_FLAG) + apiserver-boot create group version resource --group storage --version v1 --kind Volume --non-namespaced $(NON_INTERACTIVE_FLAG) + apiserver-boot create group version resource --group storage --version v1 --kind Snapshot --non-namespaced $(NON_INTERACTIVE_FLAG) build: cmds skeleton apiserver-boot build executables