# _configs.tpl
{{/* vim: set filetype=mustache: */}}

{{- define "config-redis.conf" }}
{{- if .Values.redis.customConfig }}
{{ tpl .Values.redis.customConfig . | indent 4 }}
{{- else }}
    dir "/data"
    port {{ .Values.redis.port }}
    {{- range $key, $value := .Values.redis.config }}
    {{ $key }} {{ $value }}
    {{- end }}
{{- if .Values.auth }}
    requirepass replace-default-auth
    masterauth replace-default-auth
{{- end }}
{{- end }}
{{- end }}

{{- define "config-sentinel.conf" }}
{{- if .Values.sentinel.customConfig }}
{{ tpl .Values.sentinel.customConfig . | indent 4 }}
{{- else }}
    dir "/data"
    {{- range $key, $value := .Values.sentinel.config }}
    {{- if eq "maxclients" $key  }}
        {{ $key }} {{ $value }}
    {{- else }}
        sentinel {{ $key }} {{ template "redis-ha.masterGroupName" $ }} {{ $value }}
    {{- end }}
    {{- end }}
{{- if .Values.auth }}
    sentinel auth-pass {{ template "redis-ha.masterGroupName" . }} replace-default-auth
{{- end }}
{{- end }}
{{- end }}

{{- define "config-init.sh" }}
    HOSTNAME="$(hostname)"
    INDEX="${HOSTNAME##*-}"
    MASTER="$(redis-cli -h {{ template "redis-ha.fullname" . }} -p {{ .Values.sentinel.port }} sentinel get-master-addr-by-name {{ template "redis-ha.masterGroupName" . }} | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')"
    MASTER_GROUP="{{ template "redis-ha.masterGroupName" . }}"
    QUORUM="{{ .Values.sentinel.quorum }}"
    REDIS_CONF=/data/conf/redis.conf
    REDIS_PORT={{ .Values.redis.port }}
    SENTINEL_CONF=/data/conf/sentinel.conf
    SENTINEL_PORT={{ .Values.sentinel.port }}
    SERVICE={{ template "redis-ha.fullname" . }}
    set -eu

    sentinel_update() {
        echo "Updating sentinel config with master $MASTER"
        eval MY_SENTINEL_ID="\${SENTINEL_ID_$INDEX}"
        sed -i "1s/^/sentinel myid $MY_SENTINEL_ID\\n/" "$SENTINEL_CONF"
        sed -i "2s/^/sentinel monitor $MASTER_GROUP $1 $REDIS_PORT $QUORUM \\n/" "$SENTINEL_CONF"
        echo "sentinel announce-ip $ANNOUNCE_IP" >> $SENTINEL_CONF
        echo "sentinel announce-port $SENTINEL_PORT" >> $SENTINEL_CONF
    }

    redis_update() {
        echo "Updating redis config"
        echo "slaveof $1 $REDIS_PORT" >> "$REDIS_CONF"
        echo "slave-announce-ip $ANNOUNCE_IP" >> $REDIS_CONF
        echo "slave-announce-port $REDIS_PORT" >> $REDIS_CONF
    }

    copy_config() {
        cp /readonly-config/redis.conf "$REDIS_CONF"
        cp /readonly-config/sentinel.conf "$SENTINEL_CONF"
    }

    setup_defaults() {
        echo "Setting up defaults"
        if [ "$INDEX" = "0" ]; then
            echo "Setting this pod as the default master"
            redis_update "$ANNOUNCE_IP"
            sentinel_update "$ANNOUNCE_IP"
            sed -i "s/^.*slaveof.*//" "$REDIS_CONF"
        else
            DEFAULT_MASTER="$(getent hosts "$SERVICE-announce-0" | awk '{ print $1 }')"
            if [ -z "$DEFAULT_MASTER" ]; then
                echo "Unable to resolve host"
                exit 1
            fi
            echo "Setting default slave config.."
            redis_update "$DEFAULT_MASTER"
            sentinel_update "$DEFAULT_MASTER"
        fi
    }

    find_master() {
        echo "Attempting to find master"
        if [ "$(redis-cli -h "$MASTER"{{ if .Values.auth }} -a "$AUTH"{{ end }} ping)" != "PONG" ]; then
           echo "Can't ping master, attempting to force failover"
           if redis-cli -h "$SERVICE" -p "$SENTINEL_PORT" sentinel failover "$MASTER_GROUP" | grep -q 'NOGOODSLAVE' ; then
               setup_defaults
               return 0
           fi
           sleep 10
           MASTER="$(redis-cli -h $SERVICE -p $SENTINEL_PORT sentinel get-master-addr-by-name $MASTER_GROUP | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')"
           if [ "$MASTER" ]; then
               sentinel_update "$MASTER"
               redis_update "$MASTER"
           else
              echo "Could not failover, exiting..."
              exit 1
           fi
        else
            echo "Found reachable master, updating config"
            sentinel_update "$MASTER"
            redis_update "$MASTER"
        fi
    }

    mkdir -p /data/conf/

    echo "Initializing config.."
    copy_config

    ANNOUNCE_IP=$(getent hosts "$SERVICE-announce-$INDEX" | awk '{ print $1 }')
    if [ -z "$ANNOUNCE_IP" ]; then
        "Could not resolve the announce ip for this pod"
        exit 1
    elif [ "$MASTER" ]; then
        find_master
    else
        setup_defaults
    fi

    if [ "${AUTH:-}" ]; then
        echo "Setting auth values"
        ESCAPED_AUTH=$(echo "$AUTH" | sed -e 's/[\/&]/\\&/g');
        sed -i "s/replace-default-auth/${ESCAPED_AUTH}/" "$REDIS_CONF" "$SENTINEL_CONF"
    fi

    echo "Ready..."
{{- end }}

{{- define "config-haproxy.cfg" }}
{{- if .Values.haproxy.customConfig }}
{{ .Values.haproxy.customConfig | indent 4}}
{{- else }}
    defaults REDIS
      mode tcp
      timeout connect {{ .Values.haproxy.timeout.connect }}
      timeout server {{ .Values.haproxy.timeout.server }}
      timeout client {{ .Values.haproxy.timeout.client }}
      timeout check {{ .Values.haproxy.timeout.check }}

    listen health_check_http_url
      bind :8888
      mode http
      monitor-uri /healthz
      option      dontlognull

    {{- $root := . }}
    {{- $fullName := include "redis-ha.fullname" . }}
    {{- $replicas := int (toString .Values.replicas) }}
    {{- $masterGroupName := include "redis-ha.masterGroupName" . }}
    {{- range $i := until $replicas }}
    # Check Sentinel and whether they are nominated master
    backend check_if_redis_is_master_{{ $i }}
      mode tcp
      option tcp-check
      tcp-check connect
      {{- if $root.auth }}
      tcp-check send AUTH\ {{ $root.redisPassword }}\r\n
      tcp-check expect string +OK
      {{- end }}
      tcp-check send PING\r\n
      tcp-check expect string +PONG
      tcp-check send SENTINEL\ get-master-addr-by-name\ {{ $masterGroupName }}\r\n
      tcp-check expect string REPLACE_ANNOUNCE{{ $i }}
      tcp-check send QUIT\r\n
      tcp-check expect string +OK
      {{- range $i := until $replicas }}
      server R{{ $i }} {{ $fullName }}-announce-{{ $i }}:26379 check inter 1s
      {{- end }}
    {{- end }}

    # decide redis backend to use
    #master
    frontend ft_redis_master
      bind *:{{ $root.Values.redis.port }}
      use_backend bk_redis_master
    {{- if .Values.haproxy.readOnly.enabled }}
    #slave
    frontend ft_redis_slave
      bind *:{{ .Values.haproxy.readOnly.port }}
      use_backend bk_redis_slave
    {{- end }}
    # Check all redis servers to see if they think they are master
    backend bk_redis_master
      {{- if .Values.haproxy.stickyBalancing }}
      balance source
      hash-type consistent
      {{- end }}
      mode tcp
      option tcp-check
      tcp-check connect
      {{- if .Values.auth }}
      tcp-check send AUTH\ REPLACE_AUTH_SECRET\r\n
      tcp-check expect string +OK
      {{- end }}
      tcp-check send PING\r\n
      tcp-check expect string +PONG
      tcp-check send info\ replication\r\n
      tcp-check expect string role:master
      tcp-check send QUIT\r\n
      tcp-check expect string +OK
      {{- range $i := until $replicas }}
      use-server R{{ $i }} if { srv_is_up(R{{ $i }}) } { nbsrv(check_if_redis_is_master_{{ $i }}) ge 2 }
      server R{{ $i }} {{ $fullName }}-announce-{{ $i }}:{{ $root.Values.redis.port }} check inter 1s fall 1 rise 1
      {{- end }}
    {{- if .Values.haproxy.readOnly.enabled }}
    backend bk_redis_slave
      {{- if .Values.haproxy.stickyBalancing }}
      balance source
      hash-type consistent
      {{- end }}
      mode tcp
      option tcp-check
      tcp-check connect
      {{- if .Values.auth }}
      tcp-check send AUTH\ REPLACE_AUTH_SECRET\r\n
      tcp-check expect string +OK
      {{- end }}
      tcp-check send PING\r\n
      tcp-check expect string +PONG
      tcp-check send info\ replication\r\n
      tcp-check expect  string role:slave
      tcp-check send QUIT\r\n
      tcp-check expect string +OK
      {{- range $i := until $replicas }}
      server R{{ $i }} {{ $fullName }}-announce-{{ $i }}:{{ $root.Values.redis.port }} check inter 1s fall 1 rise 1
      {{- end }}
    {{- end }}
    {{- if .Values.haproxy.metrics.enabled }}
    frontend metrics
      mode http
      bind *:{{ .Values.haproxy.metrics.port }}
      option http-use-htx
      http-request use-service prometheus-exporter if { path {{ .Values.haproxy.metrics.scrapePath }} }
    {{- end }}
{{- if .Values.haproxy.extraConfig }}
    # Additional configuration
{{ .Values.haproxy.extraConfig | indent 4 }}
{{- end }}
{{- end }}
{{- end }}


{{- define "config-haproxy_init.sh" }}
    HAPROXY_CONF=/data/haproxy.cfg
    cp /readonly/haproxy.cfg "$HAPROXY_CONF"
    {{- $fullName := include "redis-ha.fullname" . }}
    {{- $replicas := int (toString .Values.replicas) }}
    {{- range $i := until $replicas }}
    for loop in $(seq 1 10); do
      getent hosts {{ $fullName }}-announce-{{ $i }} && break
      echo "Waiting for service {{ $fullName }}-announce-{{ $i }} to be ready ($loop) ..." && sleep 1
    done
    ANNOUNCE_IP{{ $i }}=$(getent hosts "{{ $fullName }}-announce-{{ $i }}" | awk '{ print $1 }')
    if [ -z "$ANNOUNCE_IP{{ $i }}" ]; then
      echo "Could not resolve the announce ip for {{ $fullName }}-announce-{{ $i }}"
      exit 1
    fi
    sed -i "s/REPLACE_ANNOUNCE{{ $i }}/$ANNOUNCE_IP{{ $i }}/" "$HAPROXY_CONF"

    if [ "${AUTH:-}" ]; then
        echo "Setting auth values"
        ESCAPED_AUTH=$(echo "$AUTH" | sed -e 's/[\/&]/\\&/g');
        sed -i "s/REPLACE_AUTH_SECRET/${ESCAPED_AUTH}/" "$HAPROXY_CONF"
    fi
    {{- end }}
{{- end }}
 # _helpers.tpl
{{/* vim: set filetype=mustache: */}}

{{/*
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).
*/}}
{{- define "redis-ha.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).
*/}}
{{- define "redis-ha.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 -}}


{{/*
Return sysctl image
*/}}
{{- define "redis.sysctl.image" -}}
{{- $registryName :=  default "docker.io" .Values.sysctlImage.registry -}}
{{- $tag := default "latest" .Values.sysctlImage.tag | toString -}}
{{- printf "%s/%s:%s" $registryName .Values.sysctlImage.repository $tag -}}
{{- end -}}

{{- /*
Credit: @technosophos
https://github.com/technosophos/common-chart/
labels.standard prints the standard Helm labels.
The standard labels are frequently used in metadata.
*/ -}}
{{- define "labels.standard" -}}
app: {{ template "redis-ha.name" . }}
heritage: {{ .Release.Service | quote }}
release: {{ .Release.Name | quote }}
chart: {{ template "chartref" . }}
{{- end -}}

{{- /*
Credit: @technosophos
https://github.com/technosophos/common-chart/
chartref prints a chart name and version.
It does minimal escaping for use in Kubernetes labels.
Example output:
  zookeeper-1.2.3
  wordpress-3.2.1_20170219
*/ -}}
{{- define "chartref" -}}
  {{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}}
{{- end -}}

{{/*
Create the name of the service account to use
*/}}
{{- define "redis-ha.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
    {{ default (include "redis-ha.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
    {{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}

{{- define "redis-ha.masterGroupName" -}}
{{- $masterGroupName := tpl ( .Values.redis.masterGroupName | default "") . -}}
{{- $validMasterGroupName := regexMatch "^[\\w-\\.]+$" $masterGroupName -}}
{{- if $validMasterGroupName -}}
{{ $masterGroupName }}
{{- else -}}
{{ required "A valid .Values.redis.masterGroupName entry is required (matching ^[\\w-\\.]+$)" ""}}
{{- end -}}
{{- end -}}
 # redis-auth-secret.yaml
{{- if and .Values.auth (not .Values.existingSecret) -}}
apiVersion: v1
kind: Secret
metadata:
  name: {{ template "redis-ha.fullname" . }}
  namespace: {{ .Release.Namespace }}
  labels:
{{ include "labels.standard" . | indent 4 }}
type: Opaque
data:
  {{ .Values.authKey }}: {{ .Values.redisPassword | b64enc | quote }}
{{- end -}}
 # redis-ha-announce-service.yaml
{{- $fullName := include "redis-ha.fullname" . }}
{{- $namespace := .Release.Namespace -}}
{{- $replicas := int (toString .Values.replicas) }}
{{- $root := . }}
{{- range $i := until $replicas }}
---
apiVersion: v1
kind: Service
metadata:
  name: {{ $fullName }}-announce-{{ $i }}
  namespace: {{ $namespace }}
  labels:
{{ include "labels.standard" $root | indent 4 }}
  annotations:
    service.alpha.kubernetes.io/tolerate-unready-endpoints: "true"
  {{- if $root.Values.serviceAnnotations }}
{{ toYaml $root.Values.serviceAnnotations | indent 4 }}
  {{- end }}
spec:
  publishNotReadyAddresses: true
  type: ClusterIP
  ports:
  - name: server
    port: {{ $root.Values.redis.port }}
    protocol: TCP
    targetPort: redis
  - name: sentinel
    port: {{ $root.Values.sentinel.port }}
    protocol: TCP
    targetPort: sentinel
  {{- if $root.Values.exporter.enabled }}
  - name: exporter
    port: {{ $root.Values.exporter.port }}
    protocol: TCP
    targetPort: exporter-port
  {{- end }}
  selector:
    release: {{ $root.Release.Name }}
    app: {{ include "redis-ha.name" $root }}
    "statefulset.kubernetes.io/pod-name": {{ $fullName }}-server-{{ $i }}
{{- end }}
 # redis-ha-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ template "redis-ha.fullname" . }}-configmap
  namespace: {{ .Release.Namespace }}
  labels:
    heritage: {{ .Release.Service }}
    release: {{ .Release.Name }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
    app: {{ template "redis-ha.fullname" . }}
data:
  redis.conf: |
{{- include "config-redis.conf" . }}

  sentinel.conf: |
{{- include "config-sentinel.conf" . }}

  init.sh: |
{{- include "config-init.sh" . }}
{{ if .Values.haproxy.enabled }}
  haproxy.cfg: |-
{{- include "config-haproxy.cfg" . }}
{{- end }}
  haproxy_init.sh: |
{{- include "config-haproxy_init.sh" . }}
 # redis-ha-exporter-script-configmap.yaml
{{- if .Values.exporter.script }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ template "redis-ha.fullname" . }}-exporter-script-configmap
  namespace: {{ .Release.Namespace }}
  labels:
{{ include "labels.standard" . | indent 4 }}
data:
  script: {{ toYaml .Values.exporter.script | indent 2 }}
{{- end }} # redis-ha-pdb.yaml
{{- if .Values.podDisruptionBudget -}}
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: {{ template "redis-ha.fullname" . }}-pdb
  namespace: {{ .Release.Namespace }}
  labels:
{{ include "labels.standard" . | indent 4 }}
spec:
  selector:
    matchLabels:
      release: {{ .Release.Name }}
      app: {{ template "redis-ha.name" . }}
{{ toYaml .Values.podDisruptionBudget | indent 2 }}
{{- end -}}
 # redis-ha-role.yaml
{{- if and .Values.serviceAccount.create  .Values.rbac.create }}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: {{ template "redis-ha.fullname" . }}
  namespace: {{ .Release.Namespace }}
  labels:
    heritage: {{ .Release.Service }}
    release: {{ .Release.Name }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
    app: {{ template "redis-ha.fullname" . }}
rules:
- apiGroups:
    - ""
  resources:
    - endpoints
  verbs:
    - get
{{- end }}
 # redis-ha-rolebinding.yaml
{{- if and .Values.serviceAccount.create .Values.rbac.create }}
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: {{ template "redis-ha.fullname" . }}
  namespace: {{ .Release.Namespace }}
  labels:
    heritage: {{ .Release.Service }}
    release: {{ .Release.Name }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
    app: {{ template "redis-ha.fullname" . }}
subjects:
- kind: ServiceAccount
  name: {{ template "redis-ha.serviceAccountName" . }}
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: {{ template "redis-ha.fullname" . }}
{{- end }}
 # redis-ha-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ template "redis-ha.fullname" . }}
  namespace: {{ .Release.Namespace }}
  labels:
{{ include "labels.standard" . | indent 4 }}
{{- if and ( .Values.exporter.enabled ) ( .Values.exporter.serviceMonitor.enabled ) }}
    servicemonitor: enabled
{{- end }}
  annotations:
  {{- if .Values.serviceAnnotations }}
{{ toYaml .Values.serviceAnnotations | indent 4 }}
  {{- end }}
spec:
  type: ClusterIP
  clusterIP: None
  ports:
  - name: server
    port: {{ .Values.redis.port }}
    protocol: TCP
    targetPort: redis
  - name: sentinel
    port: {{ .Values.sentinel.port }}
    protocol: TCP
    targetPort: sentinel
{{- if .Values.exporter.enabled }}
  - name: exporter-port
    port: {{ .Values.exporter.port }}
    protocol: TCP
    targetPort: exporter-port
{{- end }}
  selector:
    release: {{ .Release.Name }}
    app: {{ template "redis-ha.name" . }} # redis-ha-serviceaccount.yaml
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ template "redis-ha.serviceAccountName" . }}
  namespace: {{ .Release.Namespace }}
  labels:
    heritage: {{ .Release.Service }}
    release: {{ .Release.Name }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
    app: {{ template "redis-ha.fullname" . }}
{{- end }}
 # redis-ha-servicemonitor.yaml
{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) ( .Values.exporter.serviceMonitor.enabled ) ( .Values.exporter.enabled ) }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
{{- if .Values.exporter.serviceMonitor.labels }}
  labels:
{{ toYaml .Values.exporter.serviceMonitor.labels | indent 4}}
{{- end }}
  name: {{ template "redis-ha.fullname" . }}
  namespace: {{ .Release.Namespace }}
{{- if .Values.exporter.serviceMonitor.namespace }}
  namespace: {{ .Values.exporter.serviceMonitor.namespace }}
{{- end }}
spec:
  endpoints:
  - targetPort: {{ .Values.exporter.port }}
{{- if .Values.exporter.serviceMonitor.interval }}
    interval: {{ .Values.exporter.serviceMonitor.interval }}
{{- end }}
{{- if .Values.exporter.serviceMonitor.telemetryPath }}
    path: {{ .Values.exporter.serviceMonitor.telemetryPath }}
{{- end }}
{{- if .Values.exporter.serviceMonitor.timeout }}
    scrapeTimeout: {{ .Values.exporter.serviceMonitor.timeout }}
{{- end }}
  jobLabel: {{ template "redis-ha.fullname" . }}
  namespaceSelector:
    matchNames:
    - {{ .Release.Namespace }}
  selector:
    matchLabels:
      app: {{ template "redis-ha.name" . }}
      release: {{ .Release.Name }}
      servicemonitor: enabled
{{- end }}
 # redis-ha-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ template "redis-ha.fullname" . }}-server
  namespace: {{ .Release.Namespace }}
  labels:
    {{ template "redis-ha.fullname" . }}: replica
{{ include "labels.standard" . | indent 4 }}
spec:
  selector:
    matchLabels:
      release: {{ .Release.Name }}
      app: {{ template "redis-ha.name" . }}
  serviceName: {{ template "redis-ha.fullname" . }}
  replicas: {{ .Values.replicas }}
  podManagementPolicy: OrderedReady
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      annotations:
        checksum/init-config: {{ print (include "config-redis.conf" .) (include "config-init.sh" .) | sha256sum }}
      {{- if .Values.podAnnotations }}
{{ toYaml .Values.podAnnotations | indent 8 }}
      {{- end }}
      {{- if .Values.exporter.enabled }}
        prometheus.io/port: "{{ .Values.exporter.port }}"
        prometheus.io/scrape: "true"
        prometheus.io/path: {{ .Values.exporter.scrapePath }}
      {{- end }}
      labels:
        release: {{ .Release.Name }}
        app: {{ template "redis-ha.name" . }}
        {{ template "redis-ha.fullname" . }}: replica
        {{- range $key, $value := .Values.labels }}
        {{ $key }}: {{ $value }}
        {{- end }}
    spec:
      {{- if .Values.schedulerName }}
      schedulerName: "{{ .Values.schedulerName }}"
      {{- end }}
      {{- if .Values.nodeSelector }}
      nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
      {{- end }}
      {{- if .Values.tolerations }}
      tolerations:
{{ toYaml .Values.tolerations | indent 8 }}
      {{- end }}
      affinity:
    {{- if .Values.affinity }}
    {{- with .Values.affinity }}
{{ tpl . $ | indent 8 }}
    {{- end }}
    {{- else }}
    {{- if .Values.additionalAffinities }}
{{ toYaml .Values.additionalAffinities | indent 8 }}
    {{- end }}
        podAntiAffinity:
    {{- if .Values.hardAntiAffinity }}
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: {{ template "redis-ha.name" . }}
                  release: {{ .Release.Name }}
                  {{ template "redis-ha.fullname" . }}: replica
              topologyKey: kubernetes.io/hostname
    {{- else }}
          preferredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: {{ template "redis-ha.name" . }}
                  release: {{ .Release.Name }}
                  {{ template "redis-ha.fullname" . }}: replica
              topologyKey: kubernetes.io/hostname
    {{- end }}
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app:  {{ template "redis-ha.name" . }}
                    release: {{ .Release.Name }}
                    {{ template "redis-ha.fullname" . }}: replica
                topologyKey: failure-domain.beta.kubernetes.io/zone
    {{- end }}
      {{- if .Values.imagePullSecrets }}
      imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 8 }}
      {{- end }}
      securityContext:
{{ toYaml .Values.securityContext | indent 8 }}
      serviceAccountName: {{ template "redis-ha.serviceAccountName" . }}
      initContainers:
      {{- if .Values.sysctlImage.enabled }}
      - name: init-sysctl
        image: {{ template "redis.sysctl.image" . }}
        imagePullPolicy: {{ .Values.sysctlImage.pullPolicy }}
        resources:
{{ toYaml .Values.sysctlImage.resources | indent 10 }}
        {{- if .Values.sysctlImage.mountHostSys }}
        volumeMounts:
        - name: host-sys
          mountPath: /host-sys
        {{- end }}
        command:
{{ toYaml .Values.sysctlImage.command | indent 10 }}
        securityContext:
          runAsNonRoot: false
          privileged: true
          runAsUser: 0
      {{- end }}
{{- if and .Values.hostPath.path .Values.hostPath.chown }}
      - name: hostpath-chown
        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        securityContext:
          runAsNonRoot: false
          runAsUser: 0
        command:
        - chown
        - "{{ .Values.securityContext.runAsUser }}"
        - /data
        volumeMounts:
        - name: data
          mountPath: /data
{{- end }}
      - name: config-init
        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        resources:
{{ toYaml .Values.init.resources | indent 10 }}
        command:
        - sh
        args:
        - /readonly-config/init.sh
        env:
{{- $replicas := int (toString .Values.replicas) -}}
{{- range $i := until $replicas }}
        - name: SENTINEL_ID_{{ $i }}
          value: {{ printf "%s\n%s\nindex: %d" (include "redis-ha.name" $) ($.Release.Name) $i | sha1sum }}
{{ end -}}
{{- if .Values.auth }}
        - name: AUTH
          valueFrom:
            secretKeyRef:
            {{- if .Values.existingSecret }}
              name: {{ .Values.existingSecret }}
            {{- else }}
              name: {{ template "redis-ha.fullname" . }}
            {{- end }}
              key: {{ .Values.authKey }}
{{- end }}
        volumeMounts:
        - name: config
          mountPath: /readonly-config
          readOnly: true
        - name: data
          mountPath: /data
      containers:
      - name: redis
        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        command:
        - redis-server
        args:
        - /data/conf/redis.conf
        {{- if .Values.auth }}
        env:
        - name: AUTH
          valueFrom:
            secretKeyRef:
            {{- if .Values.existingSecret }}
              name: {{ .Values.existingSecret }}
            {{- else }}
              name: {{ template "redis-ha.fullname" . }}
            {{- end }}
              key: {{ .Values.authKey }}
        {{- end }}
        livenessProbe:
          tcpSocket:
            port: {{ .Values.redis.port }}
          initialDelaySeconds: 15
        resources:
{{ toYaml .Values.redis.resources | indent 10 }}
        ports:
        - name: redis
          containerPort: {{ .Values.redis.port }}
        volumeMounts:
        - mountPath: /data
          name: data
      - name: sentinel
        image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        command:
          - redis-sentinel
        args:
          - /data/conf/sentinel.conf
{{- if .Values.auth }}
        env:
        - name: AUTH
          valueFrom:
            secretKeyRef:
            {{- if .Values.existingSecret }}
              name: {{ .Values.existingSecret }}
            {{- else }}
              name: {{ template "redis-ha.fullname" . }}
            {{- end }}
              key: {{ .Values.authKey }}
{{- end }}
        livenessProbe:
          tcpSocket:
            port: {{ .Values.sentinel.port }}
          initialDelaySeconds: 15
        resources:
{{ toYaml .Values.sentinel.resources | indent 10 }}
        ports:
          - name: sentinel
            containerPort: {{ .Values.sentinel.port }}
        volumeMounts:
        - mountPath: /data
          name: data
{{- if .Values.exporter.enabled }}
      - name: redis-exporter
        image: "{{ .Values.exporter.image }}:{{ .Values.exporter.tag }}"
        imagePullPolicy: {{ .Values.exporter.pullPolicy }}
        args:
        {{- range $key, $value := .Values.exporter.extraArgs }}
          - --{{ $key }}={{ $value }}
        {{- end }}
        env:
          - name: REDIS_ADDR
            value: redis://localhost:{{ .Values.redis.port }}
        {{- if .Values.auth }}
          - name: REDIS_PASSWORD
            valueFrom:
              secretKeyRef:
              {{- if .Values.existingSecret }}
                name: {{ .Values.existingSecret }}
              {{- else }}
                name: {{ template "redis-ha.fullname" . }}
              {{- end }}
                key: {{ .Values.authKey }}
        {{- end }}
        {{- if .Values.exporter.script }}
          - name: REDIS_EXPORTER_SCRIPT
            value: /script/script.lua
        {{- end }}
        livenessProbe:
          httpGet:
            path: {{ .Values.exporter.scrapePath }}
            port: {{ .Values.exporter.port }}
          initialDelaySeconds: 15
          timeoutSeconds: 1
          periodSeconds: 15
        resources:
{{ toYaml .Values.exporter.resources | indent 10 }}
        ports:
          - name: exporter-port
            containerPort: {{ .Values.exporter.port }}
        {{- if .Values.exporter.script }}
        volumeMounts:
          - mountPath: /script
            name: script-mount
        {{- end }}
{{- end }}
{{- if .Values.priorityClassName }}
      priorityClassName: {{ .Values.priorityClassName }}
{{- end }}
      volumes:
      - name: config
        configMap:
          name: {{ template "redis-ha.fullname" . }}-configmap
      {{- if .Values.sysctlImage.mountHostSys }}
      - name: host-sys
        hostPath:
          path: /sys
      {{- end }}
      {{- if .Values.exporter.script }}
      - name: script-mount
        configMap:
          name: {{ template "redis-ha.fullname" . }}-exporter-script-configmap
          items:
            - key: script
              path: script.lua
      {{- end }}
{{- if .Values.persistentVolume.enabled }}
  volumeClaimTemplates:
  - metadata:
      name: data
      annotations:
      {{- range $key, $value := .Values.persistentVolume.annotations }}
        {{ $key }}: {{ $value }}
      {{- end }}
    spec:
      accessModes:
      {{- range .Values.persistentVolume.accessModes }}
        - {{ . | quote }}
      {{- end }}
      resources:
        requests:
          storage: {{ .Values.persistentVolume.size | quote }}
    {{- if .Values.persistentVolume.storageClass }}
    {{- if (eq "-" .Values.persistentVolume.storageClass) }}
      storageClassName: ""
    {{- else }}
      storageClassName: "{{ .Values.persistentVolume.storageClass }}"
    {{- end }}
    {{- end }}
    {{- if .Values.persistentVolume.reclaimPolicy }}
    persistentVolumeReclaimPolicy: "{{ .Values.persistentVolume.reclaimPolicy }}"
    {{- end }}
{{- else if .Values.hostPath.path }}
      - name: data
        hostPath:
          path: {{ tpl .Values.hostPath.path .}}
{{- else }}
      - name: data
        emptyDir:
{{ toYaml .Values.emptyDir | indent 10 }}
{{- end }}
 # redis-haproxy-deployment.yaml
{{- if .Values.haproxy.enabled }}
kind: Deployment
apiVersion: apps/v1
metadata:
  name: {{ template "redis-ha.fullname" . }}-haproxy
  namespace: {{ .Release.Namespace }}
  labels:
{{ include "labels.standard" . | indent 4 }}
spec:
  strategy:
    type: RollingUpdate
  revisionHistoryLimit: 1
  replicas: {{ .Values.haproxy.replicas }}
  selector:
    matchLabels:
      app: {{ template "redis-ha.name" . }}-haproxy
      release: {{ .Release.Name }}
  template:
    metadata:
      name: {{ template "redis-ha.fullname" . }}-haproxy
      labels:
        app: {{ template "redis-ha.name" . }}-haproxy
        release: {{ .Release.Name }}
      annotations:
      {{- if .Values.haproxy.metrics.enabled }}
        prometheus.io/port: "{{ .Values.haproxy.metrics.port }}"
        prometheus.io/scrape: "true"
        prometheus.io/path: "{{ .Values.haproxy.metrics.scrapePath }}"
      {{- end }}
        checksum/config: {{ print (include "config-haproxy.cfg" .) (include "config-haproxy_init.sh" .) | sha256sum }}
      {{- if .Values.haproxy.annotations }}
{{ toYaml .Values.haproxy.annotations | indent 8 }}
      {{- end }}
    spec:
      # Needed when using unmodified rbac-setup.yml
      {{ if .Values.haproxy.serviceAccount.create }}
      serviceAccountName: {{ template "redis-ha.serviceAccountName" . }}-haproxy
      {{ end }}
      nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
      tolerations:
{{ toYaml .Values.tolerations | indent 8 }}
      affinity:
    {{- if .Values.haproxy.affinity }}
    {{- with .Values.haproxy.affinity }}
{{ tpl . $ | indent 8 }}
    {{- end }}
    {{- else }}
    {{- if .Values.haproxy.additionalAffinities }}
{{ toYaml .Values.haproxy.additionalAffinities | indent 8 }}
    {{- end }}
        podAntiAffinity:
    {{- if .Values.haproxy.hardAntiAffinity }}
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: {{ template "redis-ha.name" . }}-haproxy
                  release: {{ .Release.Name }}
              topologyKey: kubernetes.io/hostname
    {{- else }}
          preferredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: {{ template "redis-ha.name" . }}-haproxy
                  release: {{ .Release.Name }}
              topologyKey: kubernetes.io/hostname
    {{- end }}
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app:  {{ template "redis-ha.name" . }}-haproxy
                    release: {{ .Release.Name }}
                topologyKey: failure-domain.beta.kubernetes.io/zone
    {{- end }}
      initContainers:
      - name: config-init
        image: {{ .Values.haproxy.image.repository }}:{{ .Values.haproxy.image.tag }}
        imagePullPolicy: {{ .Values.haproxy.image.pullPolicy }}
        resources:
{{ toYaml .Values.haproxy.init.resources | indent 10 }}
        command:
        - sh
        args:
        - /readonly/haproxy_init.sh
{{- if .Values.auth }}
        env:
        - name: AUTH
          valueFrom:
            secretKeyRef:
            {{- if .Values.existingSecret }}
              name: {{ .Values.existingSecret }}
            {{- else }}
              name: {{ template "redis-ha.fullname" . }}
            {{- end }}
              key: {{ .Values.authKey }}
{{- end }}
        volumeMounts:
        - name: config-volume
          mountPath: /readonly
          readOnly: true
        - name: data
          mountPath: /data
      {{- if .Values.haproxy.imagePullSecrets }}
      imagePullSecrets: {{ toYaml .Values.haproxy.imagePullSecrets | nindent 8 }}
      {{- end }}
      securityContext:
{{ toYaml .Values.haproxy.securityContext | indent 8 }}
      containers:
      - name: haproxy
        image: {{ .Values.haproxy.image.repository }}:{{ .Values.haproxy.image.tag }}
        imagePullPolicy: {{ .Values.haproxy.image.pullPolicy }}
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8888
          initialDelaySeconds: 5
          periodSeconds: 3
        ports:
        - name: redis
          containerPort: {{ default "6379" .Values.redis.port }}
        {{- if .Values.haproxy.readOnly.enabled }}
        - name: readonlyport
          containerPort: {{ default "6380" .Values.haproxy.readOnly.port }}
        {{- end }}
        {{- if .Values.haproxy.metrics.enabled }}
        - name: metrics-port
          containerPort: {{ default "9101" .Values.haproxy.metrics.port }}
        {{- end }}
        resources:
{{ toYaml .Values.haproxy.resources | indent 10 }}
        volumeMounts:
        - name: data
          mountPath: /usr/local/etc/haproxy
        - name: shared-socket
          mountPath: /run/haproxy
{{- if .Values.haproxy.priorityClassName }}
      priorityClassName: {{ .Values.haproxy.priorityClassName }}
{{- end }}
      volumes:
      - name: config-volume
        configMap:
          name: {{ template "redis-ha.fullname" . }}-configmap
      - name: shared-socket
        emptyDir: 
{{ toYaml .Values.haproxy.emptyDir | indent 10 }}
      - name: data
        emptyDir: 
{{ toYaml .Values.haproxy.emptyDir | indent 10 }}
{{- end }}
 # redis-haproxy-service.yaml
{{- if .Values.haproxy.enabled }}
apiVersion: v1
kind: Service
metadata:
  name: {{ template "redis-ha.fullname" . }}-haproxy
  namespace: {{ .Release.Namespace }}
  labels:
{{ include "labels.standard" . | indent 4 }}
    component: {{ template "redis-ha.fullname" . }}-haproxy
  annotations:
  {{- if .Values.haproxy.service.annotations }}
{{ toYaml .Values.haproxy.service.annotations | indent 4 }}
  {{- end }}
spec:
  type: {{ default "ClusterIP" .Values.haproxy.service.type }}
  {{- if and (eq .Values.haproxy.service.type "LoadBalancer") .Values.haproxy.service.loadBalancerIP }}
  loadBalancerIP: {{ .Values.haproxy.service.loadBalancerIP }}
  {{- end }}
  ports:
  - name: haproxy
    port: {{ .Values.redis.port }}
    protocol: TCP
    targetPort: redis
  {{- if and (eq .Values.haproxy.service.type "NodePort") .Values.haproxy.service.nodePort }}
    nodePort: {{ .Values.haproxy.service.nodePort }}
  {{- end }}
{{- if .Values.haproxy.readOnly.enabled }}
  - name: haproxyreadonly
    port: {{ .Values.haproxy.readOnly.port }}
    protocol: TCP
    targetPort: {{ .Values.haproxy.readOnly.port }}
{{- end }}
{{- if .Values.haproxy.metrics.enabled }}
  - name: {{ .Values.haproxy.metrics.portName }}
    port: {{ .Values.haproxy.metrics.port }}
    protocol: TCP
    targetPort: metrics-port
{{- end }}
  selector:
    release: {{ .Release.Name }}
    app: {{ template "redis-ha.name" . }}-haproxy
{{- end }}
 # redis-haproxy-serviceaccount.yaml
{{- if and .Values.haproxy.serviceAccount.create .Values.haproxy.enabled }}
apiVersion: v1
kind: ServiceAccount
metadata:
  name: {{ template "redis-ha.serviceAccountName" . }}-haproxy
  namespace: {{ .Release.Namespace }}
  labels:
    heritage: {{ .Release.Service }}
    release: {{ .Release.Name }}
    chart: {{ .Chart.Name }}-{{ .Chart.Version }}
    app: {{ template "redis-ha.fullname" . }}
{{- end }}
 # redis-haproxy-servicemonitor.yaml
{{- if and ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) ( .Values.haproxy.metrics.serviceMonitor.enabled ) ( .Values.haproxy.metrics.enabled ) }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
{{- with .Values.haproxy.metrics.serviceMonitor.labels }}
  labels: {{ toYaml . | nindent 4}}
{{- end }}
  name: {{ template "redis-ha.fullname" . }}-haproxy
  namespace: {{ .Release.Namespace }}
{{- if .Values.haproxy.metrics.serviceMonitor.namespace }}
  namespace: {{ .Values.haproxy.metrics.serviceMonitor.namespace }}
{{- end }}
spec:
  endpoints:
  - targetPort: {{ .Values.haproxy.metrics.port }}
{{- if .Values.haproxy.metrics.serviceMonitor.interval }}
    interval: {{ .Values.haproxy.metrics.serviceMonitor.interval }}
{{- end }}
{{- if .Values.haproxy.metrics.serviceMonitor.telemetryPath }}
    path: {{ .Values.haproxy.metrics.serviceMonitor.telemetryPath }}
{{- end }}
{{- if .Values.haproxy.metrics.serviceMonitor.timeout }}
    scrapeTimeout: {{ .Values.haproxy.metrics.serviceMonitor.timeout }}
{{- end }}
  jobLabel: {{ template "redis-ha.fullname" . }}-haproxy
  namespaceSelector:
    matchNames:
    - {{ .Release.Namespace }}
  selector:
    matchLabels:
      app: {{ template "redis-ha.name" . }}
      release: {{ .Release.Name }}
      component: {{ template "redis-ha.fullname" . }}-haproxy
{{- end }}
 # test-redis-ha-configmap.yaml
apiVersion: v1
kind: Pod
metadata:
  name: {{ template "redis-ha.fullname" . }}-configmap-test
  labels:
{{ include "labels.standard" . | indent 4 }}
  annotations:
    "helm.sh/hook": test-success
spec:
  containers:
  - name: check-init
    image: koalaman/shellcheck:v0.5.0
    args:
    - --shell=sh
    - /readonly-config/init.sh
    volumeMounts:
    - name: config
      mountPath: /readonly-config
      readOnly: true
  {{- if .Values.imagePullSecrets }}
  imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 4 }}
  {{- end }}
  restartPolicy: Never
  volumes:
  - name: config
    configMap:
      name: {{ template "redis-ha.fullname" . }}-configmap
 # test-redis-ha-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: {{ template "redis-ha.fullname" . }}-service-test
  labels:
{{ include "labels.standard" . | indent 4 }}
  annotations:
    "helm.sh/hook": test-success
spec:
  containers:
  - name: "{{ .Release.Name }}-service-test"
    image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
    command:
      - sh
      - -c
      - redis-cli -h {{ template "redis-ha.fullname" . }} -p {{ .Values.redis.port }} info server
  {{- if .Values.imagePullSecrets }}
  imagePullSecrets: {{ toYaml .Values.imagePullSecrets | nindent 4 }}
  {{- end }}
  restartPolicy: Never

## Configure resource requests and limits
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
##
image:
  repository: redis
  tag: 5.0.6-alpine
  pullPolicy: IfNotPresent

## Reference to one or more secrets to be used when pulling images
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
## This imagePullSecrets is only for redis images
##
imagePullSecrets: []
# - name: "image-pull-secret"

## replicas number for each component
replicas: 3

## Kubernetes priorityClass name for the redis-ha-server pod
# priorityClassName: ""

## Custom labels for the redis pod
labels: {}

## Pods Service Account
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
serviceAccount:
  ## Specifies whether a ServiceAccount should be created
  ##
  create: true
  ## The name of the ServiceAccount to use.
  ## If not set and create is true, a name is generated using the redis-ha.fullname template
  # name:

## Enables a HA Proxy for better LoadBalancing / Sentinel Master support. Automatically proxies to Redis master.
## Recommend for externally exposed Redis clusters.
## ref: https://cbonte.github.io/haproxy-dconv/1.9/intro.html
haproxy:
  enabled: false
  # Enable if you want a dedicated port in haproxy for redis-slaves
  readOnly:
    enabled: false
    port: 6380
  replicas: 3
  image:
    repository: haproxy
    tag: 2.0.4
    pullPolicy: IfNotPresent

  ## Reference to one or more secrets to be used when pulling images
  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
  ##
  imagePullSecrets: []
  # - name: "image-pull-secret"

  annotations: {}
  resources: {}
  emptyDir: {}
  ## Enable sticky sessions to Redis nodes via HAProxy
  ## Very useful for long-living connections as in case of Sentry for example
  stickyBalancing: false
  ## Kubernetes priorityClass name for the haproxy pod
  # priorityClassName: ""
  ## Service type for HAProxy
  ##
  service:
    type: ClusterIP
    loadBalancerIP:
    annotations: {}
  serviceAccount:
    create: true
  ## Official HAProxy embedded prometheus metrics settings.
  ## Ref: https://github.com/haproxy/haproxy/tree/master/contrib/prometheus-exporter
  ##
  metrics:
    enabled: false
    # prometheus port & scrape path
    port: 9101
    portName: exporter-port
    scrapePath: /metrics

    serviceMonitor:
      # When set true then use a ServiceMonitor to configure scraping
      enabled: false
      # Set the namespace the ServiceMonitor should be deployed
      # namespace: monitoring
      # Set how frequently Prometheus should scrape
      # interval: 30s
      # Set path to redis-exporter telemtery-path
      # telemetryPath: /metrics
      # Set labels for the ServiceMonitor, use this to define your scrape label for Prometheus Operator
      # labels: {}
      # Set timeout for scrape
      # timeout: 10s
  init:
    resources: {}
  timeout:
    connect: 4s
    server: 30s
    client: 30s
    check: 2s
  securityContext:
    runAsUser: 1000
    fsGroup: 1000
    runAsNonRoot: true

  ## Whether the haproxy pods should be forced to run on separate nodes.
  hardAntiAffinity: true

  ## Additional affinities to add to the haproxy pods.
  additionalAffinities: {}

  ## Override all other affinity settings for the haproxy pods with a string.
  affinity: |

  ## Custom config-haproxy.cfg files used to override default settings. If this file is
  ## specified then the config-haproxy.cfg above will be ignored.
  # customConfig: |-
      # Define configuration here
  ## Place any additional configuration section to add to the default config-haproxy.cfg
  # extraConfig: |-
      # Define configuration here


## Role Based Access
## Ref: https://kubernetes.io/docs/admin/authorization/rbac/
##
rbac:
  create: true

sysctlImage:
  enabled: false
  command: []
  registry: docker.io
  repository: busybox
  tag: 1.31.1
  pullPolicy: Always
  mountHostSys: false
  resources: {}

## Use an alternate scheduler, e.g. "stork".
## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
##
# schedulerName:

## Redis specific configuration options
redis:
  port: 6379
  masterGroupName: "mymaster"       # must match ^[\\w-\\.]+$) and can be templated
  config:
    ## Additional redis conf options can be added below
    ## For all available options see http://download.redis.io/redis-stable/redis.conf
    min-replicas-to-write: 1
    min-replicas-max-lag: 5   # Value in seconds
    maxmemory: "0"       # Max memory to use for each redis instance. Default is unlimited.
    maxmemory-policy: "volatile-lru"  # Max memory policy to use for each redis instance. Default is volatile-lru.
    # Determines if scheduled RDB backups are created. Default is false.
    # Please note that local (on-disk) RDBs will still be created when re-syncing with a new slave. The only way to prevent this is to enable diskless replication.
    save: "900 1"
    # When enabled, directly sends the RDB over the wire to slaves, without using the disk as intermediate storage. Default is false.
    repl-diskless-sync: "yes"
    rdbcompression: "yes"
    rdbchecksum: "yes"


  ## Custom redis.conf files used to override default settings. If this file is
  ## specified then the redis.config above will be ignored.
  # customConfig: |-
      # Define configuration here

  resources: {}
  #  requests:
  #    memory: 200Mi
  #    cpu: 100m
  #  limits:
  #    memory: 700Mi

## Sentinel specific configuration options
sentinel:
  port: 26379
  quorum: 2
  config:
    ## Additional sentinel conf options can be added below. Only options that
    ## are expressed in the format simialar to 'sentinel xxx mymaster xxx' will
    ## be properly templated expect maxclients option.
    ## For available options see http://download.redis.io/redis-stable/sentinel.conf
    down-after-milliseconds: 10000
    ## Failover timeout value in milliseconds
    failover-timeout: 180000
    parallel-syncs: 5
    maxclients: 10000

  ## Custom sentinel.conf files used to override default settings. If this file is
  ## specified then the sentinel.config above will be ignored.
  # customConfig: |-
      # Define configuration here

  resources: {}
  #  requests:
  #    memory: 200Mi
  #    cpu: 100m
  #  limits:
  #    memory: 200Mi

securityContext:
  runAsUser: 1000
  fsGroup: 1000
  runAsNonRoot: true

## Node labels, affinity, and tolerations for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
nodeSelector: {}

## Whether the Redis server pods should be forced to run on separate nodes.
## This is accomplished by setting their AntiAffinity with requiredDuringSchedulingIgnoredDuringExecution as opposed to preferred.
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity-beta-feature
##
hardAntiAffinity: true

## Additional affinities to add to the Redis server pods.
##
## Example:
##   nodeAffinity:
##     preferredDuringSchedulingIgnoredDuringExecution:
##       - weight: 50
##         preference:
##           matchExpressions:
##             - key: spot
##               operator: NotIn
##               values:
##                 - "true"
##
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
##
additionalAffinities: {}

## Override all other affinity settings for the Redis server pods with a string.
##
## Example:
## affinity: |
##   podAntiAffinity:
##     requiredDuringSchedulingIgnoredDuringExecution:
##       - labelSelector:
##           matchLabels:
##             app: {{ template "redis-ha.name" . }}
##             release: {{ .Release.Name }}
##         topologyKey: kubernetes.io/hostname
##     preferredDuringSchedulingIgnoredDuringExecution:
##       - weight: 100
##         podAffinityTerm:
##           labelSelector:
##             matchLabels:
##               app:  {{ template "redis-ha.name" . }}
##               release: {{ .Release.Name }}
##           topologyKey: failure-domain.beta.kubernetes.io/zone
##
affinity: |

# Prometheus exporter specific configuration options
exporter:
  enabled: false
  image: oliver006/redis_exporter
  tag: v1.3.2
  pullPolicy: IfNotPresent

  # prometheus port & scrape path
  port: 9121
  scrapePath: /metrics

  # cpu/memory resource limits/requests
  resources: {}

  # Additional args for redis exporter
  extraArgs: {}

  # Used to mount a LUA-Script via config map and use it for metrics-collection
  # script: |
  #   -- Example script copied from: https://github.com/oliver006/redis_exporter/blob/master/contrib/sample_collect_script.lua
  #   -- Example collect script for -script option
  #   -- This returns a Lua table with alternating keys and values.
  #   -- Both keys and values must be strings, similar to a HGETALL result.
  #   -- More info about Redis Lua scripting: https://redis.io/commands/eval
  #
  #   local result = {}
  #
  #   -- Add all keys and values from some hash in db 5
  #   redis.call("SELECT", 5)
  #   local r = redis.call("HGETALL", "some-hash-with-stats")
  #   if r ~= nil then
  #   for _,v in ipairs(r) do
  #   table.insert(result, v) -- alternating keys and values
  #   end
  #   end
  #
  #   -- Set foo to 42
  #   table.insert(result, "foo")
  #   table.insert(result, "42") -- note the string, use tostring() if needed
  #
  #   return result

  serviceMonitor:
    # When set true then use a ServiceMonitor to configure scraping
    enabled: false
    # Set the namespace the ServiceMonitor should be deployed
    # namespace: monitoring
    # Set how frequently Prometheus should scrape
    # interval: 30s
    # Set path to redis-exporter telemtery-path
    # telemetryPath: /metrics
    # Set labels for the ServiceMonitor, use this to define your scrape label for Prometheus Operator
    # labels: {}
    # Set timeout for scrape
    # timeout: 10s

podDisruptionBudget: {}
  # maxUnavailable: 1
  # minAvailable: 1

## Configures redis with AUTH (requirepass & masterauth conf params)
auth: false
# redisPassword:

## Use existing secret containing key `authKey` (ignores redisPassword)
# existingSecret:

## Defines the key holding the redis password in existing secret.
authKey: auth

persistentVolume:
  enabled: true
  ## redis-ha data Persistent Volume Storage Class
  ## If defined, storageClassName: <storageClass>
  ## If set to "-", storageClassName: "", which disables dynamic provisioning
  ## If undefined (the default) or set to null, no storageClassName spec is
  ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
  ##   GKE, AWS & OpenStack)
  ##
  # storageClass: "-"
  accessModes:
    - ReadWriteOnce
  size: 10Gi
  annotations: {}
  # reclaimPolicy per https://kubernetes.io/docs/concepts/storage/persistent-volumes/#reclaiming
  reclaimPolicy: ""
init:
  resources: {}

# To use a hostPath for data, set persistentVolume.enabled to false
# and define hostPath.path.
# Warning: this might overwrite existing folders on the host system!
hostPath:
  ## path is evaluated as template so placeholders are replaced
  # path: "/data/{{ .Release.Name }}"

  # if chown is true, an init-container with root permissions is launched to
  # change the owner of the hostPath folder to the user defined in the
  # security context
  chown: true

emptyDir: {}
