Convert helm yaml values to cli executable - yaml

how do I convert this yaml values in a way such that this become executable with helm install command?
hostAliases:
- ip: "12.20.30.40"
hostnames:
- "001.stg.local"
i want to execute from terminal like this
helm install my-app -n my-namespace app/app1 \
--set hostAliases=[]

values.yaml
hostAliases:
- ip: "12.20.30.40"
hostnames:
- "001.stg.local"
- "002.stg.remote"
- ip: "0.0.0.0"
hostnames:
- "003.stg.local"
- "004.stg.remote"
template/configmap.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
data: |-
{{- range $idx, $alias := $.Values.hostAliases }}
ip-{{ $idx }}: {{ $alias.ip }}
{{- range $i, $n := $alias.hostnames }}
host-{{ $idx }}-{{ $i }}: {{ $n }}
{{- end }}
{{- end }}
cmd
helm template --debug test .
output
---
# Source: test/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
data: |-
ip-0: 12.20.30.40
host-0-0: 001.stg.local
host-0-1: 002.stg.remote
ip-1: 0.0.0.0
host-1-0: 003.stg.local
host-1-1: 004.stg.remote
cmd
helm template --debug test . --set "hostAliases[0].ip=1.2.3.4" --set "hostAliases[0].hostnames={001,002}"
output
# Source: test/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
data: |-
ip-0: 1.2.3.4
host-0-0: 001
host-0-1: 002

Related

helm to iterate a list of lists

Given the follow values.yaml
configurations:
endpoints:
- firstEndpoint
- firstPath
- secondPath
- secondEndpoint
- thirdPath
- fourthPath
I need to generate different resources from those values in the following way:
- name: firstEndpoint
paths:
- firstPath
- secondPath
- name: secondEndpoint
paths:
- thirdPath
- fourthPath
I can do this if "endpoints" were to be a map, instead of a list/array, but in this case, I need "endpoints" to be a list of endpoints, and "paths" to be a list of paths for each endpoint.
How could this be achieved?
As David Maze said. Your proposed endpoints: isn't valid.
You may try this:
values.yaml
configurations:
endpoints:
- firstEndpoint:
- firstPath
- secondPath
- secondEndpoint:
- thirdPath
- fourthPath
(Note the : after firstEndpoint and secondEndpoint)
template/cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
test: |-
{{- range $_, $item := .Values.configurations.endpoints }}
{{- range $k, $v := . }}
- name: {{ $k }}
path:
{{- range $_, $path := $v }}
- {{ $path }}
{{- end }}
{{- end }}
{{- end }}
output
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
test: |-
- name: firstEndpoint
path:
- firstPath
- secondPath
- name: secondEndpoint
path:
- thirdPath
- fourthPath

How to set an SpringBoot array property as a kubernetes secret?

I want to use the direct translation from k8s secret-keys to SpringBoot properties.
Therefore I have a helm chart (but similar with plain k8s):
apiVersion: v1
data:
app.entry[0].name: {{.Values.firstEntry.name | b64enc }}
kind: Secret
metadata:
name: my-secret
type: Opaque
With that my intention is that this behaves as if I'd set the spring property file:
app.entry[0].name: "someName"
But when I do this I get an error:
Invalid value: "[app.entry[0].name]": a valid config key must consist of alphanumeric characters, '-', '_' or '.' (e.g. 'key.name', or 'KEY_NAME', or 'key-name', regex used for validation is '[-._a-zA-Z0-9]+'),
So, [0] seems not to be allowed as a key name for the secrets.
Any idea how I can inject an array entry into spring directly from a k8s secret name?
Shooting around wildly I tried these that all failed:
app.entry[0].name: ... -- k8s rejects '['
app.entry__0.name: ... -- k8s ok, but Spring does not recognize this as array (I think)
"app.entry[0].name": ... -- k8s rejects '['
'app.entry[0].name': ... -- k8s rejects '['
You should be able to use environnment variables like described in sprint-boot-env.
app.entry[0].name property will be set using APP_ENTRY_0_NAME environment variable. This could be set in your deployment.
Using secret like:
apiVersion: v1
data:
value: {{.Values.firstEntry.name | b64enc }}
kind: Secret
metadata:
name: my-secret
type: Opaque
and then use it with
env:
- name: APP_ENTRY_0_NAME
valueFrom:
secretKeyRef:
name: my-secret
key: value
What you can do is passing the application.properties file specified within a k8s Secret to your Spring Boot application.
For instance, define your k8s Opaque Secret this way:
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: my-secret
data:
application.properties: "app.entry[0].name={{ .Values.firstEntry.name }}"
Of course you will have more properties that you want to set in your application.properties file, so just see this as an example with the type of entry that you need to specify, as stated in your question. I'm not a Spring Boot specialist, but an idea could be (if possible) to tell the Spring Boot application to look for more than a single application.properties file so that you would only need to pass some of the configuration parameters from the outside in instead of all of the parameters.
When using kubernetes secrets as files in pods, as specified within the official kubernetes documentation, each key in the secret data map becomes a filename under a volume mountpath (See point 4).
Hence, you can just mount the application.properties file defined within your k8s secret into your container in which your Spring Boot application is running. Assuming that you make use of a deployment template in your helm chart, here is a sample deployment.yaml template would do the job (please focus on the part where the volumes and volumeMount are specified):
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "sample.fullname" . }}
labels:
{{- include "sample.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "sample.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "sample.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "sample.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: my-awesome-volume
mountPath: /path/where/springboot/app/expects/application.properties
subPath: application.properties
volumes:
- name: my-awesome-volume
secret:
secretName: my-secret
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
As desired, this gives you a solution with no necessity of changing any of your application code. I hope that this gets you going in the intended way.
You can do saving json file as a secret
Step 1:
Create json file which needs to be stored as secret example : secret-data.json
{
"entry": [
{
"name1": "data1",
"key1": "dataX"
},
{
"name2": "data2",
"key2": "dataY"
}
]
}
Step2 : Create a secret from a file
kubectl create secret generic data-1 --from-file=secret-data.json
Step 3: Attach secret to pod
env:
- name: APP_DATA
valueFrom:
secretKeyRef:
name: data-1
key: secret-data.json
You can verify the same by exec into container and checking env

Helm Chart Error when using functions: " invalid value; expected string"

I defined the following ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: test-application-yaml
data:
application.yaml: |-
testOne: {{ .Values.testOne | nindent 6 }}
testTwo: {{ .Values.testTwo | nindent 6 }}
The values.yaml looks as follows:
test:
replicas: 1
testOne: |
testOne: "test1"
testTwo: "test2"
testTwo: |
testThree: "test3"
testFour: "test4"
When executing helm lint -f $v helm/charts/applications on Azure, the following error message is reported:
[ERROR] ... at <6>: invalid value; expected string
When trying it on my machine via helm template -f .\values.yaml . however, i get the configMap correctly indented:
apiVersion: v1
kind: ConfigMap
metadata:
name: test-application-yaml
data:
application.yaml: |-
testOne:
testOne: "test1"
testTwo: "test2"
testTwo:
testThree: "test3"
testFour: "test4"
What am I missing here?

Helm iterate over string with comma separated values

I'd like to iterate over string which contain comma separated values using range. For example:
DNS_NAMES: example.com, example2.com, example3.com
and then iterate using range over values: example.com, example2.com, example3.com
use split
values.yaml
DNS_NAMES: example.com, example2.com, example3.com
templates/cm.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
config.yaml: |-
args:
{{- range ( split ", " $.Values.DNS_NAMES ) }}
- {{ . }}
{{- end }}
output.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: test
data:
config.yaml: |-
args:
- example.com
- example2.com
- example3.com

Is it possible to use a template inside a template with go template

Using https://golang.org/pkg/text/template/, I sometimes need to use variables in the accessed path (for kubernetes deployments).
I end up writing something like :
{{ if (eq .Values.cluster "aws" }}{{ .Values.redis.aws.masterHost | quote }}{{else}}{{ .Values.redis.gcp.masterHost | quote }}{{end}}
What I'd really like to write is pretty much {{ .Values.redis.{{.Values.cluster}}.masterHost | quote }} , which doesn't compile.
Is there a way to write something similar ? (so having a kind of variable in the accessed path).
You can use _helpers.tpl file to define logic and operate with values.
_helpers.tpl
{{/*
Get redis host based on cluster.
*/}}
{{- define "chart.getRedis" -}}
{{- if eq .Values.cluster "aws" -}}
{{- .Values.redis.aws.masterHost | quote -}}
{{- else -}}
{{- .Values.redis.gcp.masterHost | quote -}}
{{- end -}}
{{- end -}}
values.yaml
cluster: local
redis:
aws:
masterHost: "my-aws-host"
gcp:
masterHost: "my-gcp-host"
And use it in your Deployment (here's a ConfigMap example to keep it shorter)
configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: Configmap
data:
redis: {{ template "chart.getRedis" . }}
Output:
helm install --dry-run --debug mychart
[debug] Created tunnel using local port: '64712'
...
COMPUTED VALUES:
cluster: local
redis:
aws:
masterHost: my-aws-host
gcp:
masterHost: my-gcp-host
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: Configmap
data:
redis: "my-gcp-host"
Set cluster value to aws:
helm install --dry-run --debug mychart --set-string=cluster=aws
[debug] Created tunnel using local port: '64712'
...
COMPUTED VALUES:
cluster: local
redis:
aws:
masterHost: my-aws-host
gcp:
masterHost: my-gcp-host
HOOKS:
MANIFEST:
---
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: Configmap
data:
redis: "my-aws-host"

Resources