Skip to content
Closed
Changes from 2 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
0a5c604
:sparkles: Use ErrorIfCRDPathMissing in EnvTest
jamielennox Nov 2, 2020
887d714
:fix: remove unecessary checks adds to the main.go (go/v3-alpha)
camilamacedo86 Dec 16, 2020
b1670d8
Remove misleading help that mentioned dep
justinsb Jan 13, 2021
3ad354c
Merge pull request #1945 from justinsb/no_more_dep
k8s-ci-robot Jan 13, 2021
84b6f53
Build the command and use it to report user errors so that the comman…
Adirio Jan 12, 2021
9fd31f1
pkg/plugins/golang/v3: upgrade kubebuilder-declarative-pattern to k8s…
estroz Jan 13, 2021
1cd45e2
Merge pull request #1946 from estroz/chore/update-dep
k8s-ci-robot Jan 13, 2021
c988208
Add help dialog to makefile template
droctothorpe Jan 14, 2021
a7fc753
Add updated testdata
droctothorpe Jan 14, 2021
20df76b
Make directory-not-empty error more self-explanatory
justinsb Jan 13, 2021
f7a5201
Merge pull request #1947 from droctothorpe/makefile-updates
k8s-ci-robot Jan 14, 2021
1001d36
Merge pull request #1943 from justinsb/directory_not_empty_message
k8s-ci-robot Jan 15, 2021
d1105e2
*: upgrade kube-rbac-proxy to v0.8.0
estroz Jan 16, 2021
c577244
Merge pull request #1937 from Adirio/enhance-root-cmd
k8s-ci-robot Jan 18, 2021
032f0c4
Merge pull request #1910 from camilamacedo86/fix-checks
k8s-ci-robot Jan 18, 2021
0d938e4
upgrade kubebuilder module from v2 to v3
camilamacedo86 Jan 18, 2021
e3e3658
Merge pull request #1958 from camilamacedo86/v3-dep
k8s-ci-robot Jan 19, 2021
8d108aa
test commit
estroz Jan 20, 2021
3af7d23
Merge pull request #1955 from estroz/deps/krp-v0.8.0
k8s-ci-robot Jan 20, 2021
79ecd51
Merge pull request #1765 from jamielennox/error-if-missing
k8s-ci-robot Jan 20, 2021
ea75c59
Update Options and Resource models and implement Config as an interfa…
Adirio Dec 17, 2020
1e78a6f
Merge pull request #1911 from Adirio/update-models
k8s-ci-robot Jan 22, 2021
1a6bb7a
Add --plural flag (go/v3)
Adirio Jan 22, 2021
b290147
Merge pull request #1967 from Adirio/plurals
k8s-ci-robot Jan 22, 2021
45f69ce
Validate the plugin flag
Adirio Jan 23, 2021
7b84f60
Merge pull request #1970 from Adirio/validate-plural
k8s-ci-robot Jan 25, 2021
db966c6
Split resource validation between Options and Resource objects so tha…
Adirio Jan 26, 2021
2aef3ad
Add the rest of the missing fields and stabilize config v3
Adirio Jan 22, 2021
03431ed
(go/v3) change 'runAsUser: 65532', which is redundant, to 'runAsNonRo…
estroz Jan 27, 2021
14b27b4
Merge pull request #1978 from estroz/feature/pod-nonroot
k8s-ci-robot Jan 28, 2021
12de4fb
Remove make calls from post-scaffold hooks
Adirio Jan 29, 2021
4fd2cd7
Tolerate "dot" directories when checking if dir is empty
justinsb Jan 13, 2021
e222f25
Merge pull request #1944 from justinsb/tolerate_git_dir
k8s-ci-robot Jan 29, 2021
71b8578
Merge pull request #1968 from Adirio/config/v3
k8s-ci-robot Jan 29, 2021
386207f
:seedling: sort plugins key for the help
camilamacedo86 Jan 29, 2021
63286ce
Merge pull request #1984 from camilamacedo86/sort-plugins-key
k8s-ci-robot Jan 29, 2021
479367b
Merge pull request #1983 from Adirio/remove-post-scaffold-make
k8s-ci-robot Jan 30, 2021
fa40846
Return a typed error in case DecodePluginConfig was unable to find th…
Adirio Feb 1, 2021
564a6e9
Merge pull request #1985 from Adirio/plugin-config-missing-error
k8s-ci-robot Feb 1, 2021
90344af
Merge pull request #1974 from Adirio/split-resource-validation
k8s-ci-robot Feb 2, 2021
95466c5
Add documentation to v2 controllers
Adirio Feb 3, 2021
fed6174
Go fmt templates
Adirio Feb 3, 2021
63904d2
Merge pull request #1989 from Adirio/v2-controller-doc
k8s-ci-robot Feb 3, 2021
6a676b1
Merge pull request #1987 from Adirio/go-fmt-templates
k8s-ci-robot Feb 3, 2021
6e1be3d
Bump addon *_types.go and controller.go templates with changes that w…
Adirio Feb 3, 2021
4ddc71c
Improve Makefile help
Adirio Jan 29, 2021
3c8e370
Merge pull request #1988 from Adirio/bump-addon
k8s-ci-robot Feb 3, 2021
f1685b8
Fix sorting issue nwith plugin versions and their supported project v…
Adirio Feb 8, 2021
89c42c4
Merge pull request #1995 from Adirio/fix-sort
k8s-ci-robot Feb 8, 2021
fe481ef
Merge pull request #1981 from Adirio/makefile-help
k8s-ci-robot Feb 8, 2021
a9dd9dc
Fix go/v2 with config/v3 resources in config file to store webhook in…
Adirio Feb 9, 2021
72f01e5
Merge pull request #1998 from Adirio/fix-go-v2-config-v3-webhooks
k8s-ci-robot Feb 9, 2021
42091e9
Track resources without an API in the config file (config/v3)
Adirio Feb 10, 2021
05abe25
Merge pull request #2003 from Adirio/track-resources-without-api
k8s-ci-robot Feb 11, 2021
bd00512
:seeding: ignore maligned lint issue for WebhookSuite struct
camilamacedo86 Feb 11, 2021
c82530b
Merge pull request #2009 from camilamacedo86/fix-lint-issue
k8s-ci-robot Feb 11, 2021
3948289
Plugin phase 1.5 EP
Adirio Feb 3, 2021
757cc8a
Merge pull request #1990 from Adirio/plugin-phase-1-5
k8s-ci-robot Feb 12, 2021
8c08161
Tests cleanup
Adirio Jan 8, 2021
ab3bb7f
:book: uprade migration guide for v3
camilamacedo86 Dec 17, 2020
685558d
Merge pull request #1916 from camilamacedo86/migration-doc
k8s-ci-robot Feb 12, 2021
9fafbf9
Accept auto-generated files from GitHub into the allowed set of files
Adirio Feb 13, 2021
46c65ba
Merge pull request #2014 from Adirio/accept-github-fefault-files
k8s-ci-robot Feb 13, 2021
a9c3e50
Add Adirio to aprovers
Adirio Feb 13, 2021
5044d6e
Merge pull request #2013 from Adirio/adirio-aprover
k8s-ci-robot Feb 13, 2021
6224a06
Merge pull request #1933 from Adirio/cleanup-tests
k8s-ci-robot Feb 14, 2021
53b2cf6
:book: proposal for new plugin to generate code
camilamacedo86 Nov 9, 2020
5afa97e
Update book examples to Kubebuilder v3.
HoustonPutman Feb 16, 2021
7adcffd
Merge pull request #1803 from camilamacedo86/code-generate-plugin
k8s-ci-robot Feb 17, 2021
e23cbe4
Fix the bug where an error was being hidden by a potentially valid fl…
Adirio Feb 17, 2021
b46beea
Merge pull request #2023 from Adirio/fix-hidden-error
k8s-ci-robot Feb 17, 2021
2398445
Merge pull request #2021 from HoustonPutman/book-empty-examples-v3
k8s-ci-robot Feb 17, 2021
d71b1a9
Allow cross-package coverage inside the "pkg" directory
Adirio Feb 17, 2021
2d9367e
Merge pull request #2024 from Adirio/increase-coverage
k8s-ci-robot Feb 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
309 changes: 309 additions & 0 deletions designs/code-generate-image-plugin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
---
title: Neat-Enhancement-Idea
authors:
- "@camilamacedo86"
reviewers:
- TBD
approvers:
- TBD
creation-date: 2020-11-09
last-updated: 2021-02-14
status: implementable
---

# New Plugin (`deploy-image.go.kubebuilder.io/v1beta1`) to generate code

## Summary

This proposal defines a new plugin which allow users get the scaffold with the
required code to have a project that will deploy and manage an image on the cluster following the the guidelines and what have been considered as good practices.

## Motivation

The biggest part of the Kubebuilder users looking for to create a project that will at the end only deploy an image. In this way, one of the mainly motivations of this proposal is to abstract the complexities to achieve this goal and still giving the possibility of users improve and customize their projects according to their requirements.

**Note:** This plugin will address requests that has been raised for a while and for many users in the community. Check [here](https://github.com/operator-framework/operator-sdk/pull/2158), for example, a request done in the past for the SDK project which is integrated with Kubebuidler to address the same need.

### Goals

- Add a new plugin to generate the code required to deploy and manage an image on the cluster
- Promote the best practices as give example of common implementations
- Make the process to develop operators projects easier and more agil.
- Give flexibility to the users and allow them to change the code according to their needs
- Provide examples of code implementations and of the most common features usage and reduce the learning curve

### Non-Goals

The idea of this proposal is provide a facility for the users. This plugin can be improved
in the future, however, this proposal just covers the basic requirements. In this way, is a non-goal
allow extra configurations such as; scaffold the project using webhooks and the controller covered by tests.

## Proposal

Add the new plugin code generate which will scaffold code implementation to deploy the image informed which would like such as; `kubebuilder create api --group=crew --version=v1 --image=myexample:0.0.1 --kind=App --plugins=deploy-image.go.kubebuilder.io/v1beta1` which will:

- Add a code implementation which will do the Custom Resource reconciliation and create a Deployment resource for the `--image`;

- Add an EnvVar on the manager manifest (`config/manager/manager.yaml`) which will store the image informed and shows its possibility to users:

```yaml
..
spec:
containers:
- name: manager
env:
- name: {{ resource}}-IMAGE
value: {{image:tag}}
image: controller:latest
...
```

- Add a check into reconcile to ensure that the replicas of the deployment on cluster are equals the size defined in the CR:

```go
// Ensure the deployment size is the same as the spec
size := {{ resource }}.Spec.Size
if *found.Spec.Replicas != size {
found.Spec.Replicas = &size
err = r.Update(ctx, found)
if err != nil {
log.Error(err, "Failed to update Deployment", "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name)
return ctrl.Result{}, err
}
// Spec updated - return and requeue
return ctrl.Result{Requeue: true}, nil
}
```

- Add the watch feature for the Deployment managed by the controller:

```go
func (r *{{ resource }}Reconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&cachev1alpha1.{{ resource }}{}).
Owns(&appsv1.Deployment{}).
Complete(r)
}
```

- Add the RBAC permissions required for the scenario such as:

```go
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
```

- A status [conditions][conditions] to allow users check that if the deployment occurred successfully or its errors

- Add a [marker][markers] in the spec definition to demonstrate how to use OpenAPI schemas validation such as `+kubebuilder:validation:Minimum=1`

- Add the specs on the `_types.go` to generate the CRD/CR sample with default values for `ImagePullPolicy` (`Always`), `ContainerPort` (`80`) and the `Replicas Size` (`3`)

- Add a finalizer implementation with TODO for the CR managed by the controller such as described in the SDK doc [Handle Cleanup on Deletion](https://sdk.operatorframework.io/docs/building-operators/golang/advanced-topics/#handle-cleanup-on-deletion)

### User Stories

- I am as user, would like to use a command to scaffold my common need which is deploy an image of my application, so that I do not need to know exactly how to implement it

- I am as user, would like to have a good example code base which uses the common features, so that I can easily learn its concepts and have a good start point to address my needs.

- I am as maintainer, would like to have a good example to address the common questions, so that I can easily describe how to implement the projects and/or use the common features.

### Implementation Details/Notes/Constraints

**Example of the controller template**

```go
// +kubebuilder:rbac:groups=cache.example.com,resources={{ resource.plural }},verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=cache.example.com,resources={{ resource.plural }}/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=cache.example.com,resources={{ resource.plural }}/finalizers,verbs=update
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete

func (r *{{ resource }}.Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("{{ resource }}", req.NamespacedName)

// Fetch the {{ resource }} instance
{{ resource }} := &{{ apiimportalias }}.{{ resource }}{}
err := r.Get(ctx, req.NamespacedName, {{ resource }})
if err != nil {
if errors.IsNotFound(err) {
// Request object not found, could have been deleted after reconcile request.
// Owned objects are automatically garbage collected. For additional cleanup logic use finalizers.
// Return and don't requeue
log.Info("{{ resource }} resource not found. Ignoring since object must be deleted")
return ctrl.Result{}, nil
}
// Error reading the object - requeue the request.
log.Error(err, "Failed to get {{ resource }}")
return ctrl.Result{}, err
}

// Check if the deployment already exists, if not create a new one
found := &appsv1.Deployment{}
err = r.Get(ctx, types.NamespacedName{Name: {{ resource }}.Name, Namespace: {{ resource }}.Namespace}, found)
if err != nil && errors.IsNotFound(err) {
// Define a new deployment
dep := r.deploymentFor{{ resource }}({{ resource }})
log.Info("Creating a new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
err = r.Create(ctx, dep)
if err != nil {
log.Error(err, "Failed to create new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name)
return ctrl.Result{}, err
}
// Deployment created successfully - return and requeue
return ctrl.Result{Requeue: true}, nil
} else if err != nil {
log.Error(err, "Failed to get Deployment")
return ctrl.Result{}, err
}

// Ensure the deployment size is the same as the spec
size := {{ resource }}.Spec.Size
if *found.Spec.Replicas != size {
found.Spec.Replicas = &size
err = r.Update(ctx, found)
if err != nil {
log.Error(err, "Failed to update Deployment", "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name)
return ctrl.Result{}, err
}
// Spec updated - return and requeue
return ctrl.Result{Requeue: true}, nil
}

// TODO: add here code implementation to update/manage the status

return ctrl.Result{}, nil
}

// deploymentFor{{ resource }} returns a {{ resource }} Deployment object
func (r *{{ resource }}Reconciler) deploymentFor{{ resource }}(m *{{ apiimportalias }}.{{ resource }}) *appsv1.Deployment {
ls := labelsFor{{ resource }}(m.Name)
replicas := m.Spec.Size

dep := &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name: m.Name,
Namespace: m.Namespace,
},
Spec: appsv1.DeploymentSpec{
Replicas: &replicas,
Selector: &metav1.LabelSelector{
MatchLabels: ls,
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: ls,
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{{
Image: imageFor{{ resource }}(m.Name),
Name: {{ resource }},
ImagePullPolicy: {{ resource }}.Spec.ContainerImagePullPolicy,
Command: []string{"{{ resource }}"},
Ports: []corev1.ContainerPort{{
ContainerPort: {{ resource }}.Spec.ContainerPort,
Name: "{{ resource }}",
}},
}},
},
},
},
}
// Set {{ resource }} instance as the owner and controller
ctrl.SetControllerReference(m, dep, r.Scheme)
return dep
}

// labelsFor{{ resource }} returns the labels for selecting the resources
// belonging to the given {{ resource }} CR name.
func labelsFor{{ resource }}(name string) map[string]string {
return map[string]string{"type": "{{ resource }}", "{{ resource }}_cr": name}
}

// imageFor{{ resource }} returns the image for the resources
// belonging to the given {{ resource }} CR name.
func imageFor{{ resource }}(name string) string {
// TODO: this method will return the value of the envvar create to store the image:tag informed
}

func (r *{{ resource }}Reconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&cachev1alpha1.{{ resource }}{}).
Owns(&appsv1.Deployment{}).
Complete(r)
}

```

**Example of the spec for the <kind>_types.go template**

```go
// {{ resource }}Spec defines the desired state of {{ resource }}
type {{ resource }}Spec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// +kubebuilder:validation:Minimum=1
// Size defines the number of {{ resource }} instances
Size int32 `json:"size,omitempty"`

// ImagePullPolicy defines the policy to pull the container images
ImagePullPolicy string `json:"image-pull-policy,omitempty"`

// ContainerPort specifies the port which will be used by the image container
ContainerPort int `json:"container-port,omitempty"`

}
```

## Design Details

### Test Plan

To ensure this implementation a new project example should be generated in the [testdata](../testdata/) directory of the project. See the [test/testadata/generate.sh](../test/testadata/generate.sh). Also, we should use this scaffold in the [integration tests](../test/e2e/) to ensure that the data scaffolded with works on the cluster as expected.

### Graduation Criteria

- The new plugin will only be support `project-version=3`
- The attribute image with the value informed should be added to the resources model in the PROJECT file to let the tool know that the Resource get done with the common basic code implementation:

```yaml
plugins:
deploy-image.go.kubebuilder.io/v1beta1:
resources:
- domain: example.io
group: crew
kind: Captain
version: v1
image: "<some-registry>/<project-name>:<tag>
```

For further information check the definition agreement register in the comment https://github.com/kubernetes-sigs/kubebuilder/issues/1941#issuecomment-778649947.

## Open Questions

1. Should we allow to scaffold the code for an API that is already created for the project?
No, at least in the first moment to keep the simplicity.

2. Should we support StatefulSet and Deployments?
The idea is we start it by using a Deployment. However, we can improve the feature in follow-ups to support more default types of scaffolds which could be like `kubebuilder create api --group=crew --version=v1 --image=myexample:0.0.1 --kind=App --plugins=deploy-image.go.kubebuilder.io/v1beta1 --type=[deployment|statefulset|webhook]`

3. Could this feature be useful to other languages or is it just valid to Go based operators?

This plugin would is reponsable to scaffold content and files for Go-based operators. In a future, if other language-based operators starts to be supported (either officially or by the community) this plugin could be used as reference to create an equivalent one for their languages. Therefore, it should probably not to be a `subdomain` of `go.kubebuilder.io.`

For its integration with SDK, it might be valid for the Ansible-based operators where a new `playbook/role` could be generated as well. However, for example, for the Helm plugin it might to be useless. E.g `deploy-image.ansible.sdk.operatorframework.io/v1beta1`

4. Should we consider create a separate repo for plugins?

In the long term yes. However, see that currently, Kubebuilder has not too many plugins yet. And then, and the preliminary support for plugins did not indeed release. For more info see the [Extensible CLI and Scaffolding Plugins][plugins-phase1-design-doc].

In this way, at this moment, it shows to be a little Premature Optimization. Note that the issue [#2016](https://github.com/kubernetes-sigs/kubebuilder/issues/1378) will check the possibility of the plugins be as separate binaries that can be discovered by the Kubebuilder CLI binary via user-specified plugin file paths. Then, the discussion over the best approach to dealing with many plugins and if they should or not leave in the Kubebuilder repository would be better addressed after that.

5. Is Kubebuilder prepared to receive this implementation already?

The [Extensible CLI and Scaffolding Plugins - Phase 1.5](extensible-cli-and-scaffolding-plugins-phase-1-5.md) and the issue #1941 requires to be implemented before this proposal. Also, to have a better idea over the proposed solutions made so for the Plugin Ecosystem see the meta issue [#2016](https://github.com/kubernetes-sigs/kubebuilder/issues/2016)

[markers]: ../docs/book/src/reference/markers.md
[conditions]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
[plugins-phase1-design-doc]: https://github.com/kubernetes-sigs/kubebuilder/blob/master/designs/extensible-cli-and-scaffolding-plugins-phase-1.md