sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/plugins/golang/v2/api.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 //go:deprecated This package has been deprecated 18 package v2 19 20 import ( 21 "bufio" 22 "errors" 23 "fmt" 24 "os" 25 26 "github.com/spf13/pflag" 27 28 "sigs.k8s.io/kubebuilder/v3/pkg/config" 29 "sigs.k8s.io/kubebuilder/v3/pkg/machinery" 30 "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" 31 "sigs.k8s.io/kubebuilder/v3/pkg/plugin" 32 "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util" 33 goPlugin "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang" 34 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds" 35 ) 36 37 var _ plugin.CreateAPISubcommand = &createAPISubcommand{} 38 39 type createAPISubcommand struct { 40 config config.Config 41 42 options *goPlugin.Options 43 44 resource *resource.Resource 45 46 // Check if we have to scaffold resource and/or controller 47 resourceFlag *pflag.Flag 48 controllerFlag *pflag.Flag 49 50 // force indicates that the resource should be created even if it already exists 51 force bool 52 53 // runMake indicates whether to run make or not after scaffolding APIs 54 runMake bool 55 } 56 57 func (p *createAPISubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { 58 subcmdMeta.Description = `Scaffold a Kubernetes API by writing a Resource definition and/or a Controller. 59 60 If information about whether the resource and controller should be scaffolded 61 was not explicitly provided, it will prompt the user if they should be. 62 63 After the scaffold is written, the dependencies will be updated and 64 make generate will be run. 65 ` 66 subcmdMeta.Examples = fmt.Sprintf(` # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate 67 %[1]s create api --group ship --version v1beta1 --kind Frigate 68 69 # Edit the API Scheme 70 nano api/v1beta1/frigate_types.go 71 72 # Edit the Controller 73 nano controllers/frigate/frigate_controller.go 74 75 # Edit the Controller Test 76 nano controllers/frigate/frigate_controller_test.go 77 78 # Generate the manifests 79 make manifests 80 81 # Install CRDs into the Kubernetes cluster using kubectl apply 82 make install 83 84 # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config 85 make run 86 `, cliMeta.CommandName) 87 } 88 89 func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) { 90 fs.BoolVar(&p.runMake, "make", true, "if true, run `make generate` after generating files") 91 92 fs.BoolVar(&p.force, "force", false, 93 "attempt to create resource even if it already exists") 94 95 p.options = &goPlugin.Options{CRDVersion: "v1beta1"} 96 // p.options.Plural can be set to specify an irregular plural form 97 98 fs.BoolVar(&p.options.DoAPI, "resource", true, 99 "if set, generate the resource without prompting the user") 100 p.resourceFlag = fs.Lookup("resource") 101 fs.BoolVar(&p.options.Namespaced, "namespaced", true, "resource is namespaced") 102 103 fs.BoolVar(&p.options.DoController, "controller", true, 104 "if set, generate the controller without prompting the user") 105 p.controllerFlag = fs.Lookup("controller") 106 } 107 108 func (p *createAPISubcommand) InjectConfig(c config.Config) error { 109 p.config = c 110 111 return nil 112 } 113 114 func (p *createAPISubcommand) InjectResource(res *resource.Resource) error { 115 p.resource = res 116 117 if p.resource.Group == "" { 118 return fmt.Errorf("group cannot be empty") 119 } 120 121 // Ask for API and Controller if not specified 122 reader := bufio.NewReader(os.Stdin) 123 if !p.resourceFlag.Changed { 124 fmt.Println("Create Resource [y/n]") 125 p.options.DoAPI = util.YesNo(reader) 126 } 127 if !p.controllerFlag.Changed { 128 fmt.Println("Create Controller [y/n]") 129 p.options.DoController = util.YesNo(reader) 130 } 131 132 p.options.UpdateResource(p.resource, p.config) 133 134 if err := p.resource.Validate(); err != nil { 135 return err 136 } 137 138 // In case we want to scaffold a resource API we need to do some checks 139 if p.options.DoAPI { 140 // Check that resource doesn't have the API scaffolded or flag force was set 141 if res, err := p.config.GetResource(p.resource.GVK); err == nil && res.HasAPI() && !p.force { 142 return errors.New("API resource already exists") 143 } 144 145 // Check that the provided group can be added to the project 146 if !p.config.IsMultiGroup() && p.config.ResourcesLength() != 0 && !p.config.HasGroup(p.resource.Group) { 147 return fmt.Errorf("multiple groups are not allowed by default, to enable multi-group visit %s", 148 "https://kubebuilder.io/migration/multi-group.html") 149 } 150 } 151 152 return nil 153 } 154 155 func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error { 156 scaffolder := scaffolds.NewAPIScaffolder(p.config, *p.resource, p.force) 157 scaffolder.InjectFS(fs) 158 return scaffolder.Scaffold() 159 } 160 161 func (p *createAPISubcommand) PostScaffold() error { 162 err := util.RunCmd("Update dependencies", "go", "mod", "tidy") 163 if err != nil { 164 return err 165 } 166 167 if p.runMake && p.resource.HasAPI() { 168 err = util.RunCmd("Running make", "make", "generate") 169 if err != nil { 170 return err 171 } 172 fmt.Print("Next: implement your new API and generate the manifests (e.g. CRDs,CRs) with:\n$ make manifests \n") 173 } 174 175 return nil 176 }