Skip to content

Commit

Permalink
Add templateValues to HelmApp, Bundle, etc
Browse files Browse the repository at this point in the history
Signed-off-by: Danil-Grigorev <[email protected]>
  • Loading branch information
Danil-Grigorev committed Jan 30, 2025
1 parent 9a7eeb7 commit 86be9f3
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 6 deletions.
108 changes: 108 additions & 0 deletions charts/fleet-crd/templates/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,24 @@ spec:
description: TakeOwnership makes helm skip the check for
its own annotations
type: boolean
templateValues:
additionalProperties:
type: string
description: 'Template Values passed to Helm. It is possible
to specify the keys and values
as go template strings. Unlike .values, content of each
key will be templated
first, before serializing to yaml. This allows to template
complex values,
like ranges and maps.
templateValues keys have precedence over values keys in
case of conflict.'
nullable: true
type: object
timeoutSeconds:
description: TimeoutSeconds is the time to wait for Helm
operations.
Expand Down Expand Up @@ -695,6 +713,24 @@ spec:
description: TakeOwnership makes helm skip the check for
its own annotations
type: boolean
templateValues:
additionalProperties:
type: string
description: 'Template Values passed to Helm. It is possible
to specify the keys and values
as go template strings. Unlike .values, content of each
key will be templated
first, before serializing to yaml. This allows to template
complex values,
like ranges and maps.
templateValues keys have precedence over values keys in
case of conflict.'
nullable: true
type: object
timeoutSeconds:
description: TimeoutSeconds is the time to wait for Helm
operations.
Expand Down Expand Up @@ -1568,6 +1604,24 @@ spec:
description: TakeOwnership makes helm skip the check for its
own annotations
type: boolean
templateValues:
additionalProperties:
type: string
description: 'Template Values passed to Helm. It is possible
to specify the keys and values
as go template strings. Unlike .values, content of each key
will be templated
first, before serializing to yaml. This allows to template
complex values,
like ranges and maps.
templateValues keys have precedence over values keys in case
of conflict.'
nullable: true
type: object
timeoutSeconds:
description: TimeoutSeconds is the time to wait for Helm operations.
type: integer
Expand Down Expand Up @@ -2433,6 +2487,24 @@ spec:
description: TakeOwnership makes helm skip the check for
its own annotations
type: boolean
templateValues:
additionalProperties:
type: string
description: 'Template Values passed to Helm. It is possible
to specify the keys and values
as go template strings. Unlike .values, content of each
key will be templated
first, before serializing to yaml. This allows to template
complex values,
like ranges and maps.
templateValues keys have precedence over values keys
in case of conflict.'
nullable: true
type: object
timeoutSeconds:
description: TimeoutSeconds is the time to wait for Helm
operations.
Expand Down Expand Up @@ -7307,6 +7379,24 @@ spec:
description: TakeOwnership makes helm skip the check for its
own annotations
type: boolean
templateValues:
additionalProperties:
type: string
description: 'Template Values passed to Helm. It is possible
to specify the keys and values
as go template strings. Unlike .values, content of each key
will be templated
first, before serializing to yaml. This allows to template
complex values,
like ranges and maps.
templateValues keys have precedence over values keys in case
of conflict.'
nullable: true
type: object
timeoutSeconds:
description: TimeoutSeconds is the time to wait for Helm operations.
type: integer
Expand Down Expand Up @@ -8191,6 +8281,24 @@ spec:
description: TakeOwnership makes helm skip the check for
its own annotations
type: boolean
templateValues:
additionalProperties:
type: string
description: 'Template Values passed to Helm. It is possible
to specify the keys and values
as go template strings. Unlike .values, content of each
key will be templated
first, before serializing to yaml. This allows to template
complex values,
like ranges and maps.
templateValues keys have precedence over values keys
in case of conflict.'
nullable: true
type: object
timeoutSeconds:
description: TimeoutSeconds is the time to wait for Helm
operations.
Expand Down
6 changes: 6 additions & 0 deletions internal/cmd/controller/options/calculate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"maps"

fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
"github.com/rancher/wrangler/v3/pkg/data"
Expand Down Expand Up @@ -52,6 +53,11 @@ func Merge(base, custom fleet.BundleDeploymentOptions) fleet.BundleDeploymentOpt
} else if custom.Helm.Values != nil {
result.Helm.Values.Data = data.MergeMaps(result.Helm.Values.Data, custom.Helm.Values.Data)
}
if result.Helm.TemplateValues == nil {
result.Helm.TemplateValues = custom.Helm.TemplateValues
} else if custom.Helm.TemplateValues != nil {
maps.Copy(result.Helm.TemplateValues, custom.Helm.TemplateValues)
}
if custom.Helm.ValuesFrom != nil {
result.Helm.ValuesFrom = append(result.Helm.ValuesFrom, custom.Helm.ValuesFrom...)
}
Expand Down
55 changes: 51 additions & 4 deletions internal/cmd/controller/target/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package target

import (
"bytes"
"cmp"
"context"
"fmt"
"maps"
"sort"
"strings"
"text/template"
Expand Down Expand Up @@ -182,10 +184,15 @@ func preprocessHelmValues(logger logr.Logger, opts *fleet.BundleDeploymentOption
}

opts.Helm = opts.Helm.DeepCopy()
if opts.Helm.Values == nil || opts.Helm.Values.Data == nil {
opts.Helm.Values = &fleet.GenericMap{
Data: map[string]interface{}{},
}
opts.Helm.Values = cmp.Or(opts.Helm.Values, &fleet.GenericMap{
Data: map[string]interface{}{},
})

if opts.Helm.Values.Data == nil {
opts.Helm.Values.Data = map[string]interface{}{}
}

if opts.Helm.TemplateValues == nil && len(opts.Helm.Values.Data) == 0 {
return nil
}

Expand All @@ -211,6 +218,14 @@ func preprocessHelmValues(logger logr.Logger, opts *fleet.BundleDeploymentOption
if err != nil {
return err
}

templatedData, err := processTemplateValuesData(opts.Helm.TemplateValues, values)
if err != nil {
return err
}

maps.Copy(opts.Helm.Values.Data, templatedData)

logger.V(4).Info("preProcess completed", "releaseName", opts.Helm.ReleaseName)
}

Expand Down Expand Up @@ -278,6 +293,38 @@ func tplFuncMap() template.FuncMap {
return f
}

func processTemplateValuesData(helmTemplateData map[string]string, templateContext map[string]interface{}) (map[string]interface{}, error) {
renderedValues := make(map[string]interface{}, len(helmTemplateData))

for k, v := range helmTemplateData {
// fleet.yaml must be valid yaml, however '{}[]' are YAML control
// characters and will be interpreted as JSON data structures. This
// causes issues when parsing the fleet.yaml so we change the delims
// for templating to '${ }'
tmpl := template.New("values").Funcs(tplFuncMap()).Option("missingkey=error").Delims("${", "}")
tmpl, err := tmpl.Parse(v)
if err != nil {
return nil, fmt.Errorf("failed to parse helm values template: %w", err)
}

var b bytes.Buffer
err = tmpl.Execute(&b, templateContext)
if err != nil {
return nil, fmt.Errorf("failed to render helm values template: %w", err)
}

var value interface{}
err = kyaml.Unmarshal(b.Bytes(), &value)
if err != nil {
return nil, fmt.Errorf("failed to interpret rendered template as helm values: %s, %v", b.String(), err)
}

renderedValues[k] = value
}

return renderedValues, nil
}

func processTemplateValues(helmValues map[string]interface{}, templateContext map[string]interface{}) (map[string]interface{}, error) {
data, err := kyaml.Marshal(helmValues)
if err != nil {
Expand Down
Loading

0 comments on commit 86be9f3

Please sign in to comment.