Is it possile to create yaml object from helm from file - kubernetes-helm

I want to iterate over the Yaml list which is defined in the file, and use it in Job. For example i have
test.yaml
list:
- first element
- second element
In _helpers.tpl i can define
something like
{{- define "mychart.list" -}}
{{ .Files.Get "test.yaml"| toYaml }}
{{- end }}
And then in Job i want do something like
{{- $lists := include "mychart.list" . }}
{{- range $element := $lists.list}}
apiVersion: batch/v1
kind: Job
metadata:
and then use the $element.
But when i am trying to do the dry-run with --debug it complains about
at <$lists.list>: can't evaluate field list in type string.
Looks like whole value is coming as string rather than Yaml, does it needs explicit call to Yaml parser ? If yes, is there a way to do that ?
BTW i have also tried various combinations of
{{- $lists := include "mychart.list" . | toYaml }}
or loading the file inline, but none of them helps.
I can put the list in Values.yaml, but don't want to do that purposely.
Any help is really appreciated.

Just putting for future reference, if someone comes and have look.
There's fromYaml function, which is undocumented. I found it hard way, but that solved the isssue.
{{- $lists := include "mychart.list" . | fromYaml}}

Related

How to use range function to keep values in same line in helm

I am trying to build configmap data out of values I have in values.yaml.
CASE 1:
values.yaml:
dns_domains: abc xyz
dns_servers: IP1 IP2 IP3
I want configmap data something as below for the above values.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: Corefile
data:
abc:53 {
log
errors
cache 30
forward . IP1 IP2 IP3
}
xyz:53 {
log
errors
cache 30
forward . IP1 IP2 IP3
}
CASE 2:
values.yaml:
dns_domains: abc xyz
dns_servers:
or
dns_domains: abc xyz
I want configmap data something as below for the above values.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: Corefile
data:
abc:53 {
log
errors
cache 30
}
xyz:53 {
log
errors
cache 30
}
I tried something as below and got stucked how to make "forward" line to have all values in the range
{{- range $domain := splitList " " .Values.dns_int_domains }}
$domain:53 {
log
errors
cache 30
{{- range $dns_int_server := splitList " " .Values.dns_int_servers }}
{{- if $dns_int_server }}
forward . $dns_int_server # how to make this line to have all values in dns_int_server list
{{- end }}
}
{{- end }}
Note: we should have only one forward plugin inside a server block. i.e, below is not allowed
abc:53 {
forward . IP1
forward . IP2
}
It would be really grateful if someone helps me out. Thanks in advance!!!
With the format you currently have, .Values.dns_servers is already a string with space-separated values, which is the format you want out. You don't need to split it to a list and write it out again.
{{- if .Values.dns_servers }}
forward . {{ .Values.dns_servers }}
{{- end }}
Helm contains (almost all of) the extension functions in the Sprig library, not all of which are in the Helm documentation proper. If you do have this as a list, there is a join template function that can combine them together.
{{- $dns_servers := splitList " " .Values.dns_servers }}
{{- if $dns_servers }}
forward . {{ join " " $dns_servers }}
{{- end }}
Rather than a space-separated string, you might find it easier to manipulate these values if you use native YAML lists in your values.yaml file. Any valid YAML list syntax will work here, including formats that put the entire list on one line.
# values.yaml, reformatted to use YAML lists and snakeCase names
dnsDomains: [abc,xyz]
dnsServers:
- 10.10.10.10
- 10.10.10.11
- 10.10.20.20
As one final option, if you're very careful about the whitespace handling, you can put the templating anywhere you want, even in the middle of a line.
{{- with .Values.dnsServers }}
forward .
{{- range . }} {{ . }}{{ end }}
{{- end }}
The important trick with this last example is that the - whitespace control before range also consumes the newline at the end of the previous line. Then inside the range block, repeated once for each element and with no whitespace control, there is a space and a list element. Finally after the very last end there is a newline.
You can double-check this with helm template, which will validate the YAML syntax and print out what got rendered (with --debug it will print it out even if it's invalid YAML).

Values context in an included helm named template

We have a helm chart that contains named templates to be used by other templates.
Originally, the helm chart containing the named templates has no "values.yaml" file, as all it has are "_function.tpl" files. But now, we would like to use a "values.yaml" file to define some values there instead of having to be passed by the caller like so after defining the dependency in the Chart.yaml.
{{ include "libchart.velero" (list . .Values.velero )}}
The named template then would have a definition, which converts those contexts passed as list to $root and "velero", so we can work comfortably with the caller passed context, like so:
{{- define "libchart.velero" -}}
{{- $root := index . 0 -}}
{{- $velero := index . 1 -}}
But question is, how could I define and consume the variables define in the "values.yaml" file present in the chart that contains the definition of the named template itself.
I've tried using things like {{ $.Values.local }} and {{ .Values.local }} to access "locally to the named template" defined variable, but no luck with those.
With that construction, the top-level Helm object (which contains Values, Release, Namespace, etc. fields) is in the $root variable inside the template.
{{-/*
Call with a list of two items, the top-level Helm object and the
.Values.velero chart configuration.
Outputs something only if the `local` top-level value is set.
*/-}}
{{- define "libchart.velero" -}}
{{- $root := index . 0 -}}
{{- $velero := index . 1 -}}
{{- if $root.Values.local -}} {{-/* <-- like this */-}}
... {{ $velero }} ...
{{- end -}}
{{- end -}}

Helm's v3 Example Doesn't Show Multi-line Properties. Get YAML to JSON parse error

In Helm's v3 documentation: Accessing Files Inside Templates, the author gives an example of 3 properties (toml) files; where each file has only one key/value pair.
The configmap.yaml looks like this. I'm only adding one config.toml for simplicity.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-config
data:
{{- $files := .Files }}
{{- range tuple "config.toml" }}
{{ . }}: |-
{{ $files.Get . }}
{{- end }}
This works fine, until I add a second line to the config.toml file.
config.toml
replicaCount=1
foo=bar
Then I get an Error: INSTALLATION FAILED: YAML parse error on deploy/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: could not find expected ':'
Any thoughts will be appreciated.
Thanks
Helm will read in that file, but it is (for good or bad) a text templating engine. It does not understand that you are trying to compose a YAML file and thus it will not help you. That's actually why you will see so many, many templates in the wild with {{ .thing | indent 8 }} or {{ .otherThing | toYaml }} -- because you need to help Helm know in what context it is emitting the text
Thus, in your specific case, you'll want the indent filter with a value of 4 because your current template has two spaces for the key indent level, and two more spaces for the value block scalar
data:
{{- $files := .Files }}
{{- range tuple "config.toml" }}
{{ . }}: |-
{{ $files.Get . | indent 4 }}
{{/* notice this ^^^ template expression is flush left,
because the 'indent' is handling whitespace, not the golang template itself */}}
{{- end }}
Also, while this is the specific answer to your question, don't overlook the .AsConfig section on that page which seems much more likely to be what you really want to happen, and requires less indent math

How to filter out file names from a .File.Glob in a Helm Chart

I have the following snippet in a helm library which is supposed to add in all the files in a folder into a ConfigMap except for those ending in .tz.
{{- /*
add the contents of every file in the config folder of this IOC helm chart
into the config map - this must include start.sh the startup script.
The files must be text only. Any files ending in .tz are explicitly ommitted
*/ -}}
{{ (.Files.Glob "config/*[!.tz]").AsConfig | indent 2 }}
version.txt: |
IOC {{ .Release.Name }} version {{ .Chart.AppVersion }}
This does not quite work in that it filters out all files ending in . or t or z.
I cant see how to do this with Go globbing. I also cannot work out the syntax for using 'without' for the list created by .Files.Glob.
Can anyone enlighten me? Thanks!
Thanks #David Maze. This almost worked but the reference to .Files.Get failed and I think that is because the . context becomes the range counter within the range loop.
Adding $ to .Files within the loop got it working.
Also to fully replicate AsConfig I needed to extract the basename from
the path which I did by adding regexReplaceAll.
data:
{{- range $path, $_ := .Files.Glob "config/*" }}
{{- if not (hasSuffix ".tz" $path) }}
{{ regexReplaceAll "(.*)/" $path "" }}: |
{{ $.Files.Get $path | indent 4 }}
{{- end }}
{{- end }}
The Helm documentation references the Go "github.com/gobwas/glob" package for the supported glob syntax; that doesn't support any sort of "except" cases, except for single characters.
What you can do instead is iterate over all of the files, and then use a normal conditional to exclude the ones you don't want. You have to construct the ConfigMap structure yourself rather than relying on the AsConfig helper.
data:
{{- range $path, $_ := .Files.Glob "config/*" }}
{{- if not (hasSuffix ".tz" $path) }}
{{ $path }}: |
{{ .Files.Get $path | indent 4 }}
{{- end }}
{{- end }}

Helm include templates

Please! Is it possible to squash multiple helm templates into one and then refer to it as a one-liner in a deployment file?
EG:
{{- define "foo.deploy" -}}
value:
{{- include "foo.1" . | nindent 6 }}
{{- include "foo.2" . | nindent 6 }}
{{- include "foo.3" . | nindent 6 }}
And then do an {{- include "foo.deploy" . }} in a separate deployment file.
Which should then contain foo.1, foo.2 and foo.3, and their respective definitions.
As opposed to literally writing out all three different 'includes' especially if you've got loads.
Much appreciated,
Thanks,
A named template (sometimes called a partial or a subtemplate) is simply a template defined inside of a file, and given a name. We’ll see two ways to create them, and a few different ways to use them.
Template names are global. As a result of this, if two templates are declared with the same name the last occurrence will be the one that is used. Since templates in subcharts are compiled together with top-level templates, it is best to name your templates with chart specific names. A popular naming convention is to prefix each defined template with the name of the chart: {{ define "mychart.labels" }}.
More information about named templates you can find here: named-template.
Proper configuration file should look like:
{{/* Generate basic labels */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
In your case part of file should looks like:
{{- define "foo.deploy" -}}
{{- include "foo.1" . | nindent 6 }}
{{- include "foo.2" . | nindent 6 }}
{{- include "foo.3" . | nindent 6 }}
{{ end }}