Append release timestamp to helm template name - kubernetes

I'm struggling with finding a way to include the Release.Time builtin as part of a helm name.
If I just include it as:
name: {{ template "myapp.name" . }}-{{ .Release.Time }}
Dry run shows this:
name: myapp-seconds:1534946206 nanos:143228281
It seems like this is a *timestamp.Timestamp object or something because {{ .Release.Time | trimPrefix "seconds:" | trunc 10 }} outputs wrong type for value; expected string; got *timestamp.Timestamp
I can hack the string parsing by doing: {{ .Release.Time | toString | trimPrefix "seconds:" | trunc 10 }}, but it seems like I should be able to call something on the Timestamp object to get the seconds. Is anyone aware of where the docs are for this? I can't find any reference to it at https://godoc.org/github.com/Masterminds/sprig.

To format timestamp, you can use date FORMAT TIME from Sprig doc. And because .Release.Time got removed in Helm 3, you have to use now instead:
{{ now | date "20060102150405" }}
Refer the format options: https://golang.org/pkg/time/#Time.Format
But having timestamp in the name is not good idea because of upgrades.

In my case, by adding the following annotation I was able to achieve this, I am also using helmfile as the wrapper of my helm templates.
annotations:
deploymentTime: {{ now | date "2006-01-02T15:04:05" }}

Related

Kubernetes: Cannot convert int64 to string. Kubernetes fails to interpret integer value in helmchart values.yaml file

I have a values.yaml file in which I have given spring_datasource_hikari_maximum_pool_size: "10"
In deployment yaml I have used this value as
- name: SPRING_DATASOURCE_HIKARI_MAXIMUM-POOL-SIZE
value: {{ .Values.spring_datasource_hikari_maximum_pool_size }}
However, when used inside the deployment.yaml file it fails with the below error.
Deploy failed: The request is invalid: patch: Invalid value: "map[metadata:map[annotations:map[kubectl.kubernetes.io/last-applied-configuration:{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":
{
(helm values etc)
`{"name":"SPRING_DATASOURCE_HIKARI_MAXIMUM-POOL-SIZE","value":10}]` **(this is the incorrect value)**
}
cannot convert int64 to string
What is the correct format of using an integer value from values.yaml file in a deployment.yaml file?
I have also tried multiple combinations with quotes "" but nothing seems to be working.
Any help is appreciated, Thanks in advance.
I was able to resolve this by using double quotes on the value itself in deployment.yaml file
- name: SPRING_DATASOURCE_HIKARI_MAXIMUM-POOL-SIZE
value: "{{ .Values.spring_datasource_hikari_maximum_pool_size }}"
Since this was a production instance I could not check with #David Maze and Vit's solution.
Edit:
Tried with quote option and it worked too.
- name: SPRING_DATASOURCE_HIKARI_MAXIMUMPOOLSIZE
value: {{ quote .Values.spring_datasource_hikari_maximum_pool_size }}
Check solutions from Helm Environment Variables with Booleans and Integers
We can use !!str to convert the output to a string, Alternatively we
can also use a undefined !! and get the same behaviour giving later
developers nice hints of what we intended !!booleanEnv or !!integerEnv
will cast the values to string (or even just !!boolean)
- name: SPRING_DATASOURCE_HIKARI_MAXIMUM-POOL-SIZE
value: !!integerEnv {{ .Values.spring_datasource_hikari_maximum_pool_size }}
- name: FAVORITE_DRINK
value: !!stringEnv {{ .Values.favoriteDrink }}
- name: TAKES_SUGAR
value: !!booleanEnv {{ .Values.takesSugar }}
YAML values have types, and the standard rule is to consider a string of digits like 10 to be a number. In the Kubernetes YAML format, though, the names and values of environment variables have to be strings.
The easiest way to do this is to use the Helm (Sprig) quote function, which will wrap its parameter in double quotes:
- name: SPRING_DATASOURCE_HIKARI_MAXIMUMPOOLSIZE
value: {{ quote .Values.spring_datasource_hikari_maximum_pool_size }}
{{/* ^^^^^ */}}
quote isn't especially intelligent; it's the same as value: "{{ .Values...}}". There's a similar squote that would wrap the value in single quotes.
If you wanted a really robust solution, you could use print to convert an arbitrary value to a string, then the lightly-documented toJson function to convert that to JSON. By design, valid JSON is valid YAML, and "converting a string to JSON" will mean double-quoting it and otherwise escaping it as needed.
value: {{ .Values...pool_size | print | toJson }}

Use variable in HELM template define function

Is it possible to use a variable inside the template define function? I attempted to wrap the variable in brackets but it seems to fail. Example
{{- define {{ .Chart.Name }}.deployment -}}
The names of template functions are always fixed strings. (This is common with almost all programming languages.) Since these names don't appear anywhere in the rendered YAML, it doesn't really matter what they're called. The only place there's a potential conflict is if your chart includes other subcharts as dependencies, or is included as a subchart; in that case all template functions share the same function namespace.
A common convention is to name templates following the current chart name; that is, matching the fixed string in the Chart.yaml file
{{- define "mychart.deployment" -}}
Using the Helm include function you can call templates with a dynamic name, but this is a somewhat unusual use.
values.yaml
global:
key: {}
deployment: appdeployv1
If you were to expand the name of the chart, you would do it like this
_helpers.tpl
{{- define "key.name" -}}
{{- default .Chart.Name .Values.deployment | trunc 63 | trimSuffix "-" -}}
{{- end -}}
That's all I can understand from your question. I hope this helps. You can try exploring docs and check Declaring and using templates with define and template heading for detailed info.

How can we specify custom path to .Files.Get when creating ConfigMap with Helm

I am creating a config map as below
kubectl create configmap testconfigmap --from-file=testkey=/var/opt/testfile.txt
As I am using helm charts, I would like to create the config map using YAML file instead of running kubectl.
I went through Kubernetes - How to define ConfigMap built using a file in a yaml? and we can use .Files.Get to access the files.
But then testfile.txt needs to be a part of helm. I would like to have something like
kind: ConfigMap
metadata:
name: testconfigmap
data:
fromfile: |-
{{ .Files.Get "/var/opt/testfile.txt" | indent 4 }}
It works when "testfile.txt" is under the main helm directory. So, {{ .Files.Get "testfile.txt" | indent 4 }} works but {{ .Files.Get "/var/opt/testfile.txt" | indent 4 }} doesn't. With custom path, the value for the ConfigMap is empty.
Is is possible to place the file at a custom path outside the helm folder, so I can define my path in Values.yaml and read it in my ConfigMap yaml ?
This is a Community Wiki answer so feel free to edit it and add any additional details you consider important.
As mdaniel has already stated in his comment:
Is is possible to place the file at a custom path outside the helm
folder no, because helm considers that a security risk – mdaniel 2
days ago
You can also compare it with this feature request on GitHub where you can find very similar requirement described in short e.g. in this comment:
I have this exact need. My chart publishes a secret read from file at
/keybase. This file is deliberately not in the chart.
I believe files for .Files.Get should not be assumed to be inside the
chart ...
One interesting comment:
lenalebt commented on Dec 23, 2017 I am quite sure .Files.Get not
being able to access the file system arbitrarily is a security
feature, so I don't think the current behaviour is wrong - it just
does not fulfill all use cases.
This issue was created quite long time ago (Dec 19, 2017) but has been recently reopened. There are even some specific proposals on how it could be handled:
titou10titou10 commented on Apr 2 #misberner can you confirm that
using--include-dir =will allow us to use
.Files.Glob().AsConfig(), and so create a ConfigMap with one
entry in the CM per file in?
#misberner misberner commented on Apr 2 Yeah that's the idea. An open
question from my point of view is whether an --include-dir with a
specified introduces an overlay, or shadows everything under
/ from previous args and from the bundle itself. I'm not super
opinionated on that one but would prefer the former.
The most recent comments give some hope that this feature might become available in future releases of helm.
As mdaniel and mario already mentioned, for now this is not possible, as it's considered a security risk.
But actually there is a workaround.
You can use Helm templating to parse your property file and load it into a ConfigMap.
# create the following ConfigMap in your Chart
# this is just a simple prototype
# it requires strict key=value syntax in your property file (no empty strings etc.)
# but it shows the idea - improve the syntax, if needed
apiVersion: v1
kind: ConfigMap
metadata:
name: example
data:
{{- if .Values.example.map }}
{{- range $line := splitList "\n" .Values.example.map }}
{{- $words := splitList "=" $line }}
{{- $key := index $words 0 | trim }}
{{- $value := rest $words | join "=" | trim }}
{{ $key }}: "{{ $value }}"
{{- end }}
{{- end }}
{{- end }}
And after that you may load your properties file into this ConfigMap.
helm install mychart --set-file example.map="/test/my.properties"
Of course it is safe to use ONLY if you fully control the input, i. e. how each and every line of your property file is populated.

Helm Charts - How do I use `default` on undefined object property values?

Using Helm, I was under the impression default would be the fallback if a variable is not defined. However, it doesn't appear Helm can get to values in sub-object hashes:
type: {{ default "NodePort" .Values.fpm.service.type }}
If .Values.fpm.service or service.type is not defined, it should use 9000.
However, attempting to template this throws a nil pointer error:
<.Values.fpm.service.type>: nil pointer evaluating interface {}.type
Is there a way to simply perform this level of variable testing? Or am I subjected to an if/else test?
The intent of this is to optionally define .fpm.service (and [..].type) within your values.yaml file.
(I'm building a Helm Library chart to handle optional definitions by main charts)
According to the official Helm doc (Using Default Function), the syntax is different and you should use it this way:
type: {{ .Values.fpm.service.type | default "NodePort" | quote }}
Doesn't look like there's really a good way to stop Helm from trying to dive into non-existing objects. I moved into a single line if condition, and it worked:
type: {{ if .Values.fpm.service -}} {{ .default "NodePort" .Values.fpm.service.type | quote }} {{- else -}} "NodePort" {{- end }}
This way, I check if fpm.service exists first, before trying .type check. It works, whether .service and .service.type is or is not defined.

How to include default value with tpl function call

I have top level chart and one of the subcharts. In subchart I want to use variables that defined in level chart, and if it is not found - use default value.
I have code like this in one of deployment definitions in my subchart
name: {{tpl .Values.global.my.GlobalValue .}}
where Values.global.my.GlobalValue - is parameter from top level chart.
Problem is when I try to install only subchart - I am failing, I need some defaults.
I tried to puth like below and it is not working
name: {{default defaultName tpl .Values.global.my.GlobalValue .}}
name: {{tpl .Values.global.my.GlobalValue . | defaultName}}
Could you please advise the correct way to do that.
As per Using the default function:
One function frequently used in templates is the default function:
default DEFAULT_VALUE GIVEN_VALUE. This function allows you to specify
a default value inside of the template, in case the value is omitted.
You should use:
name: {{ .Values.global.my.GlobalValue | default "defaultName" | quote }}