redisLabel="[Redis]" redisSentinelLabel="[RedisSentinel]" redisHaproxyLabel="[RedisHAProxy]" # Prepares Kubernetes secrets for Redis. function cmdRedisPreparation() { printInfo "$redisLabel Preparation..." local error runError error k3sRun delete secret "$redisKube-secret" --ignore-not-found || { printDanger "$redisLabel Delete old Secret: $error" return 1 } printInfo "$redisLabel Delete old Secret" runError error k3sRun create secret generic "$redisKube-secret" --from-literal=root-password="$redisRootPass" || { printDanger "$redisLabel Create new Secret: $error" return 1 } printInfo "$redisLabel Create new Secret" fileBackup "$redisPath/$redisFileUsersAcl" printSuccess "$redisLabel Preparatory completed" } # Renders the Redis Kubernetes YAML manifest via Helm. function cmdRedisYamlRender() { printInfo "$redisLabel Render YAML | Helm" local templateFile="templates/$redisKube.yaml" [[ -f "$appAssetsPath/k3s/$templateFile" ]] || { printDanger "$redisLabel Template YAML : File not found | $appAssetsPath/k3s/$templateFile" return 1 } printInfo "$redisLabel Template YAML : $appAssetsPath/k3s/$templateFile" local profileCpuFile="$appAssetsPath/k3s/profiles/cpu-$kubeCpuProfile.yaml" [[ -f "$profileCpuFile" ]] || { printDanger "$redisLabel CPU profile : File not found | $profileCpuFile" return 1 } printInfo "$redisLabel CPU profile : $profileCpuFile" local profileMemoryFile="$appAssetsPath/k3s/profiles/memory-$kubeMemoryProfile.yaml" [[ -f "$profileMemoryFile" ]] || { printDanger "$redisLabel Memory profile : File not found | $profileMemoryFile" return 1 } printInfo "$redisLabel Memory profile : $profileMemoryFile" local varsFile varsFile=$(mktemp "/tmp/$redisKube.vars.XXXXXX.yaml") || return 1 printInfo "$redisLabel Variables : $varsFile" trap 'rm -f -- "$varsFile"' RETURN cat > "$varsFile" < "$redisYaml" || { printDanger "$redisLabel Render failed" return 1 } printSuccess "$redisLabel Render completed" } # Installs Redis into Kubernetes. function cmdRedisInstall() { cmdRedisPreparation || return 1 cmdRedisYamlRender || return 1 cmdK3sYamlApplyEx "$redisYaml" } # Uninstalls Redis Kubernetes resources. function cmdRedisUninstall() { "$k3sCmd" kubectl delete -f "$redisYaml" } # local output error podList ver pid # if ! run podList error k3sPodListStatus "$openlitespeedKube"; then # printDanger "Get pods: $error" # elif [[ -z "$podList" ]]; then # printDanger "Pods not found" # else # while IFS='|' read -r pod phase; do # printSection "$pod" # if [[ "$phase" != "Running" ]]; then # printDot 60 "Phase" "$fontRed$phase$fontReset" # else # printDot 60 "Phase" "$fontGreen$phase$fontReset" # if ! run output error openlitespeedPodExec "$pod" /usr/local/lsws/bin/lswsctrl status; then # printDot 60 "Status" "$labelUnknown" # printDanger "$error" # elif [[ "$output" =~ "running" ]]; then # printDot 60 "OpenLiteSpeed status" "$fontGreen$output$fontReset" # else # printDot 60 "OpenLiteSpeed status" "$fontRed$output$fontReset" # fi # if run output error openlitespeedPodExec "$pod" /usr/local/lsws/bin/lshttpd -v; then # ver=$(awk 'NR==1{print $1, $2}' <<< "$output") # printDot 60 "OpenLiteSpeed version" "$ver" # else # printDot 60 "OpenLiteSpeed version" "$labelUnknown" # printDanger "$error" # fi # if run output error openlitespeedPodExec "$pod" php -r 'echo PHP_VERSION, "\n";'; then # printDot 60 "PHP version" "$output" # else # printDot 60 "PHP version" "$labelUnknown" # printDanger "$error" # fi # fi # done < <(awk 'NF' <<< "$podList") # fi # printRow # Prints replication INFO for all Redis and Sentinel pods. function cmdRedisInfo() { local output error podList ver pid if ! run podList error k3sPodListStatus "$redisKube"; then printDanger "Get pods: $error" elif [[ -z "$podList" ]]; then printDanger "Pods not found" else while IFS='|' read -r pod phase; do printSection "$pod" if [[ "$phase" != "Running" ]]; then printDot 60 "Phase" "$fontRed$phase$fontReset" else printDot 60 "Phase" "$fontGreen$phase$fontReset" if ! run output error redisPodExecCli "$pod" INFO server; then printDot 60 "Redis version" "$labelUnknown" printDanger "$error" else ver=$(printf '%s' "$output" | grep redis_version | cut -d ':' -f2 | tr -d '[:space:]') printDot 60 "Redis version" "$ver" fi if ! run output error redisPodExecCli "$pod" INFO replication; then printDot 60 "Redis version" "$labelUnknown" printDanger "$error" else local role slaves masterHost masterLinkStatus slaveLag role=$(printf '%s' "$output" | grep -i "role" | cut -d: -f2 | tr -d '\r\n') if [[ "$role" == "master" ]]; then printDot 60 "Replica role" "$fontGreen$role$fontReset" slaves=$(printf '%s' "$output" | grep -i "connected_slaves" | cut -d: -f2 | tr -d '\r\n') if [[ "$slaves" -eq 0 ]]; then printDot 60 "Slaves" "$fontRed$slaves$fontReset" else printDot 60 "Slaves" "$fontGreen$slaves$fontReset" fi elif [[ "$role" == "slave" ]]; then printDot 60 "Replica role" "$fontGreen$role$fontReset" masterHost=$(printf '%s' "$output" | grep -i "master_host" | cut -d: -f2 | tr -d '\r\n') masterLinkStatus=$(printf '%s' "$output" | grep -i "master_link_status" | cut -d: -f2 | tr -d '\r\n') if [[ -z "$masterHost" || "$masterLinkStatus" != "up" ]]; then [[ -z "$masterHost" ]] && printDot 60 "Master" "${fontRed}Not connect to master (master_host)$fontReset" [[ "$masterLinkStatus" != "up" ]] && printDot 60 "Master" "${fontRed}Not connect to master (master_link_status)$fontReset" continue fi printDot 60 "Master" "$fontGreen$masterHost$fontReset" slaveLag=$(printf '%s' "$output" | grep -i "master_last_io_seconds_ago" | cut -d: -f2 | tr -d '\r\n') [[ "$slaveLag" -ge 3 ]] && printDot 60 "Replication delay" "$fontYallow${slaveLag}s$fontReset" else printDot 60 "Replica role" "$fontRed$role$fontReset" fi fi fi done < <(awk 'NF' <<< "$podList") fi if ! run podList error k3sPodListStatus "$redisSentinelKube"; then printDanger "Get pods: $error" elif [[ -z "$podList" ]]; then printDanger "Pods not found" else local masterInfo slaveInfo local masterName masterIP masterPort masterNumOtherSentinels masterQuorum local masterSig replicaSig refPod refMasterSig refReplicaSig local activeReplicaCount mismatch=0 while IFS='|' read -r pod phase; do printSection "$pod" if [[ "$phase" != "Running" ]]; then printDot 60 "Phase" "$fontRed$phase$fontReset" else printDot 60 "Phase" "$fontGreen$phase$fontReset" if ! run output error redisPodExecCli "$pod" INFO server; then printDot 60 "RedisSentinel version" "$labelUnknown" printDanger "$error" else ver=$(printf '%s' "$output" | grep redis_version | cut -d ':' -f2 | tr -d '[:space:]') printDot 60 "RedisSentinel version" "$ver" fi run masterInfo error redisPodExecCli "$pod" SENTINEL masters || { printDot 60 "Get sentinel masters" "$labelFail" printDanger "$error" mismatch=1 continue } local -A masterData=() while read -r key && read -r value; do masterData["$key"]="$value" done <<< "$masterInfo" masterName="${masterData[name]}" masterIP="${masterData[ip]}" masterPort="${masterData[port]}" masterNumOtherSentinels="${masterData[num-other-sentinels]:-0}" masterQuorum="${masterData[quorum]:-0}" run slaveInfo error redisPodExecCli "$pod" --raw sentinel replicas "$masterName" || { printDot 60 "Get sentinel replicas" "$labelFail" printDanger "$error" mismatch=1 continue } replicaSig="$(redisSentinelParseReplicas "$slaveInfo" | awk 'NF' | sort)" activeReplicaCount="$(awk 'NF {c++} END {print c+0}' <<< "$replicaSig")" masterSig="${masterName}|${masterIP}|${masterPort}|${activeReplicaCount}|${masterNumOtherSentinels}|${masterQuorum}" refPod="" refMasterSig="" refReplicaSig="" if [[ -z "$refPod" ]]; then refPod="$pod" refMasterSig="$masterSig" refReplicaSig="$replicaSig" fi if [[ "$masterSig" != "$refMasterSig" || "$replicaSig" != "$refReplicaSig" ]]; then mismatch=1 printDot 60 "Topology" "mismatch vs $fontRed$refPod$fontReset" # else # printDot 60 "Topology" "matches $fontGreen$refPod$fontReset" fi printDot 60 " ┌ Replica" "$masterName" if (( masterQuorum < 1 )); then printDot 60 " ├ Quorum" "$fontRed$masterQuorum$fontReset" else printDot 60 " ├ Quorum" "$fontGreen$masterQuorum$fontReset" fi printDot 60 " ├ Other sentinels" "$masterNumOtherSentinels" # printDot 60 "Master" "$masterIP:$masterPort" printDot 60 " ├ Master" "$masterIP" if (( activeReplicaCount < 1 )); then printDot 60 " └ Slave count" "$fontRed$activeReplicaCount$fontReset" else printDot 60 " └ Slave count" "$fontGreen$activeReplicaCount$fontReset" fi while IFS=$'\t' read -r slaveName slaveIP slavePort slaveMaster slaveRunId; do [[ -z "$slaveName" ]] && continue printText " ┊" printDot 60 " ├ Slave" "$slaveIP" printDot 60 " ├ Master" "$slaveMaster" printDot 60 " └ RunID" "$slaveRunId" done <<< "$replicaSig" fi done < <(awk 'NF' <<< "$podList") fi if ! run podList error k3sPodListStatus "$redisKube-haproxy"; then printDanger "Get pods: $error" elif [[ -z "$podList" ]]; then printDanger "Pods not found" else while IFS='|' read -r pod phase; do printSection "$pod" if [[ "$phase" != "Running" ]]; then printDot 60 "Phase" "$fontRed$phase$fontReset" else printDot 60 "Phase" "$fontGreen$phase$fontReset" if ! run output error k3sRun exec "pod/$pod" -- haproxy -v; then printDot 60 "HAProxy version" "$labelUnknown" printDanger "$error" else ver=$(awk 'NR==1{print $3}' <<< "$output") printDot 60 "HAProxy version" "$ver" fi local role if ! run output error redisExecCli -h redis-master -p 6379 ROLE; then printDot 60 "Replica role" "$labelFail" printDanger "$error" else role=$(printf '%s' "$output" | head -n1 | tr -d '\r\n') if [[ "$role" != "master" ]]; then printDot 60 "Replica role" "$fontRed$role$fontReset" else printDot 60 "Replica role" "$fontGreen$role$fontReset" fi fi fi done < <(awk 'NF' <<< "$podList") fi printRow } # Checks replication role/health on each Redis pod and Sentinel topology consistency. function cmdRedisStatus() { local output error podList if ! run podList error k3sPodList "$redisKube"; then printDanger "$redisLabel Get pods: $error" elif [[ -z "$podList" ]]; then printDanger "$redisLabel Pods not found" else while read -r pod; do printSection "$pod" if run output error redisPodExecCli "$pod" INFO replication; then printText "$output" else printDanger "$redisLabel $pod | $error" fi done < <(awk 'NF' <<< "$podList") fi if ! run podList error k3sPodList "$redisSentinelKube"; then printDanger "$redisSentinelLabel Get pods: $error" elif [[ -z "$podList" ]]; then printDanger "$redisSentinelLabel Pods not found" else while read -r pod; do printSection "$pod" if run output error redisPodExecCli "$pod" INFO sentinel; then printText "$output" else printDanger "$redisSentinelLabel $pod | $error" fi done < <(awk 'NF' <<< "$podList") fi printRow } # Lists all Redis ACL users. function cmdRedisUser() { local output error printRow if ! run output error redisUserListGet; then printDanger "$error" elif [[ -z "$output" ]]; then printText "$labelNull" else printText "$output" fi printRow } # Flushes all keys from the Redis database. function cmdRedisDatabaseFlush() { local output error printRow if run output error redisDatabaseFlush; then printText "$output" else printDanger "$error" fi printRow } # Regenerates and applies the Redis root password across all nodes. function cmdRedisRootPassUpdate() { local output error printRow if run output error redisRootPassUpdate; then printText "$output" else printDanger "$error" fi printRow }