Skip to content

Commit f0a5475

Browse files
New deploy-image/v1alpha1 plugin
1 parent cf93a27 commit f0a5475

File tree

64 files changed

+3332
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+3332
-0
lines changed

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
kustomizecommonv2alpha "sigs.k8s.io/kubebuilder/v3/pkg/plugins/common/kustomize/v2-alpha"
3131
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang"
3232
declarativev1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1"
33+
deployimagev1alpha1 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/deploy-image/v1alpha1"
3334
golangv2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2"
3435
golangv3 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v3"
3536
)
@@ -60,6 +61,7 @@ func main() {
6061
&kustomizecommonv1.Plugin{},
6162
&kustomizecommonv2alpha.Plugin{},
6263
&declarativev1.Plugin{},
64+
&deployimagev1alpha1.Plugin{},
6365
),
6466
cli.WithPlugins(externalPlugins...),
6567
cli.WithDefaultPlugins(cfgv2.Version, golangv2.Plugin{}),
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
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 v1alpha1
18+
19+
import (
20+
"errors"
21+
"fmt"
22+
"os"
23+
24+
goPlugin "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang"
25+
26+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
27+
28+
"github.com/spf13/pflag"
29+
"sigs.k8s.io/kubebuilder/v3/pkg/config"
30+
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
31+
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
32+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
33+
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/deploy-image/v1alpha1/scaffolds"
34+
)
35+
36+
const (
37+
// defaultCRDVersion is the default CRD API version to scaffold.
38+
defaultCRDVersion = "v1"
39+
)
40+
41+
const deprecateMsg = "The v1beta1 API version for CRDs and Webhooks are deprecated and are no longer supported since " +
42+
"the Kubernetes release 1.22. This flag no longer required to exist in future releases. Also, we would like to " +
43+
"recommend you no longer use these API versions." +
44+
"More info: https://kubernetes.io/docs/reference/using-api/deprecation-guide/#v1-22"
45+
46+
// DefaultMainPath is default file path of main.go
47+
const DefaultMainPath = "main.go"
48+
49+
var _ plugin.CreateAPISubcommand = &createAPISubcommand{}
50+
51+
type createAPISubcommand struct {
52+
config config.Config
53+
54+
options *goPlugin.Options
55+
56+
resource *resource.Resource
57+
58+
// image indicates the image that will be used to scaffold the deployment
59+
image string
60+
61+
// runMake indicates whether to run make or not after scaffolding APIs
62+
runMake bool
63+
64+
// runManifests indicates whether to run manifests or not after scaffolding APIs
65+
runManifests bool
66+
67+
// imageCommand indicates the command that we should use to init the deployment
68+
imageContainerCommand string
69+
70+
// imageContainerPort indicates the port that we should use in the scaffold
71+
imageContainerPort string
72+
}
73+
74+
func (p *createAPISubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) {
75+
//nolint: lll
76+
subcmdMeta.Description = `Scaffold the code implementation to deploy and manage your Operand which is represented by the API informed and will be reconciled by its controller. This plugin will generate the code implementation to help you out.
77+
78+
Note: In general, it’s recommended to have one controller responsible for managing each API created for the project to properly follow the design goals set by Controller Runtime(https://github.com/kubernetes-sigs/controller-runtime).
79+
80+
This plugin will work as the common behaviour of the flag --force and will scaffold the API and controller always. Use core types or external APIs is not officially support by default with.
81+
`
82+
//nolint: lll
83+
subcmdMeta.Examples = fmt.Sprintf(` # Create a frigates API with Group: ship, Version: v1beta1, Kind: Frigate to represent the
84+
Image: example.com/frigate:v0.0.1 and its controller with a code to deploy and manage this Operand.
85+
86+
Note that in the following example we are also adding the optional options to let you inform the command which should be used to create the container and initialize itvia the flag --image-container-command as the Port that should be used
87+
88+
- By informing the command (--image-container-command="memcached,-m=64,-o,modern,-v") your deployment will be scaffold with, i.e.:
89+
90+
Command: []string{"memcached","-m=64","-o","modern","-v"},
91+
92+
- By informing the Port (--image-container-port) will deployment will be scaffold with, i.e:
93+
94+
Ports: []corev1.ContainerPort{
95+
ContainerPort: Memcached.Spec.ContainerPort,
96+
Name: "Memcached",
97+
},
98+
99+
Therefore, the default values informed will be used to scaffold specs for the API.
100+
101+
%[1]s create api --group example.com --version v1alpha1 --kind Memcached --image=memcached:1.6.15-alpine --image-container-command="memcached -m=64 modern -v" --image-container-port="11211" --plugins="deploy-image/v1-alpha" --make=false --namespaced=false
102+
103+
# Generate the manifests
104+
make manifests
105+
106+
# Install CRDs into the Kubernetes cluster using kubectl apply
107+
make install
108+
109+
# Regenerate code and run against the Kubernetes cluster configured by ~/.kube/config
110+
make run
111+
`, cliMeta.CommandName)
112+
}
113+
114+
func (p *createAPISubcommand) BindFlags(fs *pflag.FlagSet) {
115+
fs.StringVar(&p.image, "image", "", "inform the Operand image. "+
116+
"The controller will be scaffolded with an example code to deploy and manage this image.")
117+
118+
fs.StringVar(&p.imageContainerCommand, "image-container-command", "", "[Optional] if informed, "+
119+
"will be used to scaffold the container command that should be used to init a container to run the image in "+
120+
"the controller and its spec in the API (CRD/CR). (i.e. --image-container-command=\"memcached,-m=64,modern,-o,-v\")")
121+
fs.StringVar(&p.imageContainerPort, "image-container-port", "", "[Optional] if informed, "+
122+
"will be used to scaffold the container port that should be used by container image in "+
123+
"the controller and its spec in the API (CRD/CR). (i.e --image-container-port=\"11211\") ")
124+
125+
fs.BoolVar(&p.runMake, "make", true, "if true, run `make generate` after generating files")
126+
fs.BoolVar(&p.runManifests, "manifests", true, "if true, run `make manifests` after generating files")
127+
128+
p.options = &goPlugin.Options{}
129+
130+
fs.StringVar(&p.options.CRDVersion, "crd-version", defaultCRDVersion,
131+
"version of CustomResourceDefinition to scaffold. Options: [v1, v1beta1]")
132+
133+
fs.StringVar(&p.options.Plural, "plural", "", "resource irregular plural form")
134+
fs.BoolVar(&p.options.Namespaced, "namespaced", true, "resource is namespaced")
135+
136+
// (not required raise an error in this case)
137+
// nolint:errcheck,gosec
138+
fs.MarkDeprecated("crd-version", deprecateMsg)
139+
}
140+
141+
func (p *createAPISubcommand) InjectConfig(c config.Config) error {
142+
p.config = c
143+
144+
return nil
145+
}
146+
147+
func (p *createAPISubcommand) InjectResource(res *resource.Resource) error {
148+
p.resource = res
149+
p.options.DoAPI = true
150+
p.options.DoController = true
151+
p.options.UpdateResource(p.resource, p.config)
152+
153+
if err := p.resource.Validate(); err != nil {
154+
return err
155+
}
156+
157+
// Check that the provided group can be added to the project
158+
if !p.config.IsMultiGroup() && p.config.ResourcesLength() != 0 && !p.config.HasGroup(p.resource.Group) {
159+
return fmt.Errorf("multiple groups are not allowed by default, " +
160+
"to enable multi-group visit https://kubebuilder.io/migration/multi-group.html")
161+
}
162+
163+
// Check CRDVersion against all other CRDVersions in p.config for compatibility.
164+
if util.HasDifferentCRDVersion(p.config, p.resource.API.CRDVersion) {
165+
return fmt.Errorf("only one CRD version can be used for all resources, cannot add %q",
166+
p.resource.API.CRDVersion)
167+
}
168+
169+
// Check CRDVersion against all other CRDVersions in p.config for compatibility.
170+
if util.HasDifferentCRDVersion(p.config, p.resource.API.CRDVersion) {
171+
return fmt.Errorf("only one CRD version can be used for all resources, cannot add %q",
172+
p.resource.API.CRDVersion)
173+
}
174+
175+
return nil
176+
}
177+
178+
func (p *createAPISubcommand) PreScaffold(machinery.Filesystem) error {
179+
if len(p.image) == 0 {
180+
return fmt.Errorf("you MUST inform the image that will be used in the reconciliation")
181+
}
182+
183+
// check if main.go is present in the root directory
184+
if _, err := os.Stat(DefaultMainPath); os.IsNotExist(err) {
185+
return fmt.Errorf("%s file should present in the root directory", DefaultMainPath)
186+
}
187+
188+
return nil
189+
}
190+
191+
func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error {
192+
fmt.Println("updating scaffold with deploy-image/v1alpha1 plugin...")
193+
194+
scaffolder := scaffolds.NewDeployImageScaffolder(p.config,
195+
*p.resource,
196+
p.image,
197+
p.imageContainerCommand,
198+
p.imageContainerPort)
199+
scaffolder.InjectFS(fs)
200+
err := scaffolder.Scaffold()
201+
if err != nil {
202+
return err
203+
}
204+
205+
// Track the resources following a declarative approach
206+
cfg := pluginConfig{}
207+
if err := p.config.DecodePluginConfig(pluginKey, &cfg); errors.As(err, &config.UnsupportedFieldError{}) {
208+
// Config doesn't support per-plugin configuration, so we can't track them
209+
} else {
210+
// Fail unless they key wasn't found, which just means it is the first resource tracked
211+
if err != nil && !errors.As(err, &config.PluginKeyNotFoundError{}) {
212+
return err
213+
}
214+
cfg.Resources = append(cfg.Resources, p.resource.GVK)
215+
// Track the options informed
216+
cfg.Image = p.image
217+
cfg.ContainerCommand = p.imageContainerCommand
218+
cfg.ContainerPort = p.imageContainerPort
219+
if err := p.config.EncodePluginConfig(pluginKey, cfg); err != nil {
220+
return err
221+
}
222+
}
223+
224+
return nil
225+
}
226+
227+
func (p *createAPISubcommand) PostScaffold() error {
228+
err := util.RunCmd("Update dependencies", "go", "mod", "tidy")
229+
if err != nil {
230+
return err
231+
}
232+
if p.runMake && p.resource.HasAPI() {
233+
err = util.RunCmd("Running make", "make", "generate")
234+
if err != nil {
235+
return err
236+
}
237+
}
238+
239+
if p.runManifests && p.resource.HasAPI() {
240+
err = util.RunCmd("Running make", "make", "manifests")
241+
if err != nil {
242+
return err
243+
}
244+
}
245+
246+
fmt.Print("Next: check the implementation of your new API and controller. " +
247+
"If you do changes in the API run the manifests with:\n$ make manifests\n")
248+
249+
return nil
250+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 v1alpha1
18+
19+
import (
20+
"sigs.k8s.io/kubebuilder/v3/pkg/config"
21+
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
22+
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
23+
"sigs.k8s.io/kubebuilder/v3/pkg/model/stage"
24+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
25+
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang"
26+
)
27+
28+
const pluginName = "deploy-image." + golang.DefaultNameQualifier
29+
30+
var (
31+
pluginVersion = plugin.Version{Number: 1, Stage: stage.Alpha}
32+
supportedProjectVersions = []config.Version{cfgv3.Version}
33+
pluginKey = plugin.KeyFor(Plugin{})
34+
)
35+
36+
var _ plugin.CreateAPI = Plugin{}
37+
38+
// Plugin implements the plugin.Full interface
39+
type Plugin struct {
40+
createAPISubcommand
41+
}
42+
43+
// Name returns the name of the plugin
44+
func (Plugin) Name() string { return pluginName }
45+
46+
// Version returns the version of the plugin
47+
func (Plugin) Version() plugin.Version { return pluginVersion }
48+
49+
// SupportedProjectVersions returns an array with all project versions supported by the plugin
50+
func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions }
51+
52+
// GetCreateAPISubcommand will return the subcommand which is responsible for scaffolding apis
53+
func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { return &p.createAPISubcommand }
54+
55+
type pluginConfig struct {
56+
Resources []resource.GVK `json:"resources,omitempty"`
57+
// image indicates the image that will be used to scaffold the deployment
58+
Image string `json:"image,omitempty"`
59+
ContainerCommand string `json:"containerCommand,omitempty"`
60+
ContainerPort string `json:"containerPort,omitempty"`
61+
}

0 commit comments

Comments
 (0)