How to use range function to keep values in same line in helm - kubernetes-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).

Related

how split if statement over multiple lines in helm chart

Im trying to format my yml to be more readable.
I have an if statement that is really long with a bunch of and/ors and I would like to be able to spread it across multiple lines
So something along the lines of
{{-if or
(eq 'abc' .values.foo)
(eq 'def' . values.bar)
}}
Def:'works'
{{- end}}
But this throws up errors for incomplete if statement.
Is there some special character or syntax I can use to achieve the above?
helm supports direct line breaks without special characters.
Missing a space between {{ and if.
There is an extra space between . and values.
String constants require double quotes.
demo:
values.yaml
foo: xxx
bar: yyy
templates/cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
labels:
{{- include "test.labels" . | nindent 4 }}
data:
cfg: |-
{{- if or
(eq "abc" .Values.foo)
(eq "def" .Values.bar)
}}
if
{{- else }}
else
{{- end }}
cmd
helm template --debug test .
output
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
cfg: |-
else

helm --set to select environment

Struggling with some helm templating...
I'm trying to pass a separate yaml file with springboot parameters to helm, and have them split by environment... then I want to pass the environment to helm using --set env=staging
Feels like I've tried everything but clearly I'm lacking a fundamental understanding...
My _helpers.tpl contains these:
{{- define "env" }}
{{- printf "%s" .Values.env }}
{{- end }}
{{ define "configmap.metadata" }}
name: {{ .Values.name }}-config
{{ end }}
{{ define "configmap.properties" }}
{{ index .Values.environment (include "env" .) "properties" | indent 4 }}
{{ end }}
The template for the config map:
apiVersion: v1
kind: ConfigMap
metadata:
{{ include "configmap.metadata" . }}
data:
app.properties: |-
{{ include "configmap.properties" .}}
And the yaml file containing the properties looks like this:
environment:
staging:
properties:
spring:
datasource:
url: something
username: something
password: something
app1:
key: something
secret: something
baseUri: something
app2:
bootstrap_server: something
bootstrap_port: something
registry_schema: something
production:
properties:
spring:
etc, etc
And then I want to select the environment using set. I'm testing with:
helm template test . -f values.yaml -f properties.yaml --set env=staging
I think I've just tried so many things that I just can't see the wood for the trees! The error I'm seeing is:
Error: template: microservice/templates/configmap.yaml:7:7: executing "microservice/templates/configmap.yaml" at <include "configmap.properties" .>: error calling include: template: microservice/templates/_helpers.tpl:56:76: executing "configmap.properties" at <4>: wrong type for value; expected string; got map[string]interface {}
EDIT:
After tweaking, I'm still getting an error, but I'm seeing something in the configmap.. but I wonder if the error is due to the 8 spaces on the first line..
data:
app.properties: |-
app2:
bootstrap_port: something
bootstrap_server: something
registry_schema: something
app1:
baseUri: something
key: something
secret: something
spring:
datasource:
password: something
url: something
username: something
I think your actual error message is around the way you're using the .Values.environment.production.properties value. It's a YAML map, but the indent function expects it to be a string. You should be able to see some odd indentation and maybe an odd [map spring [map datasource ...]] string if you use the helm template --debug option.
When you go to render the ConfigMap, you need to make sure to do two things. Since the data you have is structured properties, you need to use the lightly-documented toYaml function to convert it back to YAML. This will begin at the first column, so you need to apply the indent function to it, and then you need to make sure the markup that invokes it is also at the first column (indent should be the only thing that supplies indentation).
data:
app.properties: |-
{{ include "configmap.properties" . | indent 4}}
{{/*- starts at column 1, but includes the `indent` function */}}
{{ define "configmap.properties" }}
{{- index .Values.environment (.Values.env) "properties" | toYaml }}
{{/*- starts at first column, includes `toYaml`, does not include `indent` */}}
{{- end }}

Helm template not able to read ip address - can't evaluate field ipAddress in type string

I am trying to create a helm template for Istio's ServiceEntry which has a list of addresses for static ip addresses. In values.yaml, I have
- name: test-se
namespace: test-se-ns
egressUrls:
- mydbhost.com
port: 32306
protocol: TCP
ipAddress: 10.2.2.2
In the .tpl file I am trying to add the value of ipAddress to a list
{{- with .ipAddress }}
addresses:
- {{ .ipAddress | quote }}
{{- end }}
Always fails with exception
templates/_service_entry.tpl:18:13: executing "common.serviceentry.tpl" at <.ipAddress>: can't evaluate field ipAddress in type string
Any idea what I am doing wrong?
If you use with you make the thing that you have used as with the context inside that block.
So, use the dot to refer to it.
{{- with .ipAddress }}
addresses:
- {{ . | quote }}
{{- end }}
From the docs:
{{with pipeline}} T1 {{end}}
If the value of the pipeline is empty, no output is generated;
otherwise, dot is set to the value of the pipeline and T1 is
executed.
In this case, an if seems also fitting, since you do not much with the new context.
{{- if .ipAddress }}
addresses:
- {{ .ipAddress | quote }}
{{- end }}
when you use with in Helm, you change the scope of the ., so Helm looks for an object and not a string, you can read more about it in the docs.
but anyway, I think that in your case, you need to use range instead of with, you can see an example here

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

Is it possile to create yaml object from helm from file

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}}