I am using Helm
v3 and trying to iterate over a complex object/map in a YAML definition file for Kubernetes network policy with the following content:
values.yaml:
networkPolicies:
egress:
- service: microservice-name
destination:
- podLabels:
app=microservice-name
namespaceLabels:
company.com/microservices: microservice-name
protocol: TCP
ports:
- 8444
At the k8s definition file, I have this code:
egress-networkpolicy.yaml:
{{- range $v, $rule := .Values.networkPolicies.egress }}---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-kong-to-{{ $rule.service }}-egress
namespace: kong
annotations:
description: Kong egress policies
spec:
podSelector:
matchLabels:
{{- range $label,$value := $rule.podSelector }}
{{ $label }}: {{ $value }}
{{- end }}
egress:
- to:
{{- range $from := $rule.to }}
- podSelector:
matchLabels:
{{- range $label,$value := $from.podLabels }}
{{ $label }}: {{ $value }}
{{- end }}
{{- if has $from "namespaceLabels" }}
namespaceSelector:
{{- if eq ( len $from.namespaceLabels ) 0 }} {}
{{- else }}
matchLabels:
{{- range $label,$value := $from.namespaceLabels }}
{{ $label }}: {{ $value }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
{{- if has $rule "ports" }}
ports:
{{- range $port := $rule.service.ports }}
- protocol: {{ $port.protocol }}
- port: {{ $port }}
{{- end }}
{{- end }}
policyTypes:
- Egress
{{ end -}}
Unfortunately when I run helm template name-of-the-template
it throws the following error:
❯ helm template name-of-the-template --debug
install.go:178: [debug] Original chart version: ""ate name-of-the-template --debug
install.go:199: [debug] CHART PATH: /Users/user/charts/name-of-the-template
Error: template: name-of-the-template/templates/egress-networkpolicy.yaml:34:13: executing "name-of-the-template/templates/egress-networkpolicy.yaml" at <has $rule "ports">: error calling has: Cannot find has on type string
helm.go:88: [debug] template: name-of-the-template/templates/egress-networkpolicy.yaml:34:13: executing "name-of-the-template/templates/egress-networkpolicy.yaml" at <has $rule "ports">: error calling has: Cannot find has on type string
I can't find the reason for Helm
throwing this error at that line, but not in similar code before that line.
CodePudding user response:
The has
template function checks for membership in a list. In this context $rule
is a mapping or dictionary (it is one of the items in the list under egress
) and for that type you need to use hasKey
instead.
{{- if hasKey $rule "ports" }}{{/* hasKey, not has */}}
ports:
...
{{- end }}
One thing that can simplify this slightly is to use the Go template with
construct instead of if
here. with
acts just like if
, except it also rebinds the special variable .
to the conditional value if it's truthy. Accessing an undefined key in a map is okay but returns nil
, which is falsey. So in this context I might write
{{- with $rule.ports }}
ports:
{{- range . }}
- protocol: {{ $rule.protocol }}
port: {{ . }}
{{- end }}
{{- end }}
(But note as I've written it that the .
in the third and fifth lines are different variables, and that this usage also changes .
as appears at the start of .Values
or in template "name" .
In this little loop that's not going to be a practical problem.)