how to access certain dotted value in helm ConfigMap - kubernetes

i want to access dotted named value with helm to use in ConfigMap
the value is something like that
valuenum:
joji.json: zok
i want to use it in ConfigMap with helm as this
{{ toYaml .Values.valuenum.joji.json }}
it returns syntax error.
could not find a fix for it.

I found the answer myself, when using index we can search for nested variables with quotes.
{{ index .Values.valuenum "joji.json" }}
link for helm doc about index and more

Related

Is it possible to configure a helm chart to dynamically use a value based on another value?

Is there any way to use helm logic to analyze the Kubernetes version, i.e. Capabilities.KubeVersion, then dynamically choose a value from a map of Kubernetes versions to values, something like
kubernetesVersionCompatibility:
1.15:
insertValue: foo
1.18:
insertValue: bar
You can stitch together a couple of different parts to do that.
You've already found the .Capabilities built-in object. You can use that to guard against, for instance, the Deployment version change in Kubernetes 1.16:
{{- if .Capabilities.APIVersions.Has "apps/v1" }}
apiVersion: apps/v1
{{- else }}
apiVersion: apps/v1beta1
{{- end }}
kind: Deployment
I'd prefer this method to checking on the .Capabilities.KubeVersion.Version if you can.
You can easily check for an exact match using the structure you show. The core text/template language includes an index function that can look up an arbitrary key in a dictionary:
{{- $v := index .Values.kubernetesVersionCompatibility .Capabilities.KubeVersion.Version }}
Insert the value {{ $v.insertValue }}
(You may need to force the keys to be strings "1.15":.)
There's not a convenient way to look up the highest version less than or equal to the current version. If, say, a developer's kind cluster runs Kubernetes 1.20, the 1.18 values will most likely work, but that would have to be explicitly listed in the values. A last resort could be hard-coding the values:
{{- if ge (int .Capabilities.KubeVersion.Minor) 18 }}
Insert the value bar
{{- else if ge (int .Capabilities.KubeVersion.Minor) 15 }}
Insert the value foo
{{- else }}
Insert the value ???
{{- end }}

How to use templates inside templates in helm chart?

I want to use template inside template with "." operator in my helm chart.
Suppose this is my values.yaml
component: my-component
my-component-arguments:
heap_opts: "heap-opts"
Now I want to get "heap_opts", but component name is dynamic.
How can I do something like this using template?
{{ .Values."{{.Values.component}}-arguments".heap_opts }}
You can do this using get spring function combined with index and printf from text/template package
{{ get (index .Values (printf "%s-arguments" .Values.component)) "heap_opts" }}

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.

How to use Lookup function in Helm Chart

While deploying a Kubernetes application, I want to check if a particular PodSecurityPolicy exists, and if it does then skip installing it again.
I came across the helm lookup function, which allows us to check the existing K8 resources.
While I understand how to use this function to get all the resources of same kind, how do I use this function to check if a PodSecurityPolicy named "myPodSecurityPolicy" exists.
I tried something like this:
{{- if ne (lookup "v1" "PodSecurityPolicy" "" "") "myPodSecurityPolicy"}}
<do my stuff>
{{- end }}
But it doesn't look like I can compare it this way, seeing an error -
error calling ne: invalid type for comparison
Any inputs? Thanks in advance.
Please check your API version and PSP name. Lookup is returning a map or nil not a string and that's why you are getting that error. The following is working for me. For negative expression, just add not after if.
{{- if (lookup "policy/v1beta1" "PodSecurityPolicy" "" "example") }}
<found: do your stuff>
{{- end }}
HTH

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.