helm templating with toYaml - kubernetes

I have values.yml file that takes in a list of ports with this format and default values:
Ports:
- number: 443
protocol: http
The script that output the list of port to use as my input gives me this format:
port_list=$(./get_ports.sh)
output:
- 80
- 8080
I want the resulting rendered template to be
Ports:
- number: 80
- number: 8080
How would I accomplish this? I tried the following in my template file:
{{- with .Values.Ports }}
Ports:
{{- toYaml . | nindent 8 }}
{{- end }}
using helm template and setting values.Ports=$port_list, it ended up giving me a pipe and an extra dash like below, which I do not know where they come from, how do I accomplish getting to the format I want above based on the input?
Ports:
|-
- number: 80
- number: 8080
As a bonus, I would also like to have a default protocol in my port list when the protocol isn't specified.
Ports:
- number: 80
protocol: http
- number: 8080
protocol: http
Is there a clean way to do this with just templating?

First, you have to know about the YAML syntax about string. You can find it by searching on the internet. For example: see YAML Multiline.
| enables multiline string and - chops the trailing \n from the end of the string.
The reason for appearing |- is the output of the script get_ports.sh (is being treated as a single string). You can test this,
port_list=$(get_ports.sh)
# pass this to the `--set` flag in both of the following ways
# 01: pass the var $port_list
--set ports=$port_list
# 02: directly pass the value of the var $port_list
--set ports="- 80
- 8080"
For both of the tests you have the same output as follows:
ports:
|-
- 80
- 8080
If you put a newline at the end of the output of your script, then you will see the - has disappeared.
--set ports="- 80
- 8080
"
The output is like as following:
ports:
|
- 80
- 8080
Now try in a different way. Change your template to like this one:
{{- if .Values.ports }}
{{- print "ports:" | nindent 2 }}
{{- range $_, $p := .Values.ports }}
- number: {{ $p }}
protocol: http
{{- end }}
{{- end }}
This template expects the value of your ports in the --set flag as a list (not a string). According to my knowledge at the time of writing this answer, to provide a list value in --set flag either of the followings can be used:
--set ports={80\,8080}
--set ports[0]=80,ports[1]=8080
Now the output is same as you want.
$ helm template test . --set ports={80\,8080}
ports:
- number: 80
protocol: http
- number: 8080
protocol: http
So all you need to process the output of get_ports.sh. That's it.
You may need to adjust the indentation in the template

Related

Merging two Dictionaries in Helm

I am using Helm 3. I have two values.yaml files. In common/values.yaml I have defined:
deployment:
ports:
- name: http
protocol: TCP
The common is of the type library. In my-app, which is of the type application, the common is added as a dependency. In my-app/values.yaml I have added:
deployment:
ports:
- containerPort: 8081
I have defined a template _deployment.yaml in common/templates. In this file I am trying to merge these two deployment dictionaries into one by using:
{{- $deployment := merge .Values.common.deployment .Values.deployment -}}
When I am printing {{ $deployment }}, it is giving output:
map[ports:[map[containerPort:8080 name:http protocol:TCP]]]
And if I do:
{{- $deployment := merge .Values.deployment .Values.common.deployment -}}
The output of {{ $deployment }} is:
map[ports:[map[containerPort:8081]]]
Moreover the output of {{ .Values.common.deployment }} is:
map[ports:[map[name:http protocol:TCP]]]
And the output of {{ .Values.deployment }} is:
map[ports:[map[containerPort:8081]]]
What I would like to have after merging is:
deployment:
ports:
- name: http
protocol: TCP
containerPort: 8081
Any advice you could give would be much appreciated.
Looks like the merge operation does not work as expected on lists (it's a common problem, as the merge operation is ambiguous on list: should a list be appended or replaced when merging ?)
Anyway, I would suggest to merge the ports data with:
{{- $ports := merge .Values.deployment.ports[0] .Values.common.deployment.ports[0] -}}
and render the result with:
deployment:
ports:
- {{- toJson $ports }}
HTH

Kong Ingress controller defining multiple HTTPS ports

I am setting up a Kong ingress controller, however, the default ingress controller listening ports are 80/443. I need to add an additional HTTPS port (8080). I can change the default HTTPS port using the servicePort in the values file, however this replaces the default HTTPS port 443 with 8080. Is there a way to add an additional HTTPS port? In the API Gateway we used to be able to define it in the proxy_listen config, however, this doesn't seem to work in the Kong Ingress controller.
You will need customize the chart,
{{- if .tls.enabled }}
- name: kong-{{ .serviceName }}-tls
port: {{ .tls.servicePort }}
targetPort: {{ .tls.overrideServiceTargetPort | default .tls.containerPort }}
appProtocol: https
- name: kong-{{ .serviceName }}-tls-customize
port: {{ .tls.servicePort_custom }}
targetPort: {{ .tls.overrideServiceTargetPort | default .tls.containerPort }}
appProtocol: https
_helpers.tpl#L176
and it will produce something like this
- name: kong-proxy-tls
port: 443
targetPort: 8443
appProtocol: https
- name: kong-proxy-custom-tls
port: 8080
targetPort: 8443
But i see something in the ENV, which seems like some binding so i do not belive it will work
- name: KONG_PORT_MAPS
value: "80:8000, 443:8443"
so seems like multiple change is involve or might be some limitations but this how you can play with chart, download it and customize it.
you can also try proxy_listen that was suppose to working with you before.
proxy_helpers.tpl#L209
{{- if .tls -}}
{{- if .tls.enabled -}}
{{/*
This is a bit of a hack to support always including "ssl" in the parameter
list for TLS listens. It's not possible to set a variable to an object from
.Values and then modify one of the objects values locally, although
https://github.com/helm/helm/issues/4987 indicates it should be. Instead,
this creates a new object and new parameters list built from the original.
*/}}
{{- $listenConfig := dict -}}
{{- $listenConfig := merge $listenConfig .tls -}}
{{- $parameters := append .tls.parameters "ssl" -}}
{{- $_ := set $listenConfig "parameters" $parameters -}}
{{- $_ := set $listenConfig "address" (default "0.0.0.0" .address) -}}
{{- $tlsListen := (include "kong.singleListen" $listenConfig) -}}
{{- $unifiedListen = append $unifiedListen $tlsListen -}}
{{- end -}}
{{- end -}}
listen-values.yaml#L145
listen_helpers.tpl#L238

Not able to render the helm template without quotes

I have used almost all possible ways to render the helm template. But now I am out of ideas and seeking help:
values.yaml:
rollout:
namespace: xyz
project: default
baseDomain: "stage.danger.zone"
clusterDomain: cluster.local
manifest.yaml
apps:
certmanager:
source:
repoURL: 'https://artifactory.intern.example.io/artifactory/helm'
targetRevision: 0.0.6
chart: abc
helm:
releaseName: abc
values:
global:
imagePullSecrets:
- name: artifactory
baseDomain: "{{ .Values.rollout.baseDomain }}"
When I try to render the template using the below command in my main.yaml file that will produce the final result:
values: {{- tpl (toYaml $appValue.values | indent 6) $ }}
Expected result:
baseDomain: stage.danger.zone (without quotes)
What I am getting is:
baseDomain: 'stage.danger.zone'
If I try to remove the double quotes from: baseDomain: "{{ .Values.rollout.baseDomain }}", I get the following error:
[debug] error converting YAML to JSON: yaml: invalid map key: map[interface {}]interface {}{".Values.baseDomain":interface {}(nil)}
Any help or ideas to achieve the same?
This is an expected behaviour by YAML.
One dirty and bad hack would be
values: {{- tpl (toYaml $appValue.values | fromYaml | toYaml | indent 6) $ }}
and then you will not see the single quotes.
However, This is not a problem at all even if you have ' single quotes in your value. You can include this variable for example something like this below:
hosts:
- host: some-gateway.{{ .Values.rollout.baseDomain }}
serviceName: gateway
servicePort: 8080
path: /
Then it will show you your variable value without ' single quotes.
Example rendered output:
hosts:
- host: some-gateway.stage.danger.zone
path: /
serviceName: gateway
servicePort: 8080

Unable to define range of values for ports

My goal is to have multiple ports defined for a service of type LoadBalancer and I do not want to copy paste the same thing over and over again.
I did come to a solution, but sure how I could define the range - I need all values from 50000 to 50999.
In my service, I define the range:
{{- range $service.ports }}
- name: tport
protocol: TCP
port: {{ . }}
{{- end }}
And in my values file:
ports:
- 50000
- 50001
- 50999
How could I define the ports or update the service template to do this?
Put the min and max port as two different values on your values.yaml and use the range on your template like this:
{{- range untilStep (.Values.config.min_port|int) (.Values.config.max_port|int) 1 }}
- port: {{ . }}
targetPort: "tcp-{{ . }}"
protocol: TCP
name: "tcp-{{ . }}"
{{ -end }}

Helm simple for loop

I can not find a way to just iterate over a simple range, 10 -> 20 using helm templating.
{{range 10 until 20 }}
- port: {{ . }}
targetPort: {{ . }}
protocol: TCP
name: brick-{{ . }}
{{end}}
Helm uses the standard Go text/template system for rendering templates, plus (most of) the Sprig extension library, plus a couple more things. In particular, Sprig includes until and untilStep functions to generate lists of numbers, which you can then range over. So you should be able to:
{{- range untilStep 10 20 1 }}
- port: {{ . }}
...
{{- end }}