add helm charts

This commit is contained in:
Ybehrooz
2025-11-09 13:22:40 +03:30
parent 282c3e52d0
commit 38e4d749ad
1352 changed files with 190457 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
To verify that aws-efs-csi-driver has started, run:
kubectl get pod -n {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "aws-efs-csi-driver.name" . }},app.kubernetes.io/instance={{ .Release.Name }}"

View File

@@ -0,0 +1,56 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "aws-efs-csi-driver.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "aws-efs-csi-driver.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "aws-efs-csi-driver.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Common labels
*/}}
{{- define "aws-efs-csi-driver.labels" -}}
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
helm.sh/chart: {{ include "aws-efs-csi-driver.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}
{{/*
Create a string out of the map for controller tags flag
*/}}
{{- define "aws-efs-csi-driver.tags" -}}
{{- $tags := list -}}
{{ range $key, $val := . }}
{{- $tags = print $key ":" $val | append $tags -}}
{{- end -}}
{{- join " " $tags -}}
{{- end -}}

View File

@@ -0,0 +1,193 @@
{{- if .Values.controller.create }}
# Controller Service
kind: Deployment
apiVersion: apps/v1
metadata:
name: {{ .Values.controller.name }}
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
{{- with .Values.controller.additionalLabels }}
{{ toYaml . | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.controller.replicaCount }}
selector:
matchLabels:
app: {{ .Values.controller.name }}
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.controller.updateStrategy }}
strategy:
{{ toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
app: {{ .Values.controller.name }}
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.controller.podLabels }}
{{ toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.podAnnotations }}
annotations: {{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- if hasKey .Values.controller "hostNetwork" }}
hostNetwork: {{ .Values.controller.hostNetwork }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets:
{{- range .Values.imagePullSecrets }}
- name: {{ . }}
{{- end }}
{{- end }}
nodeSelector:
kubernetes.io/os: linux
{{- with .Values.controller.nodeSelector }}
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ .Values.controller.serviceAccount.name }}
priorityClassName: {{ .Values.controller.priorityClassName | default "system-cluster-critical" }}
{{- with .Values.controller.tolerations }}
tolerations: {{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.securityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.controller.dnsPolicy }}
dnsPolicy: {{ .Values.controller.dnsPolicy }}
{{- end }}
{{- with .Values.controller.dnsConfig }}
dnsConfig: {{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: efs-plugin
{{- with .Values.controller.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: {{ printf "%s:%s" .Values.image.repository (default (printf "v%s" .Chart.AppVersion) (toString .Values.image.tag)) }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
- --endpoint=$(CSI_ENDPOINT)
- --logtostderr
{{- if .Values.controller.tags }}
- --tags={{ include "aws-efs-csi-driver.tags" .Values.controller.tags }}
{{- end }}
- --v={{ .Values.controller.logLevel }}
- --delete-access-point-root-dir={{ hasKey .Values.controller "deleteAccessPointRootDir" | ternary .Values.controller.deleteAccessPointRootDir false }}
env:
- name: CSI_ENDPOINT
value: unix:///var/lib/csi/sockets/pluginproxy/csi.sock
{{- if .Values.controller.regionalStsEndpoints }}
- name: AWS_STS_REGIONAL_ENDPOINTS
value: regional
{{- end }}
- name: CSI_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
{{- if .Values.useFIPS }}
- name: AWS_USE_FIPS_ENDPOINT
value: "true"
{{- end }}
- name: PORT_RANGE_UPPER_BOUND
value: "{{ .Values.portRangeUpperBound }}"
{{- with .Values.controller.env }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
{{- with .Values.controller.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: healthz
containerPort: {{ .Values.controller.healthPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: healthz
initialDelaySeconds: 10
timeoutSeconds: 3
periodSeconds: 10
failureThreshold: 5
{{- with .Values.controller.resources }}
resources: {{ toYaml . | nindent 12 }}
{{- end }}
- name: csi-provisioner
image: {{ printf "%s:%s" .Values.sidecars.csiProvisioner.image.repository .Values.sidecars.csiProvisioner.image.tag }}
imagePullPolicy: {{ .Values.sidecars.csiProvisioner.image.pullPolicy }}
args:
- --csi-address=$(ADDRESS)
- --v={{ .Values.controller.logLevel }}
- --feature-gates=Topology=true
{{- if .Values.controller.extraCreateMetadata }}
- --extra-create-metadata
{{- end }}
- --leader-election
{{- if hasKey .Values.controller "leaderElectionRenewDeadline" }}
- --leader-election-renew-deadline={{ .Values.controller.leaderElectionRenewDeadline }}
{{- end }}
{{- if hasKey .Values.controller "leaderElectionLeaseDuration" }}
- --leader-election-lease-duration={{ .Values.controller.leaderElectionLeaseDuration }}
{{- end }}
{{- range .Values.sidecars.csiProvisioner.additionalArgs }}
- {{ . }}
{{- end }}
env:
- name: ADDRESS
value: /var/lib/csi/sockets/pluginproxy/csi.sock
volumeMounts:
- name: socket-dir
mountPath: /var/lib/csi/sockets/pluginproxy/
{{- with default .Values.controller.resources .Values.sidecars.csiProvisioner.resources }}
resources: {{ toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.sidecars.csiProvisioner.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
- name: liveness-probe
image: {{ printf "%s:%s" .Values.sidecars.livenessProbe.image.repository .Values.sidecars.livenessProbe.image.tag }}
imagePullPolicy: {{ .Values.sidecars.livenessProbe.image.pullPolicy }}
args:
- --csi-address=/csi/csi.sock
- --health-port={{ .Values.controller.healthPort }}
volumeMounts:
- name: socket-dir
mountPath: /csi
{{- with .Values.controller.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with default .Values.controller.resources .Values.sidecars.livenessProbe.resources }}
resources: {{ toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.sidecars.livenessProbe.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: socket-dir
emptyDir: {}
{{- with .Values.controller.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.controller.affinity }}
affinity: {{- toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.controller.topologySpreadConstraints }}
{{- $tscLabelSelector := dict "labelSelector" ( dict "matchLabels" ( dict "app" "efs-csi-controller" ) ) }}
{{- $constraints := list }}
{{- range .Values.controller.topologySpreadConstraints }}
{{- $constraints = mustAppend $constraints (mergeOverwrite . $tscLabelSelector) }}
{{- end }}
topologySpreadConstraints:
{{- $constraints | toYaml | nindent 8 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,24 @@
{{- if .Values.controller.podDisruptionBudget.enabled -}}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ .Values.controller.name }}
namespace: {{ .Release.Namespace }}
labels:
{{- include "aws-efs-csi-driver.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
app: {{ .Values.controller.name }}
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .Values.controller.podDisruptionBudget.unhealthyPodEvictionPolicy }}
unhealthyPodEvictionPolicy: {{ .Values.controller.podDisruptionBudget.unhealthyPodEvictionPolicy }}
{{- end }}
{{- if .Values.controller.podDisruptionBudget.maxUnavailable }}
maxUnavailable: {{ .Values.controller.podDisruptionBudget.maxUnavailable }}
{{- end }}
{{- if .Values.controller.podDisruptionBudget.minAvailable }}
minAvailable: {{ .Values.controller.podDisruptionBudget.minAvailable }}
{{- end }}
{{- end -}}

View File

@@ -0,0 +1,88 @@
{{- if .Values.controller.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Values.controller.serviceAccount.name }}
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
{{- with .Values.controller.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-csi-external-provisioner-role
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "patch", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["list", "watch", "create", "patch"]
- apiGroups: ["storage.k8s.io"]
resources: ["csinodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "watch", "list", "delete", "update", "create"]
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-csi-external-provisioner-role-describe-secrets
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
rules:
- apiGroups: [ "" ]
resources: [ "secrets" ]
resourceNames: ["x-account"]
verbs: [ "get", "watch", "list" ]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-csi-provisioner-binding
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
subjects:
- kind: ServiceAccount
name: {{ .Values.controller.serviceAccount.name }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: efs-csi-external-provisioner-role
apiGroup: rbac.authorization.k8s.io
---
# We use a RoleBinding to restrict Secret access to the namespace that the
# RoleBinding is created in (typically kube-system)
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-csi-provisioner-binding-describe-secrets
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
subjects:
- kind: ServiceAccount
name: {{ .Values.controller.serviceAccount.name }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: efs-csi-external-provisioner-role-describe-secrets
apiGroup: rbac.authorization.k8s.io

View File

@@ -0,0 +1,12 @@
apiVersion: {{ ternary "storage.k8s.io/v1" "storage.k8s.io/v1beta1" (semverCompare ">=1.18.0-0" .Capabilities.KubeVersion.Version) }}
kind: CSIDriver
metadata:
name: efs.csi.aws.com
annotations:
{{- if .Values.useHelmHooksForCSIDriver }}
"helm.sh/hook": pre-install, pre-upgrade
"helm.sh/hook-delete-policy": before-hook-creation
{{- end }}
"helm.sh/resource-policy": keep
spec:
attachRequired: false

View File

@@ -0,0 +1,202 @@
# Node Service
kind: DaemonSet
apiVersion: apps/v1
metadata:
name: efs-csi-node
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
{{- with .Values.node.additionalLabels }}
{{ toYaml . | nindent 4 }}
{{- end }}
spec:
selector:
matchLabels:
app: efs-csi-node
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.node.updateStrategy }}
updateStrategy:
{{ toYaml . | nindent 4 }}
{{- end }}
template:
metadata:
labels:
app: efs-csi-node
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- with .Values.node.podLabels }}
{{ toYaml . | nindent 8 }}
{{- end }}
{{- if .Values.node.podAnnotations }}
annotations: {{ toYaml .Values.node.podAnnotations | nindent 8 }}
{{- end }}
spec:
{{- with .Values.node.hostAliases }}
hostAliases:
{{- range $k, $v := . }}
- ip: {{ $v.ip }}
hostnames:
- {{ $k }}.efs.{{ $v.region }}.amazonaws.com
{{- end }}
{{- end }}
{{- if .Values.imagePullSecrets }}
imagePullSecrets:
{{- range .Values.imagePullSecrets }}
- name: {{ . }}
{{- end }}
{{- end }}
nodeSelector:
kubernetes.io/os: linux
{{- with .Values.node.nodeSelector }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.node.affinity }}
affinity: {{- toYaml . | nindent 8 }}
{{- end }}
hostNetwork: true
dnsPolicy: {{ .Values.node.dnsPolicy }}
{{- with .Values.node.dnsConfig }}
dnsConfig: {{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ .Values.node.serviceAccount.name }}
priorityClassName: {{ .Values.node.priorityClassName}}
{{- with .Values.node.tolerations }}
tolerations: {{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.node.securityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: efs-plugin
securityContext:
privileged: true
image: {{ printf "%s:%s" .Values.image.repository (default (printf "v%s" .Chart.AppVersion) (toString .Values.image.tag)) }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
args:
- --endpoint=$(CSI_ENDPOINT)
- --logtostderr
- --v={{ .Values.node.logLevel }}
- --vol-metrics-opt-in={{ hasKey .Values.node "volMetricsOptIn" | ternary .Values.node.volMetricsOptIn false }}
- --vol-metrics-refresh-period={{ hasKey .Values.node "volMetricsRefreshPeriod" | ternary .Values.node.volMetricsRefreshPeriod 240 }}
- --vol-metrics-fs-rate-limit={{ hasKey .Values.node "volMetricsFsRateLimit" | ternary .Values.node.volMetricsFsRateLimit 5 }}
env:
- name: CSI_ENDPOINT
value: unix:/csi/csi.sock
- name: CSI_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
{{- if .Values.useFIPS }}
- name: AWS_USE_FIPS_ENDPOINT
value: "true"
{{- end }}
- name: PORT_RANGE_UPPER_BOUND
value: "{{ .Values.portRangeUpperBound }}"
{{- with .Values.node.env }}
{{- toYaml . | nindent 12 }}
{{- end }}
volumeMounts:
- name: kubelet-dir
mountPath: {{ .Values.node.kubeletPath }}
mountPropagation: "Bidirectional"
- name: plugin-dir
mountPath: /csi
- name: efs-state-dir
mountPath: /var/run/efs
- name: efs-utils-config
mountPath: /var/amazon/efs
- name: efs-utils-config-legacy
mountPath: /etc/amazon/efs-legacy
{{- with .Values.node.volumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
ports:
- name: healthz
containerPort: {{ .Values.node.healthPort }}
protocol: TCP
livenessProbe:
httpGet:
path: /healthz
port: healthz
initialDelaySeconds: 10
timeoutSeconds: 3
periodSeconds: 2
failureThreshold: 5
{{- with .Values.node.resources }}
resources: {{ toYaml . | nindent 12 }}
{{- end }}
- name: csi-driver-registrar
image: {{ printf "%s:%s" .Values.sidecars.nodeDriverRegistrar.image.repository .Values.sidecars.nodeDriverRegistrar.image.tag }}
imagePullPolicy: {{ .Values.sidecars.nodeDriverRegistrar.image.pullPolicy }}
args:
- --csi-address=$(ADDRESS)
- --kubelet-registration-path=$(DRIVER_REG_SOCK_PATH)
- --v={{ .Values.node.logLevel }}
env:
- name: ADDRESS
value: /csi/csi.sock
- name: DRIVER_REG_SOCK_PATH
value: {{ printf "%s/plugins/efs.csi.aws.com/csi.sock" (trimSuffix "/" .Values.node.kubeletPath) }}
- name: KUBE_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: registration-dir
mountPath: /registration
{{- with .Values.sidecars.nodeDriverRegistrar.resources }}
resources: {{ toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.sidecars.nodeDriverRegistrar.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
- name: liveness-probe
image: {{ printf "%s:%s" .Values.sidecars.livenessProbe.image.repository .Values.sidecars.livenessProbe.image.tag }}
imagePullPolicy: {{ .Values.sidecars.livenessProbe.image.pullPolicy }}
args:
- --csi-address=/csi/csi.sock
- --health-port={{ .Values.node.healthPort }}
- --v={{ .Values.node.logLevel }}
volumeMounts:
- name: plugin-dir
mountPath: /csi
{{- with .Values.sidecars.livenessProbe.resources }}
resources: {{ toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.sidecars.livenessProbe.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: kubelet-dir
hostPath:
path: {{ .Values.node.kubeletPath }}
type: Directory
- name: plugin-dir
hostPath:
path: {{ printf "%s/plugins/efs.csi.aws.com/" (trimSuffix "/" .Values.node.kubeletPath) }}
type: DirectoryOrCreate
- name: registration-dir
hostPath:
path: {{ printf "%s/plugins_registry/" (trimSuffix "/" .Values.node.kubeletPath) }}
type: Directory
- name: efs-state-dir
hostPath:
path: /var/run/efs
type: DirectoryOrCreate
- name: efs-utils-config
hostPath:
path: /var/amazon/efs
type: DirectoryOrCreate
- name: efs-utils-config-legacy
hostPath:
path: /etc/amazon/efs
type: DirectoryOrCreate
{{- with .Values.node.volumes }}
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@@ -0,0 +1,40 @@
{{- if .Values.node.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ .Values.node.serviceAccount.name }}
namespace: {{ .Release.Namespace }}
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
{{- with .Values.node.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-csi-node-role
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: efs-csi-node-binding
labels:
app.kubernetes.io/name: {{ include "aws-efs-csi-driver.name" . }}
subjects:
- kind: ServiceAccount
name: {{ .Values.node.serviceAccount.name }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: efs-csi-node-role
apiGroup: rbac.authorization.k8s.io

View File

@@ -0,0 +1,26 @@
{{- range .Values.storageClasses }}
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: {{ .name }}
{{- with .annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
provisioner: efs.csi.aws.com
{{- with .mountOptions }}
mountOptions:
{{ toYaml . }}
{{- end }}
{{- with .parameters }}
parameters:
{{ toYaml . | indent 2 }}
{{- end }}
{{- with .reclaimPolicy }}
reclaimPolicy: {{ . }}
{{- end }}
{{- with .volumeBindingMode }}
volumeBindingMode: {{ . }}
{{- end }}
---
{{- end }}