sigs.k8s.io/kubebuilder/v3@v3.14.0/pkg/plugins/golang/declarative/v1/api.go (about) 1 /* 2 Copyright 2022 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 package v1 18 19 import ( 20 "errors" 21 "fmt" 22 23 log "github.com/sirupsen/logrus" 24 25 "sigs.k8s.io/kubebuilder/v3/pkg/config" 26 "sigs.k8s.io/kubebuilder/v3/pkg/machinery" 27 "sigs.k8s.io/kubebuilder/v3/pkg/model/resource" 28 "sigs.k8s.io/kubebuilder/v3/pkg/plugin" 29 "sigs.k8s.io/kubebuilder/v3/pkg/plugin/util" 30 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1/scaffolds" 31 goPluginV2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2" 32 goPluginV3 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3" 33 ) 34 35 const ( 36 // kbDeclarativePattern is the sigs.k8s.io/kubebuilder-declarative-pattern version 37 kbDeclarativePatternForV2 = "v0.0.0-20200522144838-848d48e5b073" 38 kbDeclarativePatternForV3 = "18dbaf5fcd851e6adc3f2f8a8facb669a1420797" 39 kbDeclarativePatternForV4 = "9a410556b95de526e12acfe0d6f56fd35c0b0135" 40 ) 41 42 var _ plugin.CreateAPISubcommand = &createAPISubcommand{} 43 44 type createAPISubcommand struct { 45 config config.Config 46 47 resource *resource.Resource 48 } 49 50 func (p *createAPISubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) { 51 subcmdMeta.Description = ` 52 Scaffold a Kubernetes API by writing a Resource definition and a Controller. 53 54 After the scaffold is written, the dependencies will be updated and 55 make generate will be run. 56 ` 57 subcmdMeta.Examples = fmt.Sprintf(` # Create a frigates API with Group: ship, Version: v1beta1 and Kind: Frigate 58 %[1]s create api --group ship --version v1beta1 --kind Frigate --resource --controller 59 60 # Edit the API Scheme 61 nano api/v1beta1/frigate_types.go 62 63 # Edit the Controller Test 64 nano controllers/frigate/frigate_controller_test.go 65 66 # Generate the manifests 67 make manifests 68 69 # Install CRDs into the Kubernetes cluster using kubectl apply 70 make install 71 72 # Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config 73 make run 74 `, cliMeta.CommandName) 75 } 76 77 func (p *createAPISubcommand) InjectConfig(c config.Config) error { 78 p.config = c 79 80 return nil 81 } 82 83 func (p *createAPISubcommand) InjectResource(res *resource.Resource) error { 84 p.resource = res 85 86 if !p.resource.HasAPI() || !p.resource.HasController() { 87 return plugin.ExitError{ 88 Plugin: pluginName, 89 Reason: "declarative pattern is only supported when API and controller are scaffolded", 90 } 91 } 92 93 return nil 94 } 95 96 func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error { 97 log.Println("updating scaffold with declarative pattern...") 98 99 scaffolder := scaffolds.NewAPIScaffolder(p.config, *p.resource) 100 scaffolder.InjectFS(fs) 101 err := scaffolder.Scaffold() 102 if err != nil { 103 return err 104 } 105 106 // Update Dockerfile 107 // nolint:staticcheck 108 err = updateDockerfile(plugin.IsLegacyLayout(p.config)) 109 if err != nil { 110 return err 111 } 112 113 // Track the resources following a declarative approach 114 cfg := pluginConfig{} 115 if err := p.config.DecodePluginConfig(pluginKey, &cfg); errors.As(err, &config.UnsupportedFieldError{}) { 116 // Config doesn't support per-plugin configuration, so we can't track them 117 } else { 118 // Fail unless they key wasn't found, which just means it is the first resource tracked 119 if err != nil && !errors.As(err, &config.PluginKeyNotFoundError{}) { 120 return err 121 } 122 123 cfg.Resources = append(cfg.Resources, p.resource.GVK) 124 if err := p.config.EncodePluginConfig(pluginKey, cfg); err != nil { 125 return err 126 } 127 } 128 129 // Ensure that we are pinning sigs.k8s.io/kubebuilder-declarative-pattern version 130 // Just pin an old value for go/v2. It shows fine for now. However, we should improve/change it 131 // if we see that more rules based on the plugins version are required. 132 kbDeclarativePattern := kbDeclarativePatternForV4 133 for _, pluginKey := range p.config.GetPluginChain() { 134 if pluginKey == plugin.KeyFor(goPluginV2.Plugin{}) { 135 kbDeclarativePattern = kbDeclarativePatternForV2 136 break 137 } 138 if pluginKey == plugin.KeyFor(goPluginV3.Plugin{}) { 139 kbDeclarativePattern = kbDeclarativePatternForV3 140 break 141 } 142 } 143 err = util.RunCmd("Get declarative pattern", "go", "get", 144 "sigs.k8s.io/kubebuilder-declarative-pattern@"+kbDeclarativePattern) 145 if err != nil { 146 return err 147 } 148 149 return nil 150 }