Problem passing in a variable from a shell script into a deployment yaml - kubernetes

In a shell scrip I want to assigning a variable what to use in a value in a deployment. For the life of me I can not figure out how to get it to work.
My helm deploy script file has the following in order to set the value to use my variable :
--set AuthConfValue=$AUTH_CONF_VALUE
And I have this in the deployment.yaml file in order to use the variable :
- name: KONG_SETTING
value: "{ {{ .Values.AuthConfValue }} }"
If I assign the variable in my shell script like the following :
AUTH_CONF_VALUE="ernie"
It will work and the value in the deployment will show up like so:
value: '{ ernie }'
Now if I try to assign the variable like this:
AUTH_CONF_VALUE="\\\"ernie\\\":\\\"123\\\""
I will then get the error error converting YAML to JSON: yaml: line 118: did not find expected key when the helm deploy runs.
I was hoping that this would give me the following value in the deployment :
value: "{ "ernie":"123" }"
If I hardcode the value into the deployment.yaml with this:
- name: KONG_SETTING
value: "{ \"ernie\": \"123\" }"
and then run the helm deploy it will work and populate the value in the deployment with this -
value: "{ "ernie":"123" }"
Can someone show me if/how I might be able to do this?

The Helm --set option also uses backslash escaping. So in your example, the $AUTH_CONF_VALUE variable in the host shell contains a single backslash before each quote, which is consumed by --set, so .Values.AuthConfValue contains no backslashes at all, and you get invalid YAML.
If you want to keep this as close to the existing form as you can, let's construct a string with no backslashes at all (and hopefully no commas or brackets either, since those also have special meaning to --set)
AUTH_CONF_VALUE='"ernie":"123"'
helm install --set AuthConfValue="$AUTH_CONF_VALUE" .
When Helm expands a template it doesn't know anything about the context where it might be used. In your case, you know
.Values.AuthConfValue is the body of a JSON object
If you surround it in curly braces { ... } then it should be a valid JSON object
You need to turn that into a correctly-escaped YAML string
Helm contains a lightly-documented toJson function that takes an arbitrary object and converts it to JSON; any valid JSON is also valid YAML. So the closest-to-what-you-have approach might look like
- name: KONG_SETTING
value: {{ printf "{%s}" .Values.AuthConfValue | toJson }}
If you're willing to modify your deploy process a little more, you can have less escaping and more certainty. In the sequence above, we have a string that happens to be a JSON object; what if we had an actual object? Imagine settings like
# kong-auth.yaml
authConf:
ernie: "123"
You could provide this file at install time with a helm install -f option. Since valid JSON is valid YAML, again, you could also provide a JSON file here without changing anything.
helm install -f kong-auth.yaml .
Now with this setup .Values.authConf is an object; the only escaping you need to do is standard YAML/JSON escaping (for example quoting "123" so it's a string and not a number). Now we can use toJson twice, once to get the {"ernie":"123"} JSON object string, and a second time to escape that string as a value "{\"ernie\":\"123\"}".
- name: KONG_SETTING
value: {{ .Values.authConf | toJson | toJson }}
Setting this up would require modifying your deployment script, but it would be much safer against quoting and escaping concerns.

Related

Replacing a value as a string with yq

I have the following map of strings and I would like to change the value of "image.tag" key .
I tried the following but it does not work as I expected. The problem here is that image.tag is a string but I am not sure how to express that. Thanks
yq eval --inplace ".spec.chart.values.\"image.tag\": \"$TAG\"" values.yaml
spec:
chart:
values:
image.tag: master
You don't have to use double quotes for reading variables from shell. mikefarah/yq provides a method strenv to load variables (also environment) form the shell.
Also by using single quotes, you can just wrap image.tag under double quotes to let it be treated as a single word.
Use the style method to set quotes for the updated value style="double" reflects the updated tag value to be treated as a string.
newtag="foo" yq e --inplace '.spec.chart.values."image.tag" |= strenv(newtag) | ..style="double"' values.yaml
or if the new tag is defined as a shell variable say TAG
newtag="$TAG" yq e --inplace '.spec.chart.values."image.tag" |= strenv(newtag) | ..style="double"' values.yaml
Note that, if you are using yq version above 4.18.1, the eval action e is the default one and can be skipped altogether.

How can I pass imagePullSecrets, as it is defined in the default template, to helm via set commands

When you run helm create mychart it has imagePullSecrets defined like this:
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }
In default values file it looks like it's passing it a blank array:
imagePullSecrets: []
I already have a bunch of charts built from this default template that have this setting. Previously I didn't need to use imagePullSecrets so I just left it as is, but now I have some cases where I want to set this at deploy time via the cli.
Helm supports arrays now but this doesn't seem to work:
--set "mychart.imagePullSecrets[0].name={reg-creds}"
Returns:
Error: UPGRADE FAILED: error validating "": error validating data: ValidationError(Deployment.spec.template.spec.imagePullSecrets[0].name): invalid type for io.k8s.api.core.v1.LocalObjectReference.name: got "array", expected "string"
Then I tried passing a string:
--set "mychart.imagePullSecrets='- name: reg-creds'"
Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: ValidationError(Deployment.spec.template.spec.imagePullSecrets): invalid type for io.k8s.api.core.v1.PodSpec.imagePullSecrets: got "string", expected "array"
These error messages are infuriating. Is it possible to set this value with --set so I can avoid refactoring all my charts?
The helm install --set syntax is unique and complex. One unusual bit of syntax there is that a value {foo,bar} in curly braces sets the value to an array. In your example, then, --set object.path={value} sets the value to a single-element array; the error you see is that it needs to be a string instead.
That means a simple workaround here is to remove the curly braces on the right-hand side of --set. There is also a --set-string option that forces the value to be interpreted as a string, even if it contains curly braces or commas.
helm install ... --set "mychart.imagePullSecrets[0].name=reg-creds"
# no curly braces around the value ^^^^^^^^^
It might be clearer, and have a more standard syntax, to use a YAML file to provide this value instead.
# image-pull-secrets.yaml
imagePullSecrets:
- name: reg-creds
You can include this in a per-environment values file, or pass it as a standalone values file. In either case you'd use the helm install -f option to supply the file. It's fine to have multiple helm install -f values files.
helm install ... -f image-pull-secrets.yaml

Use regex in helm template

I'm trying to provide a condition inside my helm template to check for a valid (or a rather invalid) hostname using regexMatch function.
Here's my line of code that I'm using:
{{- if regexMatch "(?:[0-9]{1,3}\.){3}[0-9]{1,3}$" .Values.hostname }}
The related part in the values file is a simple one:
hostname: 10.10.10.10
However, I'm hitting a syntax error with no real explanation:
Error: parse error at (api-gateway/templates/ingress.yml:1): invalid syntax
When I've tried to use the example from the docs: https://helm.sh/docs/chart_template_guide/function_list/#regexmatch-mustregexmatch
it obviously worked, so I wonder why my code isn't working.
Turns out that I needed to use a double backslash to make it work:
{{- if regexMatch "(?:[0-9]{1,3}\\.){3}[0-9]{1,3}$" .Values.hostname }}

Unset/remove default value in helm values.yaml

I have a downloaded file through helm inspect called sftp.yaml
I have a parameter in that sftp.yaml file:-
sftp:
allowedMACs: "hmac-sha2-512"
allowedCiphers: aes256-ctr
Now if i install the corresponding helm chart after commenting out the entire line of "allowedMACs" from custom values files i.e. "sftp.yaml", then K8s takes the delta of sftp.yaml and the actual values.yaml and then use values.yaml's "allowedMACs".
However What i want is if "allowedMACs" line is commented in "sftp.yaml" custom values file, then it should not set the env variable at all, or sets it as null.
presently my deployment file's env section looks like
- name: MACs
value: {{ default "" .Values.sftp.allowedMACs | quote }}
You need to either override (with new value) or unset the value, if you only comment out the section you are not doing any of the above and the default value is going to be used.
Basically you are looking to unset a default value. As per banzaicloud example this can be done like so:
helm install stable/chart-name --set sftp.allowedMACs=null
You can also use override value file in a similar way:
sftp:
allowedMACs: null
allowedCiphers: aes256-ctr
This is available in Helm since version 2.6. If you like in-depth information you can review the issue and the subsequent PR that introduced the feature.
yeah I think helm would retrieve values from all values files, so if allowedMACs is in one of those it'll get populated. If this parameter is affected only by sftp.yaml file should it really belong only to it and would i make sense to remove it from main values.yaml?

Helm: Pass a multiline env variable to deployment

I need to pass a private RSA key as ENV var to my deployment file, and I can't do it at the moment.
containers:
env:
- name: MY_PRIVATE_KEY
value: |+
{{ .Values.fpm.dot_env.MY_PRIVATE_KEY}}
I've tried with indent, without indent, using toYaml (there is no error with this but my env var start with |-)...
Any idea?
This is the error I get from that code:
Error: UPGRADE FAILED: YAML parse error on broker-api/templates/deployment.yaml: error converting YAML to JSON: yaml: line 59: could not find expected ':'
If you're trying to embed a multi-line string in a Kubernetes artifact in a Helm chart, the easiest recipe is
Use the YAML | block scalar form to preserve newlines;
Start the Go template {{ ... }} macro at the first column; and
Use the sprig indent function to indent every line of the block, including the first one.
(You frequently will see |- which trims the final newline; for this I can imagine wanting to keep the final newline |+ or just plain |; the difference between these last two is whether extra empty lines at the end are kept or not.)
containers:
env:
- name: MY_PRIVATE_KEY
value: |+
{{ .Values.fpm.dot_env.MY_PRIVATE_KEY | indent 12 }}
(Usually for actual secrets it's considered preferable to store them in Kubernetes Secret objects. Those values are base64 encoded in the Kubernetes API, so when you declare the Secret object in Helm you'd use ... | b64enc instead of this indent recipe.)
Finally I solved my problem b64encoding my key, and b64decoding it from my backend.
Thanks.