---
# Source: redis/templates/networkpolicy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: turboscale-redis
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/instance: turboscale
      app.kubernetes.io/name: redis
  policyTypes:
    - Ingress
    - Egress
  egress:
    - {}
  ingress:
    # Allow inbound connections
    - ports:
        - port: 6379
        - port: 26379
---
# Source: redis/templates/sentinel/pdb.yaml
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: turboscale-redis-node
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
    app.kubernetes.io/component: node
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app.kubernetes.io/instance: turboscale
      app.kubernetes.io/name: redis
      app.kubernetes.io/component: node
---
# Source: redis/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
automountServiceAccountToken: false
metadata:
  name: turboscale-redis
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
---
# Source: redis/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: turboscale-redis-configuration
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
data:
  redis.conf: |-
    # User-supplied common configuration:
    # Enable AOF https://redis.io/topics/persistence#append-only-file
    appendonly yes
    # Disable RDB persistence, AOF persistence already enabled.
    save ""
    # End of common configuration
  master.conf: |-
    dir /data
    # User-supplied master configuration:
    rename-command FLUSHDB ""
    rename-command FLUSHALL ""
    # End of master configuration
  replica.conf: |-
    dir /data
    # User-supplied replica configuration:
    rename-command FLUSHDB ""
    rename-command FLUSHALL ""
    # End of replica configuration
  sentinel.conf: |-
    dir "/tmp"
    port 26379
    sentinel monitor mymaster turboscale-redis.<HubHaNameSpace>.svc.cluster.local 6379 2
    sentinel down-after-milliseconds mymaster 60000
    sentinel resolve-hostnames yes
    sentinel failover-timeout mymaster 180000
    sentinel parallel-syncs mymaster 1
    # User-supplied sentinel configuration:
    # End of sentinel configuration
---
# Source: redis/templates/health-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: turboscale-redis-health
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
data:
  ping_readiness_local.sh: |-
    #!/bin/bash

    [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")"
    [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD"
    response=$(
      timeout -s 15 $1 \
      redis-cli \
        -h localhost \
        -p $REDIS_PORT \
        ping
    )
    if [ "$?" -eq "124" ]; then
      echo "Timed out"
      exit 1
    fi
    if [ "$response" != "PONG" ]; then
      echo "$response"
      exit 1
    fi
  ping_liveness_local.sh: |-
    #!/bin/bash

    [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")"
    [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD"
    response=$(
      timeout -s 15 $1 \
      redis-cli \
        -h localhost \
        -p $REDIS_PORT \
        ping
    )
    if [ "$?" -eq "124" ]; then
      echo "Timed out"
      exit 1
    fi
    responseFirstWord=$(echo $response | head -n1 | awk '{print $1;}')
    if [ "$response" != "PONG" ] && [ "$responseFirstWord" != "LOADING" ] && [ "$responseFirstWord" != "MASTERDOWN" ]; then
      echo "$response"
      exit 1
    fi
  ping_sentinel.sh: |-
    #!/bin/bash
    [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")"
    [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD"
    response=$(
      timeout -s 15 $1 \
      redis-cli \
        -h localhost \
        -p $REDIS_SENTINEL_PORT \
        ping
    )
    if [ "$?" -eq "124" ]; then
      echo "Timed out"
      exit 1
    fi
    if [ "$response" != "PONG" ]; then
      echo "$response"
      exit 1
    fi
  parse_sentinels.awk: |-
    /ip/ {FOUND_IP=1}
    /port/ {FOUND_PORT=1}
    /runid/ {FOUND_RUNID=1}
    !/ip|port|runid/ {
      if (FOUND_IP==1) {
        IP=$1; FOUND_IP=0;
      }
      else if (FOUND_PORT==1) {
        PORT=$1;
        FOUND_PORT=0;
      } else if (FOUND_RUNID==1) {
        printf "\nsentinel known-sentinel mymaster %s %s %s", IP, PORT, $0; FOUND_RUNID=0;
      }
    }
  ping_readiness_master.sh: |-
    #!/bin/bash

    [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")"
    [[ -n "$REDIS_MASTER_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_MASTER_PASSWORD"
    response=$(
      timeout -s 15 $1 \
      redis-cli \
        -h $REDIS_MASTER_HOST \
        -p $REDIS_MASTER_PORT_NUMBER \
        ping
    )
    if [ "$?" -eq "124" ]; then
      echo "Timed out"
      exit 1
    fi
    if [ "$response" != "PONG" ]; then
      echo "$response"
      exit 1
    fi
  ping_liveness_master.sh: |-
    #!/bin/bash

    [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")"
    [[ -n "$REDIS_MASTER_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_MASTER_PASSWORD"
    response=$(
      timeout -s 15 $1 \
      redis-cli \
        -h $REDIS_MASTER_HOST \
        -p $REDIS_MASTER_PORT_NUMBER \
        ping
    )
    if [ "$?" -eq "124" ]; then
      echo "Timed out"
      exit 1
    fi
    responseFirstWord=$(echo $response | head -n1 | awk '{print $1;}')
    if [ "$response" != "PONG" ] && [ "$responseFirstWord" != "LOADING" ]; then
      echo "$response"
      exit 1
    fi
  ping_readiness_local_and_master.sh: |-
    script_dir="$(dirname "$0")"
    exit_status=0
    "$script_dir/ping_readiness_local.sh" $1 || exit_status=$?
    "$script_dir/ping_readiness_master.sh" $1 || exit_status=$?
    exit $exit_status
  ping_liveness_local_and_master.sh: |-
    script_dir="$(dirname "$0")"
    exit_status=0
    "$script_dir/ping_liveness_local.sh" $1 || exit_status=$?
    "$script_dir/ping_liveness_master.sh" $1 || exit_status=$?
    exit $exit_status
---
# Source: redis/templates/scripts-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: turboscale-redis-scripts
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
data:
  start-node.sh: |
    #!/bin/bash

    . /opt/bitnami/scripts/libos.sh
    . /opt/bitnami/scripts/liblog.sh
    . /opt/bitnami/scripts/libvalidations.sh

    get_port() {
        hostname="$1"
        type="$2"

        port_var=$(echo "${hostname^^}_SERVICE_PORT_$type" | sed "s/-/_/g")
        port=${!port_var}

        if [ -z "$port" ]; then
            case $type in
                "SENTINEL")
                    echo 26379
                    ;;
                "REDIS")
                    echo 6379
                    ;;
            esac
        else
            echo $port
        fi
    }

    get_full_hostname() {
        hostname="$1"
        full_hostname="${hostname}.${HEADLESS_SERVICE}"
        echo "${full_hostname}"
    }

    REDISPORT=$(get_port "$HOSTNAME" "REDIS")

    HEADLESS_SERVICE="turboscale-redis-headless.<HubHaNameSpace>.svc.cluster.local"

    if [ -n "$REDIS_EXTERNAL_MASTER_HOST" ]; then
        REDIS_SERVICE="$REDIS_EXTERNAL_MASTER_HOST"
    else
        REDIS_SERVICE="turboscale-redis.<HubHaNameSpace>.svc.cluster.local"
    fi

    SENTINEL_SERVICE_PORT=$(get_port "turboscale-redis" "SENTINEL")

    redis_cli_command() {
        local timeout="${1:-0}"

        local args=("-h" "$REDIS_SERVICE" "-p" "$SENTINEL_SERVICE_PORT")
        local command="redis-cli"
        if is_boolean_yes "$REDIS_TLS_ENABLED"; then
            args+=("--tls" "--cert" "$REDIS_TLS_CERT_FILE" "--key" "$REDIS_TLS_KEY_FILE")
            [ -n "$REDIS_TLS_CA_FILE" ] && args+=("--cacert" "$REDIS_TLS_CA_FILE")
        fi
        if [ "$timeout" -gt 0 ]; then
            command="timeout $timeout $command"
        fi

        echo "REDISCLI_AUTH="\$REDIS_PASSWORD"  $command ${args[*]}"
    }

    validate_quorum() {
        quorum_info_command="$(redis_cli_command) sentinel master mymaster"
        info "about to run the command: $quorum_info_command"
        eval $quorum_info_command | grep -Fq "s_down"
    }

    trigger_manual_failover() {
        failover_command="$(redis_cli_command) sentinel failover mymaster"
        info "about to run the command: $failover_command"
        eval $failover_command
    }

    get_sentinel_master_info() {
        sentinel_info_command="$(redis_cli_command 90) sentinel get-master-addr-by-name mymaster"
        info "about to run the command: $sentinel_info_command"
        retry_while "eval $sentinel_info_command" 2 5
    }

    [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")"
    [[ -f $REDIS_MASTER_PASSWORD_FILE ]] && export REDIS_MASTER_PASSWORD="$(< "${REDIS_MASTER_PASSWORD_FILE}")"

    # check if there is a master
    master_in_persisted_conf="$(get_full_hostname "$HOSTNAME")"
    master_port_in_persisted_conf="$REDIS_MASTER_PORT_NUMBER"
    master_in_sentinel="$(get_sentinel_master_info)"
    redisRetVal=$?

    if [[ -f /opt/bitnami/redis-sentinel/etc/sentinel.conf ]]; then
        master_in_persisted_conf="$(awk '/monitor/ {print $4}' /opt/bitnami/redis-sentinel/etc/sentinel.conf)"
        master_port_in_persisted_conf="$(awk '/monitor/ {print $5}' /opt/bitnami/redis-sentinel/etc/sentinel.conf)"
        info "Found previous master ${master_in_persisted_conf}:${master_port_in_persisted_conf} in /opt/bitnami/redis-sentinel/etc/sentinel.conf"
        debug "$(cat /opt/bitnami/redis-sentinel/etc/sentinel.conf | grep monitor)"
    fi

    if [[ $redisRetVal -ne 0 ]]; then
        if [[ "$master_in_persisted_conf" == "$(get_full_hostname "$HOSTNAME")" ]]; then
            # Case 1: No active sentinel and in previous sentinel.conf we were the master --> MASTER
            info "Configuring the node as master"
            export REDIS_REPLICATION_MODE="master"
        else
            # Case 2: No active sentinel and in previous sentinel.conf we were not master --> REPLICA
            info "Configuring the node as replica"
            export REDIS_REPLICATION_MODE="replica"
            REDIS_MASTER_HOST=${master_in_persisted_conf}
            REDIS_MASTER_PORT_NUMBER=${master_port_in_persisted_conf}
        fi
    else
        # Fetches current master's host and port
        REDIS_SENTINEL_INFO=($(get_sentinel_master_info))
        info "Current master: REDIS_SENTINEL_INFO=(${REDIS_SENTINEL_INFO[0]},${REDIS_SENTINEL_INFO[1]})"
        REDIS_MASTER_HOST=${REDIS_SENTINEL_INFO[0]}
        REDIS_MASTER_PORT_NUMBER=${REDIS_SENTINEL_INFO[1]}

        if [[ "$REDIS_MASTER_HOST" == "$(get_full_hostname "$HOSTNAME")" ]]; then
            # Case 3: Active sentinel and master it is this node --> MASTER
            info "Configuring the node as master"
            export REDIS_REPLICATION_MODE="master"
        else
            # Case 4: Active sentinel and master is not this node --> REPLICA
            info "Configuring the node as replica"
            export REDIS_REPLICATION_MODE="replica"
        fi
    fi

    if [[ -n "$REDIS_EXTERNAL_MASTER_HOST" ]]; then
      REDIS_MASTER_HOST="$REDIS_EXTERNAL_MASTER_HOST"
      REDIS_MASTER_PORT_NUMBER="${REDIS_EXTERNAL_MASTER_PORT}"
    fi

    if [[ -f /opt/bitnami/redis/mounted-etc/replica.conf ]];then
        cp /opt/bitnami/redis/mounted-etc/replica.conf /opt/bitnami/redis/etc/replica.conf
    fi

    if [[ -f /opt/bitnami/redis/mounted-etc/redis.conf ]];then
        cp /opt/bitnami/redis/mounted-etc/redis.conf /opt/bitnami/redis/etc/redis.conf
    fi

    echo "" >> /opt/bitnami/redis/etc/replica.conf
    echo "replica-announce-port $REDISPORT" >> /opt/bitnami/redis/etc/replica.conf
    echo "replica-announce-ip $(get_full_hostname "$HOSTNAME")" >> /opt/bitnami/redis/etc/replica.conf
    ARGS=("--port" "${REDIS_PORT}")

    if [[ "$REDIS_REPLICATION_MODE" = "slave" ]] || [[ "$REDIS_REPLICATION_MODE" = "replica" ]]; then
        ARGS+=("--replicaof" "${REDIS_MASTER_HOST}" "${REDIS_MASTER_PORT_NUMBER}")
    fi
    ARGS+=("--requirepass" "${REDIS_PASSWORD}")
    ARGS+=("--masterauth" "${REDIS_MASTER_PASSWORD}")
    ARGS+=("--include" "/opt/bitnami/redis/etc/replica.conf")
    ARGS+=("--include" "/opt/bitnami/redis/etc/redis.conf")
    exec redis-server "${ARGS[@]}"

  start-sentinel.sh: |
    #!/bin/bash

    . /opt/bitnami/scripts/libos.sh
    . /opt/bitnami/scripts/libvalidations.sh
    . /opt/bitnami/scripts/libfile.sh

    HEADLESS_SERVICE="turboscale-redis-headless.<HubHaNameSpace>.svc.cluster.local"
    REDIS_SERVICE="turboscale-redis.<HubHaNameSpace>.svc.cluster.local"

    get_port() {
        hostname="$1"
        type="$2"

        port_var=$(echo "${hostname^^}_SERVICE_PORT_$type" | sed "s/-/_/g")
        port=${!port_var}

        if [ -z "$port" ]; then
            case $type in
                "SENTINEL")
                    echo 26379
                    ;;
                "REDIS")
                    echo 6379
                    ;;
            esac
        else
            echo $port
        fi
    }

    get_full_hostname() {
        hostname="$1"
        full_hostname="${hostname}.${HEADLESS_SERVICE}"
        echo "${full_hostname}"
    }

    SERVPORT=$(get_port "$HOSTNAME" "SENTINEL")
    REDISPORT=$(get_port "$HOSTNAME" "REDIS")
    SENTINEL_SERVICE_PORT=$(get_port "turboscale-redis" "SENTINEL")

    sentinel_conf_set() {
        local -r key="${1:?missing key}"
        local value="${2:-}"

        # Sanitize inputs
        value="${value//\\/\\\\}"
        value="${value//&/\\&}"
        value="${value//\?/\\?}"
        [[ "$value" = "" ]] && value="\"$value\""

        replace_in_file "/opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf" "^#*\s*${key} .*" "${key} ${value}" false
    }
    sentinel_conf_add() {
        echo $'\n'"$@" >> "/opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf"
    }
    host_id() {
        echo "$1" | openssl sha1 | awk '{print $2}'
    }
    get_sentinel_master_info() {
        if is_boolean_yes "$REDIS_SENTINEL_TLS_ENABLED"; then
            sentinel_info_command="REDISCLI_AUTH="\$REDIS_PASSWORD" timeout 90 redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT --tls --cert ${REDIS_SENTINEL_TLS_CERT_FILE} --key ${REDIS_SENTINEL_TLS_KEY_FILE} --cacert ${REDIS_SENTINEL_TLS_CA_FILE} sentinel get-master-addr-by-name mymaster"
        else
            sentinel_info_command="REDISCLI_AUTH="\$REDIS_PASSWORD" timeout 90 redis-cli -h $REDIS_SERVICE -p $SENTINEL_SERVICE_PORT sentinel get-master-addr-by-name mymaster"
        fi
        info "about to run the command: $sentinel_info_command"
        retry_while "eval $sentinel_info_command" 2 5
    }

    [[ -f $REDIS_PASSWORD_FILE ]] && export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")"

    master_in_persisted_conf="$(get_full_hostname "$HOSTNAME")"

    if [[ -f /opt/bitnami/redis-sentinel/etc/sentinel.conf ]]; then
        master_in_persisted_conf="$(awk '/monitor/ {print $4}' /opt/bitnami/redis-sentinel/etc/sentinel.conf)"
        info "Found previous master $master_in_persisted_conf in /opt/bitnami/redis-sentinel/etc/sentinel.conf"
        debug "$(cat /opt/bitnami/redis-sentinel/etc/sentinel.conf | grep monitor)"
    fi
    REDIS_SENTINEL_INFO=($(get_sentinel_master_info))
    if [ "$?" -eq "0" ]; then
        # current master's host and port obtained from other Sentinel
        info "printing REDIS_SENTINEL_INFO=(${REDIS_SENTINEL_INFO[0]},${REDIS_SENTINEL_INFO[1]})"
        REDIS_MASTER_HOST=${REDIS_SENTINEL_INFO[0]}
        REDIS_MASTER_PORT_NUMBER=${REDIS_SENTINEL_INFO[1]}
    else
        REDIS_MASTER_HOST="$master_in_persisted_conf"
        REDIS_MASTER_PORT_NUMBER="$REDISPORT"
    fi
    if [[ "$REDIS_MASTER_HOST" == "$(get_full_hostname "$HOSTNAME")" ]]; then
        export REDIS_REPLICATION_MODE="master"
    else
        export REDIS_REPLICATION_MODE="replica"
    fi

    if [[ -n "$REDIS_EXTERNAL_MASTER_HOST" ]]; then
      REDIS_MASTER_HOST="$REDIS_EXTERNAL_MASTER_HOST"
      REDIS_MASTER_PORT_NUMBER="${REDIS_EXTERNAL_MASTER_PORT}"
    fi

    # To prevent incomplete configuration and as the redis container accesses /opt/bitnami/redis-sentinel/etc/sentinel.conf
    # as well, prepare the new config in `prepare-sentinel.conf` and move it atomically to the ultimate destination when it is complete.
    cp /opt/bitnami/redis-sentinel/mounted-etc/sentinel.conf /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    printf "\nsentinel auth-pass %s %s" "mymaster" "$REDIS_PASSWORD" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    printf "\nrequirepass %s" "$REDIS_PASSWORD" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    printf "\nsentinel myid %s" "$(host_id "$HOSTNAME")" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf

    if [[ -z "$REDIS_MASTER_HOST" ]] || [[ -z "$REDIS_MASTER_PORT_NUMBER" ]]
    then
        # Prevent incorrect configuration to be written to sentinel.conf
        error "Redis master host is configured incorrectly (host: $REDIS_MASTER_HOST, port: $REDIS_MASTER_PORT_NUMBER)"
        exit 1
    fi

    sentinel_conf_set "sentinel monitor" "mymaster "$REDIS_MASTER_HOST" "$REDIS_MASTER_PORT_NUMBER" 2"
    sentinel_conf_add "sentinel resolve-hostnames yes"

    add_known_sentinel() {
        hostname="$1"
        ip="$2"

        if [[ -n "$hostname" && -n "$ip" && "$hostname" != "$HOSTNAME" ]]; then
            sentinel_conf_add "sentinel known-sentinel mymaster $(get_full_hostname "$hostname") $(get_port "$hostname" "SENTINEL") $(host_id "$hostname")"
        fi
    }
    add_known_replica() {
        hostname="$1"
        ip="$2"

        if [[ -n "$ip" && "$(get_full_hostname "$hostname")" != "$REDIS_MASTER_HOST" ]]; then
            sentinel_conf_add "sentinel known-replica mymaster $(get_full_hostname "$hostname") $(get_port "$hostname" "REDIS")"
        fi
    }

    # Add available hosts on the network as known replicas & sentinels
    for node in $(seq 0 $((3-1))); do
        hostname="turboscale-redis-node-$node"
        ip="$(getent hosts "$hostname.$HEADLESS_SERVICE" | awk '{ print $1 }')"
        add_known_sentinel "$hostname" "$ip"
        add_known_replica "$hostname" "$ip"
    done

    echo "" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    echo "sentinel announce-hostnames yes" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    echo "sentinel resolve-hostnames yes" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    echo "sentinel announce-port $SERVPORT" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    echo "sentinel announce-ip $(get_full_hostname "$HOSTNAME")" >> /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf
    mv /opt/bitnami/redis-sentinel/etc/prepare-sentinel.conf /opt/bitnami/redis-sentinel/etc/sentinel.conf
    exec redis-server /opt/bitnami/redis-sentinel/etc/sentinel.conf --sentinel
  prestop-sentinel.sh: |
    #!/bin/bash

    . /opt/bitnami/scripts/libvalidations.sh
    . /opt/bitnami/scripts/libos.sh

    HEADLESS_SERVICE="turboscale-redis-headless.<HubHaNameSpace>.svc.cluster.local"

    get_full_hostname() {
        hostname="$1"
        full_hostname="${hostname}.${HEADLESS_SERVICE}"
        echo "${full_hostname}"
    }

    run_sentinel_command() {
        if is_boolean_yes "$REDIS_SENTINEL_TLS_ENABLED"; then
            redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_TLS_PORT_NUMBER" --tls --cert "$REDIS_SENTINEL_TLS_CERT_FILE" --key "$REDIS_SENTINEL_TLS_KEY_FILE" --cacert "$REDIS_SENTINEL_TLS_CA_FILE" sentinel "$@"
        else
            redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_PORT" sentinel "$@"
        fi
    }
    sentinel_failover_finished() {
      REDIS_SENTINEL_INFO=($(run_sentinel_command get-master-addr-by-name "mymaster"))
      REDIS_MASTER_HOST="${REDIS_SENTINEL_INFO[0]}"
      [[ "$REDIS_MASTER_HOST" != "$(get_full_hostname $HOSTNAME)" ]]
    }

    REDIS_SERVICE="turboscale-redis.<HubHaNameSpace>.svc.cluster.local"

    # redis-cli automatically consumes credentials from the REDISCLI_AUTH variable
    [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD"
    [[ -f "$REDIS_PASSWORD_FILE" ]] && export REDISCLI_AUTH="$(< "${REDIS_PASSWORD_FILE}")"

    if ! sentinel_failover_finished; then
        echo "I am the master pod and you are stopping me. Starting sentinel failover"
        if retry_while "sentinel_failover_finished" "20" 1; then
            echo "Master has been successfuly failed over to a different pod."
            exit 0
        else
            echo "Master failover failed"
            exit 1
        fi
    else
        exit 0
    fi
  prestop-redis.sh: |
    #!/bin/bash

    . /opt/bitnami/scripts/libvalidations.sh
    . /opt/bitnami/scripts/libos.sh

    run_redis_command() {
        local args=("-h" "127.0.0.1")
        if is_boolean_yes "$REDIS_TLS_ENABLED"; then
            args+=("-p" "$REDIS_TLS_PORT" "--tls" "--cert" "$REDIS_TLS_CERT_FILE" "--key" "$REDIS_TLS_KEY_FILE")
            [ -n "$REDIS_TLS_CA_FILE" ] && args+=("--cacert" "$REDIS_TLS_CA_FILE")
        else
            args+=("-p" "$REDIS_PORT")
        fi
        redis-cli "${args[@]}" "$@"
    }
    is_master() {
        REDIS_ROLE=$(run_redis_command role | head -1)
        [[ "$REDIS_ROLE" == "master" ]]
    }

    HEADLESS_SERVICE="turboscale-redis-headless.<HubHaNameSpace>.svc.cluster.local"

    get_full_hostname() {
        hostname="$1"
        full_hostname="${hostname}.${HEADLESS_SERVICE}"
        echo "${full_hostname}"
    }

    run_sentinel_command() {
        if is_boolean_yes "$REDIS_SENTINEL_TLS_ENABLED"; then
            redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_TLS_PORT_NUMBER" --tls --cert "$REDIS_SENTINEL_TLS_CERT_FILE" --key "$REDIS_SENTINEL_TLS_KEY_FILE" --cacert "$REDIS_SENTINEL_TLS_CA_FILE" sentinel "$@"
        else
            redis-cli -h "$REDIS_SERVICE" -p "$REDIS_SENTINEL_PORT" sentinel "$@"
        fi
    }
    sentinel_failover_finished() {
        REDIS_SENTINEL_INFO=($(run_sentinel_command get-master-addr-by-name "mymaster"))
        REDIS_MASTER_HOST="${REDIS_SENTINEL_INFO[0]}"
        [[ "$REDIS_MASTER_HOST" != "$(get_full_hostname $HOSTNAME)" ]]
    }

    REDIS_SERVICE="turboscale-redis.<HubHaNameSpace>.svc.cluster.local"

    # redis-cli automatically consumes credentials from the REDISCLI_AUTH variable
    [[ -n "$REDIS_PASSWORD" ]] && export REDISCLI_AUTH="$REDIS_PASSWORD"
    [[ -f "$REDIS_PASSWORD_FILE" ]] && export REDISCLI_AUTH="$(< "${REDIS_PASSWORD_FILE}")"


    if is_master && ! sentinel_failover_finished; then
        echo "I am the master pod and you are stopping me. Pausing client connections."
        # Pausing client write connections to avoid data loss
        run_redis_command CLIENT PAUSE "22000" WRITE

        echo "Issuing failover"
        # if I am the master, issue a command to failover once
        run_sentinel_command failover "mymaster"
        echo "Waiting for sentinel to complete failover for up to 20s"
        retry_while "sentinel_failover_finished" "20" 1
    else
        exit 0
    fi
---
# Source: redis/templates/headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: turboscale-redis-headless
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
spec:
  type: ClusterIP
  clusterIP: None
  publishNotReadyAddresses: true
  ports:
    - name: tcp-redis
      port: 6379
      targetPort: redis
    - name: tcp-sentinel
      port: 26379
      targetPort: redis-sentinel
  selector:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/name: redis
---
# Source: redis/templates/sentinel/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: turboscale-redis
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
    app.kubernetes.io/component: node
spec:
  type: ClusterIP
  sessionAffinity: None
  ports:
    - name: tcp-redis
      port: 6379
      targetPort: 6379
      nodePort: null
    - name: tcp-sentinel
      port: 26379
      targetPort: 26379
      nodePort: null
  selector:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/name: redis
    app.kubernetes.io/component: node
---
# Source: redis/templates/sentinel/statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: turboscale-redis-node
  namespace: <HubHaNameSpace>
  labels:
    app.kubernetes.io/instance: turboscale
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: redis
    app.kubernetes.io/version: 7.4.1
    helm.sh/chart: redis-20.6.1
    app.kubernetes.io/component: node
    cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
spec:
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/instance: turboscale
      app.kubernetes.io/name: redis
      app.kubernetes.io/component: node
  serviceName: turboscale-redis-headless
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/instance: turboscale
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/name: redis
        app.kubernetes.io/version: 7.4.1
        helm.sh/chart: redis-20.6.1
        app.kubernetes.io/component: node
      annotations:
#        checksum/configmap: b9e0d9224bd2abd3ff02f3d37b936ca145274cbb2098345a941898e5093b86d3
        checksun/configmap: 9cca9faa12c4456a87f4bf62979b014d7f434168602b6715f693e8f66ff26bfd
        checksum/health: 1eace71641fb5bd753e90012419e82c10b1180d694f91d83743b727a5aacca73
#        checksum/scripts: fe48872558f2a79b33688c17b93e60dd870db913659952247eb02a8112f28ae4
#        checksum/secret: 59a721b3bcc0ef9196fa2ff07a656b2b693af8b9a053fcb56c62c2770e85bb1f
        checksum/scripts: e76c92ac67e7d72dad0eb764cdf02361844822f1275c5098d1118552955db334
#        checksum/secret: 9d8f8d280dae4b98203bb2dddf76c739a082ec202e076c112ea9f3a315eb3854
        "cluster-autoscaler.kubernetes.io/safe-to-evict": "false"
    spec:

      automountServiceAccountToken: false
      securityContext:
        fsGroup: 1001
        fsGroupChangePolicy: Always
        supplementalGroups: []
        sysctls: []
      serviceAccountName: turboscale-redis
      affinity:
        podAffinity:

        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app.kubernetes.io/instance: turboscale
                    app.kubernetes.io/name: redis
                    app.kubernetes.io/component: node
                topologyKey: kubernetes.io/hostname
              weight: 1
        nodeAffinity:

      enableServiceLinks: true
      terminationGracePeriodSeconds: 30
      containers:
        - name: redis
          image: public.ecr.aws/v4a1k5d3/browserstack/turboscale-kafka-uploader:redis_7.4.1-debian-12-r3
          imagePullPolicy: "IfNotPresent"
          lifecycle:
            preStop:
              exec:
                command:
                  - /bin/bash
                  - -c
                  - /opt/bitnami/scripts/start-scripts/prestop-redis.sh
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
              - ALL
            readOnlyRootFilesystem: true
            runAsGroup: 1001
            runAsNonRoot: true
            runAsUser: 1001
            seLinuxOptions: {}
            seccompProfile:
              type: RuntimeDefault
          command:
            - /bin/bash
          args:
            - -c
            - /opt/bitnami/scripts/start-scripts/start-node.sh
          env:
            - name: BITNAMI_DEBUG
              value: "false"
            - name: REDIS_MASTER_PORT_NUMBER
              value: "6379"
            - name: ALLOW_EMPTY_PASSWORD
              value: "no"
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: browserstack-secret
                  key: redis-password
            - name: REDIS_MASTER_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: browserstack-secret
                  key: redis-password
            - name: REDIS_TLS_ENABLED
              value: "no"
            - name: REDIS_PORT
              value: "6379"
            - name: REDIS_SENTINEL_TLS_ENABLED
              value: "no"
            - name: REDIS_SENTINEL_PORT
              value: "26379"
            - name: REDIS_DATA_DIR
              value: /data
          ports:
            - name: redis
              containerPort: 6379
          startupProbe:
            failureThreshold: 22
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
            exec:
              command:
                - sh
                - -c
                - /health/ping_liveness_local.sh 5
          livenessProbe:
            initialDelaySeconds: 20
            periodSeconds: 5
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 5
            exec:
              command:
                - sh
                - -c
                - /health/ping_liveness_local.sh 5
          readinessProbe:
            initialDelaySeconds: 20
            periodSeconds: 5
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 5
            exec:
              command:
                - sh
                - -c
                - /health/ping_readiness_local.sh 1
          resources:
            limits:
              cpu: 512m
              ephemeral-storage: 2Gi
              memory: 256Mi
            requests:
              cpu: 256m
              ephemeral-storage: 50Mi
              memory: 128Mi
          volumeMounts:
            - name: start-scripts
              mountPath: /opt/bitnami/scripts/start-scripts
            - name: health
              mountPath: /health
            - name: sentinel-data
              mountPath: /opt/bitnami/redis-sentinel/etc
            - name: redis-data
              mountPath: /data
            - name: config
              mountPath: /opt/bitnami/redis/mounted-etc
            - name: empty-dir
              mountPath: /opt/bitnami/redis/etc
              subPath: app-conf-dir
            - name: empty-dir
              mountPath: /tmp
              subPath: tmp-dir
        - name: sentinel
          image: public.ecr.aws/v4a1k5d3/browserstack/turboscale-kafka-uploader:sentinel_7.4.1-debian-12-r3
          imagePullPolicy: "IfNotPresent"
          lifecycle:
            preStop:
              exec:
                command:
                  - /bin/bash
                  - -c
                  - /opt/bitnami/scripts/start-scripts/prestop-sentinel.sh
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
              - ALL
            readOnlyRootFilesystem: true
            runAsGroup: 1001
            runAsNonRoot: true
            runAsUser: 1001
            seLinuxOptions: {}
            seccompProfile:
              type: RuntimeDefault
          command:
            - /bin/bash
          args:
            - -c
            - /opt/bitnami/scripts/start-scripts/start-sentinel.sh
          env:
            - name: BITNAMI_DEBUG
              value: "false"
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: browserstack-secret
                  key: redis-password
            - name: REDIS_SENTINEL_TLS_ENABLED
              value: "no"
            - name: REDIS_SENTINEL_PORT
              value: "26379"
          ports:
            - name: redis-sentinel
              containerPort: 26379
          startupProbe:
            failureThreshold: 22
            initialDelaySeconds: 10
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 5
            exec:
              command:
                - sh
                - -c
                - /health/ping_sentinel.sh 5
          livenessProbe:
            initialDelaySeconds: 20
            periodSeconds: 10
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 6
            exec:
              command:
                - sh
                - -c
                - /health/ping_sentinel.sh 5
          readinessProbe:
            initialDelaySeconds: 20
            periodSeconds: 5
            timeoutSeconds: 1
            successThreshold: 1
            failureThreshold: 6
            exec:
              command:
                - sh
                - -c
                - /health/ping_sentinel.sh 1
          resources:
            limits:
              cpu: 512m
              ephemeral-storage: 2Gi
              memory: 256Mi
            requests:
              cpu: 256m
              ephemeral-storage: 50Mi
              memory: 128Mi
          volumeMounts:
            - name: empty-dir
              mountPath: /tmp
              subPath: tmp-dir
            - name: start-scripts
              mountPath: /opt/bitnami/scripts/start-scripts
            - name: health
              mountPath: /health
            - name: sentinel-data
              mountPath: /opt/bitnami/redis-sentinel/etc
            - name: redis-data
              mountPath: /data
            - name: config
              mountPath: /opt/bitnami/redis-sentinel/mounted-etc
      nodeSelector:
        kubernetes.io/os: linux
      volumes:
        - name: start-scripts
          configMap:
            name: turboscale-redis-scripts
            defaultMode: 493
        - name: health
          configMap:
            name: turboscale-redis-health
            defaultMode: 493
        - name: config
          configMap:
            name: turboscale-redis-configuration
        - name: sentinel-data
          emptyDir: {}
        - name: empty-dir
          emptyDir: {}
  volumeClaimTemplates:
    - apiVersion: v1
      kind: PersistentVolumeClaim
      metadata:
        name: redis-data
        labels:
          app.kubernetes.io/instance: turboscale
          app.kubernetes.io/name: redis
          app.kubernetes.io/component: node
      spec:
        storageClassName: <StorageClassName>
        accessModes:
          - ReadWriteOnce
        resources:
          limits:
            storage: 4Gi
          requests:
            storage: 1Gi