在 helm 中迭代 YAML 复杂映射

Iterate over a YAML complex map in helm

我正在使用 Helm v3 并尝试在具有以下内容的 Kubernetes 网络策略的 YAML 定义文件中迭代复杂的 object/map:
values.yaml:

networkPolicies:
  egress:
    - service: microservice-name
      destination:
        - podLabels:
            app=microservice-name
          namespaceLabels:
             company.com/microservices: microservice-name
      protocol: TCP
      ports:
        - 8444

在k8s定义文件中,我有这样的代码:
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 -}}

不幸的是,当我 运行 helm template name-of-the-template 它抛出以下错误:

❯ 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

我找不到 Helm 在该行抛出此错误的原因,但在该行之前的类似代码中找不到。

改为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

{{- if hasKey $rule "ports" }}{{/* hasKey, not has */}}
ports:
  ...
{{- end }}

可以稍微简化这一点的一件事是在这里使用 Go 模板 with 构造而不是 ifwith 的作用与 if 相同,除了它还会将特殊变量 . 重新绑定到条件值(如果它为真)。访问映射中未定义的键是可以的,但是 returns nil,这是错误的。所以在这种情况下我可能会写

{{- with $rule.ports }}
ports:
{{- range . }}
  - protocol: {{ $rule.protocol }}
    port: {{ . }}
{{- end }}
{{- end }}

(但请注意,正如我所写的那样,第三行和第五行中的 . 是不同的变量,并且这种用法也会更改 . ,如出现在 .Valuestemplate "name" . 在这个不会成为实际问题的小循环中。)