Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ testbin/*

dist/

vendor/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Usage:
| -cert-manager-install-crd | Allows the user to install cert-manager CRD as part of the cert-manager subchart.(default "true") | `helmify -cert-manager-install-crd` |
| -preserve-ns | Allows users to use the object's original namespace instead of adding all the resources to a common namespace. (default "false") | `helmify -preserve-ns` |
| -add-webhook-option | Adds an option to enable/disable webhook installation | `helmify -add-webhook-option`|
| -optional-crds | Enable optional CRD installation through values. | `helmify -optional-crds` |
## Status
Supported k8s resources:
- Deployment, DaemonSet, StatefulSet
Expand Down
9 changes: 5 additions & 4 deletions cmd/helmify/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,17 @@ func ReadFlags() config.Config {
flag.BoolVar(&result.Verbose, "v", false, "Enable verbose output (print WARN & INFO). Example: helmify -v")
flag.BoolVar(&result.VeryVerbose, "vv", false, "Enable very verbose output. Same as verbose but with DEBUG. Example: helmify -vv")
flag.BoolVar(&crd, "crd-dir", false, "Enable crd install into 'crds' directory.\nWarning: CRDs placed in 'crds' directory will not be templated by Helm.\nSee https://helm.sh/docs/chart_best_practices/custom_resource_definitions/#some-caveats-and-explanations\nExample: helmify -crd-dir")
flag.BoolVar(&result.ImagePullSecrets, "image-pull-secrets", false, "Allows the user to use existing secrets as imagePullSecrets in values.yaml")
flag.BoolVar(&result.ImagePullSecrets, "image-pull-secrets", false, "Allows the user to use existing secrets as imagePullSecrets in values.yaml.")
flag.BoolVar(&result.GenerateDefaults, "generate-defaults", false, "Allows the user to add empty placeholders for typical customization options in values.yaml. Currently covers: topology constraints, node selectors, tolerances")
flag.BoolVar(&result.CertManagerAsSubchart, "cert-manager-as-subchart", false, "Allows the user to add cert-manager as a subchart")
flag.StringVar(&result.CertManagerVersion, "cert-manager-version", "v1.12.2", "Allows the user to specify cert-manager subchart version. Only useful with cert-manager-as-subchart.")
flag.BoolVar(&result.CertManagerInstallCRD, "cert-manager-install-crd", true, "Allows the user to install cert-manager CRD. Only useful with cert-manager-as-subchart.")
flag.BoolVar(&result.FilesRecursively, "r", false, "Scan dirs from -f option recursively")
flag.BoolVar(&result.OriginalName, "original-name", false, "Use the object's original name instead of adding the chart's release name as the common prefix.")
flag.Var(&files, "f", "File or directory containing k8s manifests")
flag.BoolVar(&preservens, "preserve-ns", false, "Use the object's original namespace instead of adding all the resources to a common namespace")
flag.BoolVar(&result.AddWebhookOption, "add-webhook-option", false, "Allows the user to add webhook option in values.yaml")
flag.Var(&files, "f", "File or directory containing k8s manifests.")
flag.BoolVar(&preservens, "preserve-ns", false, "Use the object's original namespace instead of adding all the resources to a common namespace.")
flag.BoolVar(&result.AddWebhookOption, "add-webhook-option", false, "Allows the user to add webhook option in values.yaml.")
flag.BoolVar(&result.OptionalCRDs, "optional-crds", false, "Enable optional CRD installation through values.")

flag.Parse()
if h || help {
Expand Down
4 changes: 3 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ type Config struct {
OriginalName bool
// PreserveNs retains the namespaces on the Kubernetes manifests
PreserveNs bool
// AddWebhookOption enables the generation of a webhook option in values.yamlß
// AddWebhookOption enables the generation of a webhook option in values.yaml
AddWebhookOption bool
// OptionalCRDs - Enable optional CRD installation through values.
OptionalCRDs bool
}

func (c *Config) Validate() error {
Expand Down
25 changes: 19 additions & 6 deletions pkg/processor/crd/crd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package crd
import (
"bytes"
"fmt"
"github.com/sirupsen/logrus"
"io"
"strings"

"github.com/sirupsen/logrus"

v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
Expand Down Expand Up @@ -34,6 +35,8 @@ status:
conditions: []
storedVersions: []`

const optionalCRDsConditional = "crds.enabled"

var crdGVC = schema.GroupVersionKind{
Group: "apiextensions.k8s.io",
Version: "v1",
Expand Down Expand Up @@ -129,23 +132,33 @@ func (c crd) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured
res := fmt.Sprintf(crdTeml, obj.GetName(), appMeta.ChartName(), annotations, labels, string(specYaml))
res = strings.ReplaceAll(res, "\n\n", "\n")

values := helmify.Values{}

if appMeta.Config().OptionalCRDs {
res = fmt.Sprintf("{{- if .Values.%s }}\n%s\n{{- end }}", optionalCRDsConditional, res)
_, _ = values.Add(true, strings.Split(optionalCRDsConditional, ".")...)
logrus.WithField("crd", name).WithField("condition", optionalCRDsConditional).Debug("enabling optional CRD installation")
}

return true, &result{
name: name + "-crd.yaml",
data: []byte(res),
name: name + "-crd.yaml",
data: []byte(res),
values: values,
}, nil
}

type result struct {
name string
data []byte
name string
data []byte
values helmify.Values
}

func (r *result) Filename() string {
return r.name
}

func (r *result) Values() helmify.Values {
return helmify.Values{}
return r.values
}

func (r *result) Write(writer io.Writer) error {
Expand Down
40 changes: 40 additions & 0 deletions pkg/processor/crd/crd_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package crd

import (
"strings"
"testing"

"github.com/arttor/helmify/pkg/config"
"github.com/arttor/helmify/pkg/metadata"

"github.com/arttor/helmify/internal"
Expand Down Expand Up @@ -45,4 +47,42 @@ func Test_crd_Process(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, false, processed)
})

t.Run("wrapped with condition", func(t *testing.T) {
obj := internal.GenerateObj(strCRD)

meta := metadata.New(config.Config{OptionalCRDs: true})
processed, tmpl, err := testInstance.Process(meta, obj)
assert.NoError(t, err)
assert.True(t, processed)
assert.NotNil(t, tmpl)

data := string(tmpl.(*result).data)

assert.Contains(t, data, "{{- if .Values."+optionalCRDsConditional+" }}", "template should start with conditional")
assert.Contains(t, data, "{{- end }}", "template should end with conditional")

values := tmpl.(*result).values
val, ok := getValue(values, optionalCRDsConditional)
assert.True(t, ok, "expected key crds."+optionalCRDsConditional+" in values")
assert.Equal(t, true, val)
})
}

func getValue(values map[string]any, path string) (any, bool) {
parts := strings.Split(path, ".")
current := any(values)

for _, part := range parts {
m, ok := current.(map[string]any)
if !ok {
return nil, false
}
current, ok = m[part]
if !ok {
return nil, false
}
}

return current, true
}