HELM YAML - arrays values that sometimes requires spaces/tabs but sometimes not? - kubernetes

I am confused when to use spaces and when not to when it comes to arrays and configs.
I think for single value arrays you need to use spaces:
ie:
values:
- "hello"
- "bye"
- "yes"
However this is wrong:
spec:
scaleTargetRef:
name: sb-testing
minReplicaCount: 3
triggers:
- type: azure-servicebus
metadata:
direction: in
When the values are a map, the helm interpreter complains when I add spaces:
error: error parsing deploy.yaml: error converting YAML to JSON: yaml: line 12: did not find expected '-' indicator
Doesn't when I don't:
spec:
scaleTargetRef:
name: sb-testing
minReplicaCount: 3
triggers:
- type: azure-servicebus
metadata:
direction: in
I can't seem to find any rules about this.

An array of objects in YAML can start with or without spaces. Both are valid in YAML syntax.
values:
- "hello"
- "bye"
- "yes"
values:
- "hello"
- "bye"
- "yes"
Make sure that the keys of the same block must be in the same column.
Sample:
spec:
scaleTargetRef:
name: sb-testing
minReplicaCount: 3
triggers:
- type: azure-servicebus
metadata: # "metadata" and "type" in the same column
direction: in
or
spec:
scaleTargetRef:
name: sb-testing
minReplicaCount: 3
triggers:
- type: azure-servicebus
metadata:
direction: in

Related

How to replace some of the values in Helm template definition?

I have a value someField in my values.yaml file that looks like this:
someField:
field1: 1
field2: someValue
field3: someObject
...
I now want to add this to my template, but change some of the fields and add some other fields and maybe remove some of them too.
someField:
field1: 2
field3: someObject
...
field100: someNewValue
I can write to my template all the fields one by one and then do what I want, but there are multiple fields that are available and I would like to avoid listing them all.
I can use toYaml, but it would fully write the original value, and I do not know how to augment it "on the fly"
Extended example:
I have another helm chart installed that is called KEDA, and it defines a CRD:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: {scaled-object-name}
spec:
scaleTargetRef:
apiVersion: {api-version-of-target-resource} # Optional. Default: apps/v1
kind: {kind-of-target-resource} # Optional. Default: Deployment
name: {name-of-target-resource} # Mandatory. Must be in the same namespace as the ScaledObject
envSourceContainerName: {container-name} # Optional. Default: .spec.template.spec.containers[0]
pollingInterval: 30 # Optional. Default: 30 seconds
cooldownPeriod: 300 # Optional. Default: 300 seconds
idleReplicaCount: 0 # Optional. Default: ignored, must be less than minReplicaCount
minReplicaCount: 1 # Optional. Default: 0
maxReplicaCount: 100 # Optional. Default: 100
fallback: # Optional. Section to specify fallback options
failureThreshold: 3 # Mandatory if fallback section is included
replicas: 6 # Mandatory if fallback section is included
advanced: # Optional. Section to specify advanced options
restoreToOriginalReplicaCount: true/false # Optional. Default: false
horizontalPodAutoscalerConfig: # Optional. Section to specify HPA related options
name: {name-of-hpa-resource} # Optional. Default: keda-hpa-{scaled-object-name}
behavior: # Optional. Use to modify HPA's scaling behavior
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
triggers:
- type: service-bus
authenticationRef: name-of-auth
I have my own HelmChart where I want to generate this CRD from a definition, but change some values.
So a user would provide spec, but I would augment it by e.g. adding 'authenticationRef' to every element of the triggers array.

helm multiline file inside range

Im trying to create one secret with multiple file in it.
My value.yaml ( the format of the multiline is not yaml or json)
secretFiles:
- name: helm-template-file
subPath: ".file1"
mode: "0644"
value: |
This is a multiline
value, aka heredoc.
Then my secret file template is secret.yaml:
apiVersion: v1
kind: Secret
metadata:
name: {{ include "helm-template.fullname" . }}-file
namespace: {{ .Release.Namespace }}
labels:
app: {{ include "helm-template.name" . }}
chart: {{ include "helm-template.chart" . }}
type: Opaque
stringData:
{{- range .Values.secretFiles }}
{{ .subPath}}: |
{{ .value | indent 4}}
{{- end }}
The helm install gives error "error converting YAML to JSON: yaml: line 12: did not find expected comment or line break". How can I fix it? Thank you.
values.yaml
secretFiles:
- name: helm-template-file
subPath: ".file1"
mode: "0644"
value: |
This is a multiline
value, aka heredoc.
- name: helm-template-file2
subPath: ".file2"
mode: "0644"
value: |
This is a multiline222
value, aka heredoc.
xxx_tpl.yaml
...
stringData:
{{- range .Values.secretFiles }}
{{ .subPath}}: |
{{- .value | nindent 4}}
{{- end }}
output
...
stringData:
.file1: |
This is a multiline
value, aka heredoc.
.file2: |
This is a multiline222
value, aka heredoc.
ref:
nindent
The nindent function is the same as the indent function, but
prepends a new line to the beginning of the string.
indent
The indent function indents every line in a given string to the specified indent width
When you indent a line, you need to make sure the markup in the line starts at the very first column.
stringData:
{{- range .Values.secretFiles }}
{{ .subPath}}: |
{{ .value | indent 4}}{{/* no space at start of this line */}}
{{- end }}
In the form you have in the original question, the four spaces at the start of the line are copied to the output, then the indent expression adds four more spaces to the start of every line. This results in the first line being indented by eight spaces, and the second line by 4, and that inconsistency results in the YAML parse error you see.
You'd also be able to see this visually if you run helm template --debug over your chart; you'll see the same error but also the template output that can't be parsed.
(#z.x's answer solves the same problem a different way: putting the - inside the curly braces removes both the leading whitespace and also the preceding newline, and then changing indent to nindent puts the newline back.)

Using a defined helper as an iteration for a range

While recently writing a helm chart, I ran into an issue that I couldn't find a solution to.
Basically, I am trying to range off of a defined value (labels), but appear to be running into an issue because the defined value is a string and not a map. I tried to convert it with toYaml to no avail:
{{- range $key, $value := ( include "myChart.selectorLabels" . | toYaml ) }}
- key: {{ $key }}
operator: In
values:
- {{ $value }}
{{- end }}
Example error with toYaml:
COMBINED OUTPUT:
Error: Failed to render chart: exit status 1: Error: template: myApp/templates/deployment.yaml:103:77: executing "myApp/templates/deployment.yaml" at <toYaml>: range can't iterate over |-
app.kubernetes.io/name: myApp
app.kubernetes.io/instance: env-myApp
conf-sha: 0b92fad469486fedb6ad012c1b5f22c
Example error without toYaml (note lack of linebreak before first value):
COMBINED OUTPUT:
Error: Failed to render chart: exit status 1: Error: template: myApp/templates/deployment.yaml:103:73: executing "myApp/templates/deployment.yaml" at <.>: range can't iterate over app.kubernetes.io/name: myApp
app.kubernetes.io/instance: env-myApp
conf-sha: 0b92fad469486fedb6ad012c1b5f22c
Expected render:
- key: app.kubernetes.io/name
operator: In
values:
- myApp
- key: app.kubernetes.io/instance
operator: In
values:
- env-myApp
- key: conf-sha
operator: In
values:
- 0b92fad469486fedb6ad012c1b5f22c
I think there must be a more elegant solution to this in helm's templating that I am missing.
Helm has two extension functions to convert between strings and complex YAML structures. You're calling toYaml which takes an arbitrary object and serializes it to a YAML string. What you actually have is the string result from include which happens to be parseable YAML, and you need the opposite function, fromYaml.
{{- range $key, $value := ( include "myChart.selectorLabels" . | fromYaml ) }}
{{/*- not toYaml ^^^^ */}}
Neither function is especially well-documented. They are specific to Helm. There are corresponding toJson and fromJson that work similarly.

Check if a values.yaml property has any entries in it when you don't know the names?

I have a helm chart template that looks like this:
volumes:
- name: secrets
projected:
sources:
{{- range $secretKey := .Values.secrets }}
- secret:
name: {{ $secretKey | kebabcase }}-secret
{{- end }}
This works perfectly, except for when .Values.secrets has no entries in it. Then it gives this error:
error validating data: ValidationError(Deployment.spec.template.spec.volumes[0].projected): missing required field "sources" in io.k8s.api.core.v1.ProjectedVolumeSource
Basically, it is complaining that sources does not have any values.
But I can't find a way to check to only do this section when .Values.secrets has entries. My values.yaml file is filled automatically and sometimes does not have any values for the secrets.
But because it is filled automatically, I don't know the names of the values in it. As such I cannot just do a test for one of the entries (like most examples do).
How can I check if .Values.secrets has any values?
You only need to add a conditional judgment above, and no object is generated when there is no value.
According to the helm document, when the object is empty, the if statement judges to return false.
A pipeline is evaluated as false if the value is:
a boolean false
a numeric zero
an empty string
a nil (empty or null)
an empty collection (map, slice, tuple, dict, array)
volumes:
{{- if .Values.secrets }}
- name: secrets
projected:
sources:
{{- range $secretKey := .Values.secrets }}
- secret:
name: {{ $secretKey | kebabcase }}-secret
{{- end }}
{{- end }}
case 1:
values.yaml
secrets:
output:
volumes:
case 2:
values.yaml
secrets:
- "aaa"
- "bbb"
output:
volumes:
- name: secrets
projected:
sources:
- secret:
name: aaa-secret
- secret:
name: bbb-secret

How to read env property file in the config map

I have a property file in chart/properties folder. For example chart/properties/dev is the file
and the contents of it looks like the below
var1=somevalue1
var2=somevalue2
var3=somepwd=
var4=http://someurl.company.com
some of the value strings in property file have an =. There are also some empty lines in the property file.
and chart/configmap.yaml looks like below
apiVersion: v1
kind: ConfigMap
metadata:
name: env-configmap
namespace: {{ .Release.Namespace }}
data:
{{ range .Files.Lines "properties"/.Values.env.required.environment }}
{{ . | replace "=" ": " }}
{{ end }}
Generated yaml file:
---
# Source: app/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: env-configmap
namespace: default
data:
var1: somevalue1
var2: somevalue2
var3: somepwd:
var4: http://someurl.company.com
The generated output property entries are missing double quote in the value, as a result deployment complains of it when the value strings contain special characters.
I'm expecting the configmap.yaml data block to be a proper yaml (Indent 2) like file with the above changes. With above changes, there are extra lines after each property entry in yaml file. I got this to work partially when there are no blank lines and no value strings with =. Need help to get this working correctly.
Expected yaml file:
---
# Source: app/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: env-configmap
namespace: default
data:
var1: "somevalue1"
var2: "somevalue2"
var3: "somepwd="
var4: "http://someurl.company.com"
You can follow go template syntax to do that. I update config.yaml like following works
apiVersion: v1
kind: ConfigMap
metadata:
name: env-configmap
namespace: {{ .Release.Namespace }}
data:
{{ range .Files.Lines "properties"/.Values.env.required.environment }}
{{- if ne . "" -}}
{{- $parts := splitn "=" 2 . -}} # details about split function http://masterminds.github.io/sprig/string_slice.html
{{ $parts._0 }}: {{ $parts._1 | quote }}
{{end}}
{{ end }}
I could not comment on your question because of my reputation. If it is possible for your case, you can use the config map as a file. I think Reading the property file in your code is easier.
https://kubernetes.io/docs/concepts/configuration/configmap/#using-configmaps-as-files-from-a-pod