Draft: Introduce interpret command

This is a (functional?) proof of concept of the work in progress done to move interpretation of the values to sylva-units-operator (described in sylva-projects&61)

The interpretation engine is expected to move to sylva-units-operator, but it will also be usable with sylvactl as exposed here in order to replace "helm template" command that won't be usable any more as soon as we'll start using custom functions in our values.

It is backward compatible with our current code and can already be used to interpret values:

./sylvactl interpret charts/sylva-units/ -f charts/sylva-units/management.values.yaml

(note that in contrary to helm template, it will use the provided kubeconfig to perform lookup on cluster, use '--install' and '--offline' flags to interpret values w/o cluster connectivity. This part will be revisited to provide a clean interface)

But it is also able to leverage the new template engine to perform a "smarter" interpretation of values. Here is a preview of the proposed format:

Provided a sample chart with following values.yaml

unit_templates:
  base-deps:
    depends_on:
      cluster-machines-ready: true

  kube-job:
    kustomization_spec:
      name: '{{ unitName . }}'    # <<< new unitName template to find unit name

units:
  foo:
    (templates):
      - unit_templates.base-deps     # <<< will use "unit_templates.base-deps" as template for foo
      - unit_templates.kube-job

  bar:
    list:
      - item1
      - item2
    (templates):
      - unit_templates.base-deps

test:
  reference: '{{ randAlphaNum 64 }}'
  get-reference: '{{ eval "test.reference" }}'             # <<< eval ensures nested interpretation of values
  preserve-type: '{{ eval "units.bar" | preserveType }}'            # <<< preserveType is more concise
  nested: '{{ eval "test.reference" | b64enc }}'
  result: '{{ eval "test.nested" | b64dec }}'
  assertion: >-
    {{- if ne (eval "test.result") (eval "test.reference") -}}
       {{ fail (printf "expected %s but got %s" (eval "test.reference") (eval "test.result")) -}}
    {{- else -}}
       "test passed"
    {{- end -}}

it can merge extra-values.yaml with power-merge syntax:

units:
  bar:
    (append)list:
      - item3

using following syntax:

sylvactl interpret . -f extra-values.yaml --install --offline

Key benefits:

  • It provide a much more powerful templating language:
    • supports power-merging lists (append/prepend)
    • it provides safe support for nested templating
    • it allows us to easely introduce new functions
  • As it supports new syntax in a backward compatible way, it'll allow us to revisit the syntax of our values progressively
  • It is much more performant than our internal gotpl interpreter:
❯ time ./sylvactl interpret ../../sylva-core/charts/sylva-units/ -f ../../sylva-core/charts/sylva-units/management.values.yaml &>/dev/null

real    0m6,506s
user    0m5,256s
sys     0m0,387s

❯ time helm template interpret charts/sylva-units/ -f charts/sylva-units/management.values.yaml --show-only templates/extras/interpreted-values.tpl &>/dev/null

real    0m22,173s
user    0m41,184s
sys     0m2,522s
  • It displays much more meaningful error messages:

instead of

❯ helm template interpret charts/sylva-units/ -f charts/sylva-units/management.values.yaml --show-only templates/extras/interpreted-values.tpl
Error: template: sylva-units/templates/extras/interpreted-values.tpl:39:3:
executing "sylva-units/templates/extras/interpreted-values.tpl" at <include "interpret-values-gotpl" .>: error calling include: template: sylva-units/templates/_interpret-values.tpl:119:71:
executing "interpret-values-gotpl" at <include "interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:307:38:
executing "interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:373:54:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:373:54:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:373:54:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:373:54:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:355:49:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:373:54:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:373:54:
executing "_interpret-inner-gotpl" at <include "_interpret-inner-gotpl">: error calling include: template: sylva-units/templates/_interpret-values.tpl:339:28:
executing "_interpret-inner-gotpl" at <tpl $data $envAll>: error calling tpl: error during tpl function execution for "{{ div 1 0 }}": template: gotpl:1:3:
executing "gotpl" at <div 1 0>: error calling div: runtime error: integer divide by zero

it'll print

❯ ./sylvactl interpret ../../sylva-core/charts/sylva-units/ -f ../../sylva-core/charts/sylva-units/management.values.yaml 
Error: failed to render values: failed to evaluate '{{ div 1 0 }}' at path units.workload-teams-repo.kustomization_spec._patches.0.target.kind: error calling div: runtime error: integer divide by zero

Side note:

pkg/value-engine/engine code is almost fully copied from helm code, our code lives in evalfunc.go and few lines had to be added to engine.go to add our custom function to funcMap (since we have pass all values to this function, we can't use engine's CustomTemplateFuncs)

Edited by Francois Eleouet

Merge request reports

Loading
Loading