Can't evaluate if variable equals a specific number - kubernetes-helm

I want to write a condition that returns true if:
.Values.pdb.enabled == true
and
.Values.replicas != 1
This throws an error I don't understand:
{{- if and (eq .Values.pdb.enabled true) (ne .Values.replicas 1) }}
Error:
... at <ne .Values.replicas "1">: error calling ne: incompatible types for comparison
I also tried wrapping 1 in quotes.
This is the problem: ne .Values.replicas 1
I also tried this but I get the same error for the lt function: lt .Values.replicas 2

Related

Git actions - simple if statement condition

Hi Please note that the if condition gets executed in the below case even though the variable "highPriority" is zero.
- name: Polaris Result
id: polaris_result
run: |
highPriority=$(cat sample.json | jq '.issueSummary.high')
echo "$highPriority"
echo "::set-output name=highPriority::$highPriority"
- name: fail If crosses threshold for high priority issues
if: ${{ steps.polaris_result.outputs.highPriority }} > 0
run: exit 1
note that echo "$highPriority" outputs "0". However the if condition gets executed in this case which should not be
You should surround all the expression with the { } bracet.
please try:
if: ${{ steps.polaris_result.outputs.highPriority > 0 }}
instead of:
if: ${{ steps.polaris_result.outputs.highPriority }} > 0
See expression section in the doc for some context

How to ammend a condition in helm charts

Currently, I am checking if lifecycle hooks are enabled, if yes add some extra delay:
{{- $delay := hasKey .Values "shutdownDelay" | ternary .Values.shutdownDelay 30 }}
{{- $graceperiod := hasKey .Values.service "terminationGracePeriodSeconds" | ternary .Values.service.terminationGracePeriodSeconds 120 }}
{{- $extraDelay := .Values.lifecycleHooks.enabled | ternary $delay 0 }}
terminationGracePeriodSeconds: {{ add $graceperiod $extraDelay }}
I want to cover a use case where the if .Values.lifecycleHooks.postStart and .Values.lifecycleHooks.prestart have some values then it should not add the extra delay in terminationGracePeriodSeconds
The values.yaml looks like
#shutdownDelay: 40
lifecycleHooks:
enabled: true
postStart:
exec:
command:
- echo
- "Run after starting container"
preStop:
exec:
command:
- echo
- "Run before stopping container"
service:
terminationGracePeriodSeconds: 120
So if the poststop hook value is defined like in values.yaml then it should not add any delay to terminationperiod.
The question is not very specific but if you are looking for "if"
condition with "and"/"or", below is an example might be helpfull.
As per your explanation assuming value for poststart/prestart, If the lifecycle.poststart is "false" and lifecycle.prestart is "true" then the terminationgraceperiodseconds wont have extradelay else condition will have an extradelay
{{- if and (eq .Values.lifecycleHooks.postStart "false") (eq .Values.lifecycleHooks.prestart "true")) }}
terminationGracePeriodSeconds: {{ $graceperiod }}
{{- else}}
terminationGracePeriodSeconds: {{ add $graceperiod $extraDelay }}
{{- end }}
conditional or
{{- if or (eq .Values.lifecycleHooks.postStart "false") (eq .Values.lifecycleHooks.prestart "true")) }}
terminationGracePeriodSeconds: {{ add $graceperiod $extraDelay }}
{{- end }}

if condition with AND operator and greater than condition in helm

I am trying to make a default value for CPU if its mentioned(if its not mentioned, i have handled that separately) value in values file is less than 5000m. I am trying this but I don't think I am doing it correctly.
Also, if I make the default value as 5000m and in my values file its mentioned just as 5. Would it be able to compare both?
resources:
requests:
{{- if .Values.resources.requests.cpu }}
cpu: {{ .Values.resources.requests.cpu }}
{{- end }}
{{- if .Values.resources.requests.memory }}
memory: {{ .Values.resources.requests.memory }}
{{- end }}
limits:
{{- if ((( .Values.resources).limits).cpu) }}
cpu: {{ .Values.resources.limits.cpu }}
{{- else }}
{{- $limit_value := .Values.resources.requests.cpu | toString | regexFind "[0-9.]+" }}
{{- $limit_suffix := .Values.resources.requests.cpu | toString | regexFind "[^0-9.]+" }}
cpu: {{ mulf $limit_value 3 }}{{ $limit_suffix }} }}
{{- end }}
{{- if (((.Values.resources).limits).memory) }}
memory: {{ .Values.resources.limits.memory }}
{{- else }}
{{- $limit_val := .Values.resources.requests.memory | toString | regexFind "[0-9.]+" }}
{{- $limit_suff := .Values.resources.requests.memory | toString | regexFind "[^0-9.]+" }}
memory: {{ mulf $limit_val 3 }}{{ $limit_suff }}
{{- end }}
{{- end }}
You have two separate issues here. There's not a built-in way to parse the Kubernetes resource values, so you'll have to do a lot of work to actually provide that default value.
If you just want to provide a default value and not try to check for a minimum, then you can just use the Helm (Sprig) default function:
resources:
requests:
cpu: {{ .Values.resources.requests.cpu | default "5000m" }}
The minimum bound is what leads to some trouble. I don't believe there's a function in Helm to parse 5000m, or to compare that to 5.0. You could try writing it in Helm template syntax, but it can become awkward.
{{/* Convert a resource quantity like "5000m" to a base number like "5".
Call with the quantity string as the parameter, returns the number
as a string. */}}
{{- define "resource-quantity" -}}
{{- if . | hasSuffix "m" -}}
{{- $quantity = . | trimSuffix "m" | float64 -}}
{{- divf $quantity 10000000 -}}
{{- else -}}
{{ . }}
{{- end -}}
{{- end -}}
Note that there are many suffixes besides m and you might want to handle those too, maybe using a dictionary structure. I'm using the Sprig floating-point math functions which should be included in Helm. This template is actual code and you also want to arrange things like tests for it, which Helm does not support well.
Once you have that, gt (greater-than) is a function that takes two parameters. You want to test both "is it present" and also "is it at least this minimum", so you'd have to repeat the value. For a long value like this one thing that can help is to use the standard template with operator, which both acts like an if instruction and also temporarily rebinds the . variable to the value you're testing.
So you could write something like
{{- with .Values.resources.requests.cpu -}}
{{- $quantity := include "resource-quantity" . | float64 }}
{{- if and . (gt $quantity 5.0) }}
cpu: {{ . }}
{{- else }}{{/* if */}}
cpu: 5000m
{{- end }}{{/* if */}}
{{- else }}{{/* with */}}
cpu: 5000m
{{- end }}{{/* with */}}
But with already tests if the value is non-empty, and you can use the maxf function to enforce a minimum value. So (given a complete working tested resource-quantity template function) you could write:
resources:
requests:
{{- with .Values.resources.requests.cpu }}
cpu: {{ include "resource-quantity" . | float64 | maxf 5.0 }}
{{- else }}
cpu: 5.0
{{- end }}
This is how I managed to compare. Below is the example of one of the unit m
{{- if eq $limit_suffix "m" }}
cpu: {{ mulf $limit_value 3 | max 5000 }}{{$limit_suffix}}
{{- else }}
cpu: {{ mulf $limit_value 3 | max 5 }}
{{- end }}

Helm named template explodes with 'unsupported value: encountered a cycle via map[string]interface' if called more than once

I am trying to refactor a Helm chart for a large enterprise application with numerous deployments, services, ingresses etc and am trying to reduce copy-and-paste. Since I've not found any generally accepted DRY design patterns for Helm charts that have enterprise applications in mind, I am simply working from this guide as starting point: https://faun.pub/dry-helm-charts-for-micro-services-db3a1d6ecb80
I would like to define a named template for each high level resource, such as a deployment and call it as needed for each component in the application that I'm deploying. Using a simple ConfigMap as an example, I have come up with the following example that works perfectly as expected if I invoke the named template only once:
{{- define "mergeproblem.configmap" -}}
{{- $ := index . 0 -}}
{{- $name := index . 2 -}}
{{- with index . 1 -}}
{{- $this := dict "Values" (get .Values $name) -}}
{{- $defaultRoot := dict "Values" (omit .Values $name) -}}
{{- $noValues := omit . "Values" -}}
{{- with merge $noValues $this $defaultRoot -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "mergeproblem.fullname" . }}-{{ $name }}
labels:
{{- include "mergeproblem.labels" . | nindent 4 }}
data:
MergeProblemExample: |
Values: {{ .Values | toYaml | nindent 6 }}
Template: {{ .Template | toYaml | nindent 6 }}
Chart: {{ .Chart | toYaml | nindent 6 }}
Release: {{ .Release | toYaml | nindent 6 }}
{{- end -}}
{{- end -}}
{{- end -}}
The idea here is that I can call this named template, giving it the name of the resource I want to create. It will pull the defaults from the top-level .Values but merge in the .Values.$name over the top with a higher precedence so that the template contents can be relatively simple without having to perform individual merges or ternaries on every variable interpolation -- instead the main scoped input will already have the merging done on .Values.
An example of the working output if I make only a single call: https://pastebin.com/ZCJ4LTpV
I am invoking it with the following:
{{- template "mergeproblem.configmap" (list $ . "myfoo") -}}
However if I invoke it more than once like so:
{{- template "mergeproblem.configmap" (list $ . "myfoo") -}}
{{- template "mergeproblem.configmap" (list $ . "yourbar") -}}
I receive the following error from Helm:
$ helm upgrade --install --namespace mergeproblem --debug mergeproblem ./mergeproblem/
history.go:56: [debug] getting history for release mergeproblem
upgrade.go:123: [debug] preparing upgrade for mergeproblem
upgrade.go:131: [debug] performing update for mergeproblem
upgrade.go:303: [debug] creating upgraded release for mergeproblem
Error: UPGRADE FAILED: create: failed to encode release "mergeproblem": json: unsupported value: encountered a cycle via map[string]interface {}
helm.go:81: [debug] json: unsupported value: encountered a cycle via map[string]interface {}
create: failed to encode release "mergeproblem"
helm.sh/helm/v3/pkg/storage/driver.(*Secrets).Create
/private/tmp/helm-20210414-93729-197z3ms/pkg/storage/driver/secrets.go:156
helm.sh/helm/v3/pkg/storage.(*Storage).Create
/private/tmp/helm-20210414-93729-197z3ms/pkg/storage/storage.go:69
helm.sh/helm/v3/pkg/action.(*Upgrade).performUpgrade
/private/tmp/helm-20210414-93729-197z3ms/pkg/action/upgrade.go:304
helm.sh/helm/v3/pkg/action.(*Upgrade).Run
/private/tmp/helm-20210414-93729-197z3ms/pkg/action/upgrade.go:132
main.newUpgradeCmd.func2
/private/tmp/helm-20210414-93729-197z3ms/cmd/helm/upgrade.go:155
github.com/spf13/cobra.(*Command).execute
/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra#v1.1.1/command.go:850
github.com/spf13/cobra.(*Command).ExecuteC
/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra#v1.1.1/command.go:958
github.com/spf13/cobra.(*Command).Execute
/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra#v1.1.1/command.go:895
main.main
/private/tmp/helm-20210414-93729-197z3ms/cmd/helm/helm.go:80
runtime.main
/usr/local/Cellar/go/1.16.3/libexec/src/runtime/proc.go:225
runtime.goexit
/usr/local/Cellar/go/1.16.3/libexec/src/runtime/asm_amd64.s:1371
UPGRADE FAILED
main.newUpgradeCmd.func2
/private/tmp/helm-20210414-93729-197z3ms/cmd/helm/upgrade.go:157
github.com/spf13/cobra.(*Command).execute
/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra#v1.1.1/command.go:850
github.com/spf13/cobra.(*Command).ExecuteC
/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra#v1.1.1/command.go:958
github.com/spf13/cobra.(*Command).Execute
/Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/github.com/spf13/cobra#v1.1.1/command.go:895
main.main
/private/tmp/helm-20210414-93729-197z3ms/cmd/helm/helm.go:80
runtime.main
/usr/local/Cellar/go/1.16.3/libexec/src/runtime/proc.go:225
runtime.goexit
/usr/local/Cellar/go/1.16.3/libexec/src/runtime/asm_amd64.s:1371
My values.yaml looks like this:
########
#
# Component specifics
#
myfoo:
image:
repository: REPOSITORY-FROM-MYFOO-BLOCK
tag: TAG-FROM-MYFOO-BLOCK
autoscaling:
minReplicas: 33
yourbar:
image:
repository: Repository-From-Yourbar-Block
tag: Tag-From-Yourbar-Block
########
#
# Example defaults
#
replicaCount: 1
image:
repository: default-repository-from-top-level-image-block
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "default-tag-from-top-level-image-block"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80

Helm template doesnt work when binded to configmap

I have a file which will be binded to a configmap. Once I put a tpl function in it, it stops working when other lines are included in the file.
I use this helper tpl:
{{- define "call-nested" }}
{{- $dot := index . 0 }}
{{- $subchart := index . 1 | splitList "." }}
{{- $template := index . 2 }}
{{- $values := $dot.Values }}
{{- range $subchart }}
{{- $values = index $values . }}
{{- end }}
{{- include $template (dict "Chart" (dict "Name" (last $subchart)) "Values" $values "Release" $dot.Release "Capabilities" $dot.Capabilities) }}
{{- end }}
testing in some.yaml:
psqlhost: {{include "call-nested" (list . "postgresql" "postgresql.fullname")}}
newlinekey: value
It works well if some.yaml is a standalone file. But once I bind it a configmap, it gives this error:
executing "mytestchart/templates/my-configmap.yaml" at <tpl (.Files.Glob "config/*").AsConfig .>: error calling tpl: Error during tpl function execution for "some.yaml:<br>\"name: {{include \\\"call-nested\\\" (list . \\\"postgresql\\\" \\\"postgresql.fullname\\\")}}\\r\\nnewlinekey:\n value\"\n": parse error in "mytestchart/templates/my-configmap.yaml": template: mytestchart/templates/my-configmap.yam:1: unexpected "\\" in operand
Once I remove the new line it will also work well.
edit: Configmap:
apiVersion: v1
kind: ConfigMap
metadata:
name: somename
data:
{{ tpl (.Files.Glob "config/*").AsConfig .| indent 2 }}
Your template is not rendering correctly. In order to make it work you need to change the following:
Add a .tmpl suffix to the file you'd like to put to your ConfigMap, for example: some.yaml.tmpl.
Set your ConfigMap's data: to: {{- tpl ((.Files.Glob "config/*.tmpl").AsConfig) . | indent 2 }}. Add a indentation to that line also.
Your ConfigMap would than look something like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: somename
data:
{{- tpl ((.Files.Glob "config/*.tmpl").AsConfig) . | indent 2 }}
You can find more info with some examples here.
Please let me know if that helped.