Define a variable in Helm template - kubernetes-helm

I need to define a variable based on an if statement and use that variable multiple times.
In order not to repeat the if I tried something like this:
{{ if condition}}
{{ $my_val = "http" }}
{{ else }}
{{ $my_val = "https" }}
{{ end }}
{{ $my_val }}://google.com
However this returns an error:
Error: render error in "templates/deployment.yaml":
template: templates/deployment.yaml:30:28:
executing "templates/deployment.yaml" at
<include (print $.Template.BasePath "/config.yaml") .>: error calling
include: template: templates/config.yaml:175:59:
executing "templates/config.yaml" at <"https">: undefined variable: $my_val
Ideas?

The most direct path to this is to use the ternary function provided by the Sprig library. That would let you write something like
{{ $myVal := ternary "http" "https" condition -}}
{{ $myVal }}://google.com
A simpler, but more indirect path, is to write a template that generates the value, and calls it
{{- define "scheme" -}}
{{- if condition }}http{{ else }}https{{ end }}
{{- end -}}
{{ template "scheme" . }}://google.com
If you need to include this in another variable, Helm provides an include function that acts just like template except that it's an "expression" rather than something that outputs directly.
{{- $url := printf "%s://google.com" (include "scheme" .) -}}

Related

Helm template converting to json

I would like to be able from Helm template file as below to insert template with toJson helm function as explained in the documentation :
value: {{ include "mytpl" . | lower | quote }}
https://helm.sh/docs/howto/charts_tips_and_tricks/#know-your-template-functions
My configuration :
_helper.tpl
{{- define "my_tpl" -}}
key1: value1
key2: value2
{{- end -}}
dep.yaml
template:
metadata:
annotations:
test: >-
{{ include "my_tpl" . | toJson }}
This should return
template:
metadata:
annotations:
test: >-
{"key1":"value1","key2":"value2"}
but it return
template:
metadata:
annotations:
test: >-
"key1:value1\nkey2:value2"
I'm using Helm v3.
Anyone have an idea please ?
A defined template always produces a string; the Helm-specific include function always returns a string.
In your example, you have a string that happens to be valid YAML. Helm has an undocumented fromYaml function that converts the string to object form, and then you can serialize that again with toJson.
{{ include "my_tpl" . | fromYaml | toJson }}
You may find it easier to have the template itself produce the correct JSON serialization. That could look something like
{{- define "my_tpl" -}}
{{- $dict := dict "key1" "value1" "key2" "value2" -}}
{{- toJson $dict -}}
{{- end -}}
{{ include "my_tpl" . }}
where the "key1", "value1", etc. can be any valid template expression (you do not need nested {{ ... }}).

Why helm template function is not resolveing $labels var?

I am defining a PrometheusRule as follow:
prometheusRule:
rules:
- alert: SSLCertExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 10
for: 0m
labels:
severity: warning
annotations:
summary: Blackbox SSL certificate will expire soon (instance {{ $labels.instance }})
description: "SSL certificate expires in 30 days\n VALUE = {{ $value }}\n LABELS = {{ $labels }}"
And the template yml from helm chart:
{{- if .Values.prometheusRule.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: {{ template "prometheus-blackbox-exporter.fullname" . }}
{{- with .Values.prometheusRule.namespace }}
namespace: {{ . }}
{{- end }}
labels:
{{- include "prometheus-blackbox-exporter.labels" . | nindent 4 }}
{{- with .Values.prometheusRule.additionalLabels -}}
{{- toYaml . | nindent 4 -}}
{{- end }}
spec:
{{- with .Values.prometheusRule.rules }}
groups:
- name: {{ template "prometheus-blackbox-exporter.name" $ }}
rules: {{ tpl (toYaml .) $ | nindent 8 }}
{{- end }}
{{- end }}
when I run helm template, tpl func it is not resolving the $labels and $values vars. When I remove annotations then the helm template is not complaining anymore. Where do fail?
error:
Error: template: prometheus-blackbox-exporter/templates/prometheusrule.yaml:18:16: executing "prometheus-blackbox-exporter/templates/prometheusrule.yaml" at <tpl (toYaml .) $>: error calling tpl: error during tpl function execution for "- alert: SSLCertExpiringSoon\n annotations:\n summary: Blackbox SSL certificate will expire soon (instance {{ $labels.instance\n }})\n expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 10\n for: 0m\n labels:\n release: prometheus\n severity: warning\n- alert: SSLCertExpiringSoon\n annotations: null\n expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 3\n for: 0m\n labels:\n severity: critical": parse error at (prometheus-blackbox-exporter/templates/prometheusrule.yaml:3): undefined variable "$labels"
Prometheus's alerting rules also use {{ ... $variable ... }} syntax, similar to Helm but with a different variant on the Go text/template syntax. When you pass this file through tpl, Helm tries to evaluate the embedded {{ ... }} template and evaluate any blocks there. Since $labels and $value aren't local variables defined at the Helm level, you get this error.
If you just want Prometheus to see this file as-is, and you don't need to replace anything at the Helm level (the file doesn't include references to .Values) then you don't need tpl
rules: {{ toYaml . | nindent 8 }}
If you do need tpl, then inside the included file you need to cause {{ to be emitted as a string and not processed as a template. One syntactic approach to it is to create a template block that prints out {{:
description: "VALUE = {{ "{{" }} $value }}"
# ^^^^^^^^^^ a {{ ... }} block that prints "{{"
The working version of syntax is as follow:
{{ `{{` }} $value }}

Helm: overloading global variables on {{ include }} call?

I have a shared metadata block, based on the commons library that I would like to override a name for one specific instance. Is it possible?
metadata:
{{ include "common.metadata" (merge (dict ".Values.fullnameSuffix" "-redirect") .) }} # Doesn't work - How do I add a `-redirect` suffix?
name: {{ include "common.fullname" . }}-redirect # Causes two `name:` attributes
Within common.metadata there is a call to "fullname" as well:
{{ define "common.metadata" -}}
name: {{ template "common.fullname" . }}
namespace: {{ .Release.Namespace }}
{{- end -}}
Is there a way to pass-down a variable override from the first include so that I can override the name:? It's specific only to this chart.
Use set to add a new key/value pair to a dictionary and pass it to slightly modified common.metadata helper function.
values.yaml
fullnameSuffix: redirect
_helpers.tpl
{{- define "common.metadata" -}}
{{- if .suffix }}
name: {{ template "common.fullname" . }}-{{ .suffix }}
{{- else }}
name: {{ template "common.fullname" . }}
{{- end }}
namespace: {{ .Release.Namespace }}
{{- end -}}
manifest.yaml
metadata:
{{- include "common.metadata" (set . "suffix" .Values.fullnameSuffix ) }}
If your fullnameSuffix is empty, name without suffix will be used.

HELM _helpers.tpl : How to check if template block is defined in _helpers.tpl?

I want to check if a template block has been defined in _helpers.tpl.
Sudo Code:
{{- if "sample.color" template is defined }}
color: {{ include "sample.color" . }}
{{- else }}
color: {{ .Values.color }}
{{- end }}
Is there a way to achieve {{- if "sample.color" template is defined }} in helm?

ingress.yaml template returns error in renderring --> nil pointer evaluating interface {}.service

I am installing a helm chart which has a ingress.yaml template.
I get this error:
Error: render error in "chartmuseum/templates/ingress.yaml": template: chartmuseum/templates/ingress.yaml:35:22: executing "chartmuseum/templates/ingress.yaml" at <.Values.service.servicename>: nil pointer evaluating interface {}.service
I am not able to find where the problem is. The same set of if else structure works abolutely fine in the service.yaml of the same helm chart.
- path: {{ default "/" .path | quote }}
backend:
{{- if .Values.service.servicename }}
serviceName: {{ .Values.service.servicename }}
{{- else }}
serviceName: {{ include "chartmuseum.fullname" . }}
{{- end }}
Getting error on this line --> serviceName: {{ .Values.service.servicename }}
The code that works in service.yaml fine is
metadata:
{{- if .Values.service.servicename }}
name: {{ .Values.service.servicename }}
{{- else }}
name: {{ include "chartmuseum.fullname" . }}
{{- end }}
Expected result: if there is a servcice.servicename in values in values.yaml file , the ingress should pick the value from there for the key serviceName. Else it should include "chartmuseum.fullname".
The same structure works fine for service.yaml.
Below is the url of the original helm chart that i am using.
https://github.com/helm/charts/tree/master/stable/chartmuseum
I just modified the ingress.yaml to add if else block around line 31.
Ingress.yaml https://github.com/helm/charts/blob/master/stable/chartmuseum/templates/ingress.yaml
Values.yaml file is insignificant. I have the below values in it
service:
servicename: helm-charts-test
but even without this value, the if else block is expected to work.
What you're seeing is a weird caveat in Go templating. Your conditional logic is being evaluated inside a range loop. This means . you're using to access Values is not the one you expect it to be, as it's overridden for each range iteration evaluation.
You can use $, which references the global scope in order to access the Values as expected.
For your scenario, it would be something like:
- path: {{ default "/" .path | quote }}
backend:
{{- if $.Values.service.servicename }}
serviceName: {{ $.Values.service.servicename }}
{{- else }}
serviceName: {{ include "chartmuseum.fullname" $ }}
{{- end }}
See here for more details.
I followed this answer by #Torrey and replaced
targetPort: {{ .Values.non_existing.port | default 1234 }}
with
targetPort: {{ (.Values.non_existing).port | default 1234 }}
and it worked