Helm: How to avoid recreating secrets on upgrade? - kubernetes

I have something in a secret template like this:
apiVersion: v1
kind: Secret
metadata:
# not relevant
type: Opaque
data:
password: {{ randAlphaNum 32 | b64enc | quote }}
Now, when doing helm upgrade, the secret is recreated, but the pods using this aren't (they also shouldn't, this is OK).
This causes the pods to fail when they are restarted or upgraded as the new password now doesn't match the old one.
Is it possible to skip re-creation of the secret when it exists, like, a {{- if not(exists theSecret) }} and how to do it?

You can use the look up function in HELM to check the if secret exist or not
https://helm.sh/docs/chart_template_guide/functions_and_pipelines/#using-the-lookup-function
Function in helm chart goes like : https://github.com/sankalp-r/helm-charts-examples/blob/1081ab5a5af3a1c7924c826c5a2bed4c19889daf/sample_chart/templates/_helpers.tpl#L67
{{/*
Example for function
*/}}
{{- define "gen.secret" -}}
{{- $secret := lookup "v1" "Secret" .Release.Namespace "test-secret" -}}
{{- if $secret -}}
{{/*
Reusing value of secret if exist
*/}}
password: {{ $secret.data.password }}
{{- else -}}
{{/*
add new data
*/}}
password: {{ randAlphaNum 32 | b64enc | quote }}
{{- end -}}
{{- end -}}
secret creation will be something like
example file : https://github.com/sankalp-r/helm-charts-examples/blob/main/sample_chart/templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: "test-secret"
type: Opaque
data:
{{- ( include "gen.secret" . ) | indent 2 -}}
chart example : https://github.com/sankalp-r/helm-charts-examples
{{- $secret := (lookup "v1" "Secret" .Release.Namespace "test-secret" -}}
apiVersion: v1
kind: Secret
metadata:
name: test-secret
type: Opaque
# 2. If the secret exists, write it back
{{ if $secret -}}
data:
password: {{ $secret.data.password }}
# 3. If it doesn't exist ... create new
{{ else -}}
stringData:
password: {{ randAlphaNum 32 | b64enc | quote }}
{{ end }}

Related

helm or operator with required function

I have to check for mandatory values based on some condition.
My values.yaml is as below
id: 3
test:
id: 2
test1:
id: 1
In my template, I need to check if id is present at .Values.test.test1.id and assign that value. If not fall back to .Values.test.id and at last .Values.id. But id has to be mandatory and I need to use required function.
My template is as below
{{- if .Values.test.test1.id }}
<assign> {{ .Values.test.test1.id }}
{{- else }}
{{- $id := .Values.test.id }}
{{- $id2 := .Values.id }}
<assign> <need to check required with or of $id $id2> </assign>
{{- end }}
I know this can be solved with one elseif in between if and else. But I need to repeat the same logic for many ids.
What is the best way to achieve this?
It seems like a perfect fit for the coalesce function, which
takes a list of values and returns the first non-empty one.
Source: https://helm.sh/docs/chart_template_guide/function_list/#coalesce
You will also need to use the default function to convert the cases when the test or test.test1 dictionaries are not defined.
All this together, gives:
{{- $test := .Values.test | default dict -}}
{{- $test1 := $test.test1 | default dict -}}
{{- $id := required "Please provide an ID" (
coalesce $test1.id $test.id .Values.id
) -}}
id: {{ $id }}
And here are the test cases and results:
Gives:
id: 1
when values.yaml is
id: 3
test:
id: 2
test1:
id: 1
Gives:
id: 2
when values.yaml is
id: 3
test:
id: 2
Gives:
id: 3
when values.yaml is
id: 3
Gives:
Error: execution error at (demo/templates/test.yaml:3:11):
Please provide an ID
when values.yaml is an empty file

Helm upgrade - preserve value of an environment variable when if condition is not met

I am doing helm upgrade --install with the --reuse-values option. I want to conditionally update the value of an environment variable if a certain condition is met and if the condition is not met preserve the already existing value. I've tried to achieve that this way:
env:
- name: RELEASE_DATE
value: "{{ if eq .Values.config.myCondition "testValue" }}{{ date "2006-01-02T15:04:05" .Release.Time }}{{ end }}"
or
env:
- name: RELEASE_DATE
value: "{{ if eq .Values.config.myCondition "testValue" }}{{ date "2006-01-02T15:04:05" .Release.Time }}{{ else }}{{ .Values.someOtherValue }}{{ end }}"
where .Values.someOtherValue is never really existing, or even doing it this way
env:
{{- if eq .Values.config.deployedService "ftmFrontend" }}
- name: RELEASE_DATE
value: "{{ if eq .Values.config.myCondition "testValue" }}{{ date "2006-01-02T15:04:05" .Release.Time }}{{ end }}"
{{- end }}
I was expecting that if I use a --reuse-values option that the values are going to be kept/preserved if the condition is not met, but instead it always deletes it and leaves it empty.
The option does work however, when there is no condition clause and only the value from the chart is referenced. It's only not working if the if statement is used.
How can I use if statement and still preserve the value if the condition is not met?

Is it possible to neatly flatten a list of maps from values.yaml by selecting a key present in each map?

Suppose I have a values.yaml that contains the following arbitrary-length list of maps:
values.yaml
-----------
people:
- name: "alice"
age: 56
- name: "bob"
age: 42
One of the containers in my stack will need access to a list of just the names. (NAMES="alice,bob")
So far, I have come up with the following solution:
templates/_helpers.tpl
----------------------
{{- define "list.listNames" -}}
{{ $listStarted := false }}
{{- range .Values.people }}
{{- if $listStarted }},{{- end }}{{ $listStarted = true }}{{ .name }}
{{- end }}
{{- end }}
templates/configmap.yaml
------------------------
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
NAMES: '{{- include "list.listNames" . }}'
This solution works, but it feels inelegant. Looking through the Helm documentation, it seems like this would be the perfect use case for pluck in combination with join, but I haven't found a way to use .Values.people as an argument to that function.
Is there a cleaner way to do this?
There's a join function.
I've two different solutions to utilize join:
Solution 1
I can't collect the names in a list. Therefore I use a dict and extract the keys later:
{{- define "list.listNames" -}}
{{- $map := dict }}
{{- range .Values.people }}
{{- $_ := set $map .name "" }}
{{- end }}
{{- keys $map | join "," }}
{{- end }}
This solution might change the order. Perhaps sortAlpha could fix this.
Solution 2
Because function must return a map, I need to add a key. Otherwise you can't convert to a dict by fromYaml:
templates/_helpers.tpl
----------------------
{{- define "list.listNames" -}}
items:
{{- range .Values.people }}
- {{ .name }}
{{- end }}
{{- end }}
Then I convert to a dict object by fromYaml and join the list:
templates/configmap.yaml
------------------------
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
{{- $items := include "list.listNames" . | fromYaml }}
NAMES: {{ $items.items | join "," | quote }}

Create entry in helm template only if an entry exists in a map

Assuming this map exists in my values.yaml
something:
somethingElse:
variable1: value1
variable2: value2
variable3: value3
I want to create a helm template for a kubernetes Secret resource (although this is not of primary importance) if and only if say the key - value pair variable2: value2 exists. (I am only actually interest to match the variable2's existence, not what is the value of value2)
I know how to range to include all entries
{{- range $name, $value := .Values.something.somethingElse }}
{{indent 4 $name }}: {{ $value }}
{{- end }}
but in pseudocode, what I want is
if variable2 in .Values.something.somethingElse
variable2: value2
Is this somehow feasible using the helm templating language?
You can do:
{{if (index .Values.something.somethingElse "variable2")}}
Helm contain a flow control and you can create if / else conditional blocks, for your case this example can be helpful.
In your values.yaml
foo:
enabled: true
So, in your template:
{{- if .Values.foo.enabled }}
--- TEMPLATE CODE --
{{- end }}
Ref: https://helm.sh/docs/chart_template_guide/control_structures/

How to get values dynamically based on parameters in Helm Chart

I did Helm Chart helper file as follows:
{{- define "logging.log_path" -}}
{{- if and .Values.log_path (eq .Values.app_type "sales") }}
{{- join "," .Values.log_path.sales }}
{{ else if and .Values.log_path (eq .Values.app_type "inventory") }}
{{- join "," .Values.log_path.inventory }}
{{ else if and .Values.log_path (eq .Values.app_type "order") }}
{{- join "," .Values.log_path.order }}
{{ else if and .Values.log_path (eq .Values.app_type "warehouse") }}
{{- join "," .Values.log_path.warehouse }}
{{ else }}
{{- join "," .Values.log_path.sales }}
{{- end }}
{{- end }}
The problem is whenever it's required to add new app_type, I need to add app_type in that file manually. I think it's difficult to maintain and time consuming either.
Is there anyway that I could do like that .Values.log_path[".Values.app_type"] or any solution similar to that one? Thanks.
Helm includes a dictionary helper get
get $myDict "key1"
{{ define "logging.log_path" }}
{{- $path := get .Values.log_path .Values.app_type | default .Values.log_path.sales -}}
{{- join "," $path -}}
{{ end }}