how to pass conditional argument as command in kubernetes with helm charts - kubernetes

I have to run a command when my pod start in kubernetes which takes some argument but those argument are conditional. How to set those values. My configuration looks like
#file: values.yaml
arguments:
debug: false
values: 16 # this is not necessarily set
#deployment command section looks like
command: [ "/bin/bash", "-ce", "./my_app.sh" ]
args:
- {{ -f .Values.arguments.debug }}
- {{ -v .Values.arguments.values}}
But it seems to not accepting argument. Is this incorrect way. How can I pass multiple argument?

Helm uses the Go text/template language with a number of extensions; the Helm Chart Template Guide has quite a few examples.
In particular the templating language includes an if...else...end construct. You can use this like:
args:
- -f
- {{ quote .Values.arguments.debug }}
{{- if .Values.arguments.values }}
- -v
- {{ quote .Values.arguments.values}}
{{- end }}
Note that the -f and -v text are outside the template curly braces, and I've split them out into separate items in the argument list. In the last part there's a test if the values option is set, and the -v option isn't emitted if it's not.

Related

in Helm 3 how to get the entire mapped yaml from values file?

I am trying to get the following "Match" values from the values.yaml file
PublicVirtualService:
match:
- uri:
prefix: "/api/webhook/"
- method:
exact: POST
and this is the helm template file I am trying with
http:
{{- if hasKey .Values.PublicVirtualService "match" }}
- match:
{{- toJson $.Values.PublicVirtualService.match | indent 2 }}
{{- end }}
so the final rendered output will be going to looks like this
http:
- match:
- uri:
prefix: "/api/hook/"
- method:
exact: POST
But it's looking like this after running the debug
http:
- match: [{"uri":{"prefix":"/api/hook/"}},{"method":{"exact":"POST"}}]
So far I have tried different methods but without any success . Any way to get all the values that's are under the "match" as it is in values yaml file .
Also tried with toYaml
but it's looking like this
http:
- match: "- uri: \n prefix: \"/api/webhook/\"\n- method:\n exact: POST\n"
Your initial output is correct and you don't need to do anything.
One of the interesting design points of YAML is that all valid JSON is supposed to be valid YAML. The same syntactic constructs exists: [...] is an inline way to write a list, {key: value} is an object, you're allowed to quote any string. So your one-line output of toJson is valid YAML, and has the same structure as the input.
If you want it to be in multi-line YAML form, Helm includes a toYaml function that can produce that. Indentation is important and the default output of toYaml is indented starting at the first column, so you'll usually need to combine this with the indent helper. This should work:
http:
{{- with .Values.PublicVirtualService.match }}
- http:
{{ toYaml . | indent 4 }}
{{- end }}
One important difference between this and your original form is that there is not a - before toYaml (or toJson). This consumes all of the whitespace before the markup, which includes the newline, so the child markup is on the same line as the tag. That's fine for the one-line JSON form but doesn't work for multi-line YAML.
I've also used a shorter with...end block here. with acts like if, but binds the special variable . to its condition if it's truthy. $any_map.key is defined but nil if key isn't defined, which is falsey. If ...match is defined (and non-empty) then the with block executes, and then {{ toYaml . }} serializes the condition's value. Note that this use of . conflicts with the default Helm use of constructs like .Values.

helm template output showing values not being resolved

I'm new to helm charts and K8s, so forgive me. I'm working on a project that deploys an application project with several apps as part of it. The previous dev that put the charts together was using a "find-and-replace" technique to fill in values for things like the image repository, tags, etc. This is making our CICD pipeline development tricky and not scalable. I'm trying to update the charts to use variables and values.yml files. Most of it seems to be working, values are getting passed down to the templates except for one part and I can't figure out why. Its a large project so I won't copy all the chart files. I'll try to lay out the important parts:
Folder structure:
helm
project1
dev
charts
app1
templates
*template files
Chart.yaml
values.yaml
app2
*same subfolders
app3
*same subfolders
Chart.yml
values.yml
Base Values.yml
artifactory_base_url: company.repo.io/repo_folder
imageversions:
app1_tag: 6.1.2-alpine-edge
app2_tag: 8.1.0.0-edge
app3_tag: 8.1.0.0-alpine-edge
app4_tag: 10.1.1-alpine-edge
initcontainer: latest
App Values.yml file
app:
image:
repository: "{{ .Values.artifactory_base_url }}/pingaccess"
tag: "{{ .Values.pa_tag }}"
deployment.yml template file
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.app.image }}"
I'm running the following helm template command to confirm that I'm getting the proper output for at least the app1 part before actually trying to deploy to the k8s cluster.
helm template app1 --set date="$EPOCHSECONDS" --set namespace='porject_namespace' --values helm/project1/dev/values.yaml helm/project1/dev/charts/app1
Most of the resulting yaml looks great, and it looks like the values I have defined in the base values.yml file are getting passed through in other areas like this example:
initContainers:
- name: appinitcontainer
image: "company.repo.io/repo_folder/initcontainer:latest"
But there is one portion that is populated from the deployment.yml template file that is still showing the curly braces for variables
containers:
- name: app1
image: "map[repository:{{ .Values.image_repo_base_url }}/app1 tag:{{ .Values.app1_tag }}]"
imagePullPolicy: Always
I've tried making variations in all the files mentioned above to remove quotes, use single quotes, etc. In those attempts I usually get a variation of the following errors:
"error converting yaml to json. did not find expected key"
"error mapping values"
I haven't been able to find a solution. I'm assuming that the "helm template" command should not contain any braces like that, all variables and values should be resolved. I'm hoping somebody can provide some tips of things I might be missing.
You're hitting two issues here. First, .Values.app.image is a map containing the two keys repository and tag; that's why you get the weird map[repository:... tag:...] syntax in the output. Second, string values in values.yaml aren't reinterpreted for Helm template syntax; that's why the {{ ... }} markup gets passed through to the output.
This in turn means you need to do two things. To resolve the map, construct the string from the contents of the dictionary; and to resolve the templating markup inside the string values, use Helm's tpl function.
{{- $repository := tpl .Values.app.image.repository . }}
{{- $tag := tpl .Values.app.image.tag . }}
image: "{{ $repository }}:{{ $tag }}"
(You may find it useful to separate "repository", "registry" or "image", and "tag" into three separate parts, since probably all of your images are coming from the same repository; that would let you configure the repository in one place and customize the image name per component. The bitnami/postgresql chart is one example of this setup.)

Update nested array value in yaml with yq

Given a yaml file (helmfile) like the following
releases:
- chart: ../charts/foo
name: foo
namespace: '{{ .Values.stack }}'
values:
- ../config/templates/foo-values.yaml.gotmpl
set:
- name: image.tag
value: 22
- name: replicas
value: 1
- chart: ../charts/bar
name: bar
namespace: '{{ .Values.stack }}'
values:
- ../config/templates/bar-values.yaml.gotmpl
set:
- name: image.bar_proxy.tag
value: 46
- name: image.bar.tag
value: 29
- name: replicas
value: 1
I'm trying to figure out a clean way to update a specific image tag. For example, I'd like to update image.bar_proxy.tag from 46 to 51.
I have the following, which does the job, but it requires that you know the exact index of the array item:
yq -y '.releases[] |= if .name=="bar" then .set[0].value |= 51 else . end' helmfile-example.yaml
So if the array order were to change at some point this would break.
A preferred solution would be: "update image.bar_proxy.tag value from 46 to 51 where set[].name==image.bar_proxy.tag". Any ideas on how to achieve a more specific conditional selection like this?
FYI our yq version:
$ yq --version
yq 2.10.0
You can use the following filter to make it work. It works by dynamically selecting the index of the object where your tag exists. On the selected object .value=51 will update the value as you wanted. You can also use the -i flag to do in-place modification of the original file.
yq -y '.releases[].set |= map(select(.name == "image.bar_proxy.tag").value=51)' yaml
See the underlying jq filter acting on the JSON object at jq-playground
Given the context of using Helmfile, there are a couple of ways you can approach this without necessarily editing the helmfile.yaml. Helmfile allows using the Go text/template language in many places, similarly to the underlying Helm tool, and has some other features that can help.
One of the easiest things you can do is take advantage of values: being a list, and of unknown values generally being ignored. You (or your CI/CD system) can write a separate YAML file that contains just the tags (JSON may be easier to write and is valid YAML)
# tags.yaml
image:
tag: 22
bar: {tag: 29}
bar_proxy: {tag: 46}
and then include this file as an additional file in the helmfile.yaml. (This would be equivalent to using helm install -f with multiple local values files, rather than helm install --set individual values.)
releases:
- name: foo
values:
- ../config/templates/foo-values.yaml.gotmpl
- tags.yaml
# no `set:`
- name: bar
values:
- ../config/templates/bar-values.yaml.gotmpl
- tags.yaml
- replicas: 1
# no `set:`
Helmfile's templating extensions also include env and requiredEnv to read ordinary environment variables from the host system. Helm proper does not have these to try to minimize the number of implicit inputs to a chart, but for Helmfile it's a possible way to provide values at deploy time.
releases:
- name: bar
set:
- name: image.bar_proxy.tag
value: {{ env "BAR_PROXY_TAG" | default "46" }}
- name: image.bar.tag
value: {{ requiredEnv "BAR_TAG" }}

How to pass a variable or resolver as an argument to a hook in Sceptre?

I'm trying to use one of the outputs of my CloudFormation template as a parameter to a !cmd hook - e.g.
hooks:
after_create:
- !cmd "echo {{ value of cloudformation output }}"
Is there a way to do this?

Ansible - need to output all the hosts in the playbook into a configuration file

I'll try to make this brief... I'm setting up ansible to write a PostgreSQL pg_hba.conf file, and what I want to do is permit any db server to replicate to any other db server. This way I don't have to reconfigure in the event of a failure. I want ansible to insert lines for each host listed in the group "db". These entries must be CIDR types. So, far I've only succeeded in getting each system to show their own CIDR in the file. I've looked extensively with no joy, but here's what I'm trying to use:
- name: Update the pg_hba.conf file
lineinfile:
path: '{{ pg_data }}/{{ pg_cluster_name }}/pg_hba.conf'
regexp: 'hostssl replication'
insertafter: 'hostssl replication'
line: "hostssl replication rplctn_usr {{ hostvars[ '{{ item }}' ]['ansible_default_ipv4']['address'] }}/32 md5"
with_items: groups['db']
tags:
- "pg_hba.conf"
Nothing I've done gets the {{ item }} variable to expand properly. Anyone?
Firstly, you need to reference the var to iterate through with braces:
with_items: "{{ groups['db'] }}"
Second, item is the var representing the value of each iteration. Inside {{ }} you can reference any vars directly without extra braces:
{{ hostvars[item]['ansible_default_ipv4']['address'] }}