-
Notifications
You must be signed in to change notification settings - Fork 19
/
README.md
228 lines (207 loc) · 6.81 KB
/
README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#!/bin/bash
#
# Bitnami Redis Cluster library
# shellcheck disable=SC1091
# shellcheck disable=SC2178
# shellcheck disable=SC2128
# shellcheck disable=SC1090
# Load Generic Libraries
. /opt/bitnami/scripts/libfile.sh
. /opt/bitnami/scripts/libfs.sh
. /opt/bitnami/scripts/liblog.sh
. /opt/bitnami/scripts/libnet.sh
. /opt/bitnami/scripts/libos.sh
. /opt/bitnami/scripts/libservice.sh
. /opt/bitnami/scripts/libvalidations.sh
. /opt/bitnami/scripts/libredis.sh
# Functions
########################
# Load global variables used on Redis configuration.
# Globals:
# REDIS_*
# Arguments:
# None
# Returns:
# Series of exports to be used as 'eval' arguments
#########################
redis_cluster_env() {
cat <<"EOF"
export REDIS_BASEDIR="/opt/bitnami/redis"
export REDIS_EXTRAS_DIR="/opt/bitnami/extra/redis"
export REDIS_VOLUME="/bitnami/redis"
export REDIS_TEMPLATES_DIR="${REDIS_EXTRAS_DIR}/templates"
export REDIS_TMPDIR="${REDIS_BASEDIR}/tmp"
export REDIS_LOGDIR="${REDIS_BASEDIR}/logs"
export PATH="${REDIS_BASEDIR}/bin:$PATH"
export REDIS_DAEMON_USER="redis"
export REDIS_DAEMON_GROUP="redis"
export REDIS_DISABLE_COMMANDS="${REDIS_DISABLE_COMMANDS:-}"
export POD_NAME="${POD_NAME:-}"
export REDIS_PORT="${REDIS_PORT:-6379}"
export REDIS_CLUSTER_CREATOR="${REDIS_CLUSTER_CREATOR:-no}"
export REDIS_CLUSTER_REPLICAS="${REDIS_CLUSTER_REPLICAS:-1}"
export REDIS_NODES="${REDIS_NODES:-}"
export REDIS_PASSWORD="${REDIS_PASSWORD:-}"
export REDIS_CLUSTER_DYNAMIC_IPS="${REDIS_CLUSTER_DYNAMIC_IPS:-yes}"
export REDIS_CLUSTER_ANNOUNCE_IP="${REDIS_CLUSTER_ANNOUNCE_IP:-}"
export REDIS_DNS_RETRIES="${REDIS_DNS_RETRIES:-120}"
export ALLOW_EMPTY_PASSWORD="${ALLOW_EMPTY_PASSWORD:-no}"
EOF
if [[ -f "${REDIS_PASSWORD_FILE:-}" ]]; then
cat <<"EOF"
export REDIS_PASSWORD="$(< "${REDIS_PASSWORD_FILE}")"
EOF
fi
}
########################
# Validate settings in REDIS_* env vars.
# Globals:
# REDIS_*
# Arguments:
# None
# Returns:
# None
#########################
redis_cluster_validate() {
debug "Validating settings in REDIS_* env vars.."
local error_code=0
# Auxiliary functions
print_validation_error() {
error "$1"
error_code=1
}
empty_password_enabled_warn() {
warn "You set the environment variable ALLOW_EMPTY_PASSWORD=${ALLOW_EMPTY_PASSWORD}. For safety reasons, do not use this flag in a production environment."
}
empty_password_error() {
print_validation_error "The $1 environment variable is empty or not set. Set the environment variable ALLOW_EMPTY_PASSWORD=yes to allow the container to be started with blank passwords. This is recommended only for development."
}
if is_boolean_yes "$ALLOW_EMPTY_PASSWORD"; then
empty_password_enabled_warn
else
if ! is_boolean_yes "$REDIS_CLUSTER_CREATOR"; then
[[ -z "$REDIS_PASSWORD" ]] && empty_password_error REDIS_PASSWORD
fi
fi
if ! is_boolean_yes "$REDIS_CLUSTER_DYNAMIC_IPS"; then
if ! is_boolean_yes "$REDIS_CLUSTER_CREATOR"; then
[[ -z "$REDIS_CLUSTER_ANNOUNCE_IP" ]] && print_validation_error "To provide external access you need to provide the REDIS_CLUSTER_ANNOUNCE_IP env var"
fi
fi
[[ -z "$REDIS_NODES" ]] && print_validation_error "REDIS_NODES is required"
if [[ -z "$REDIS_PORT" ]]; then
print_validation_error "REDIS_PORT cannot be empty"
fi
if is_boolean_yes "$REDIS_CLUSTER_CREATOR"; then
[[ -z "$REDIS_CLUSTER_REPLICAS" ]] && print_validation_error "To create the cluster you need to provide the number of replicas"
fi
[[ "$error_code" -eq 0 ]] || exit "$error_code"
}
########################
# Redis specific configuration to override the default one
# Globals:
# REDIS_*
# Arguments:
# None
# Returns:
# None
#########################
redis_cluster_override_conf() {
# Redis configuration to override
redis_conf_set daemonize no
redis_conf_set cluster-enabled yes
redis_conf_set cluster-config-file "${REDIS_VOLUME}/data/nodes.conf"
if ! (is_boolean_yes "$REDIS_CLUSTER_DYNAMIC_IPS" || is_boolean_yes "$REDIS_CLUSTER_CREATOR"); then
redis_conf_set cluster-announce-ip "$REDIS_CLUSTER_ANNOUNCE_IP"
fi
}
########################
# Ensure Redis is initialized
# Globals:
# REDIS_*
# Arguments:
# None
# Returns:
# None
#########################
redis_cluster_initialize() {
redis_configure_default
redis_cluster_override_conf
}
########################
# Creates the Redis cluster
# Globals:
# REDIS_*
# Arguments:
# - $@ Array with the hostnames
# Returns:
# None
#########################
redis_cluster_create() {
local nodes=("$@")
local ips=()
for node in "${nodes[@]}"; do
while [[ $(redis-cli -h "$node" -p "$REDIS_PORT" ping) != 'PONG' ]]; do
echo "Node $node not ready, waiting for all the nodes to be ready..."
sleep 1
done
ips=($(dns_lookup "$node") "${ips[@]}")
done
redis-cli --cluster create "${ips[@]/%/:${REDIS_PORT}}" --cluster-replicas "$REDIS_CLUSTER_REPLICAS" --cluster-yes || true
if redis_cluster_check "${ips[0]}"; then
echo "Cluster correctly created"
else
echo "The cluster was already created, the nodes should have recovered it"
fi
}
#########################
## Checks if the cluster state is correct.
## Params:
## - $1: node where to check the cluster state
#########################
redis_cluster_check() {
local -r check=$(redis-cli --cluster check "$1":"$REDIS_PORT")
if [[ $check =~ "All 16384 slots covered" ]]; then
true
else
false
fi
}
#########################
## Recovers the cluster when using dynamic IPs by changing them in the nodes.conf
# Globals:
# REDIS_*
# Arguments:
# None
# Returns:
# None
#########################
redis_cluster_update_ips() {
IFS=' ' read -ra nodes <<< "$REDIS_NODES"
declare -A host_2_ip_array # Array to map hosts and IPs
# Update the IPs when a number of nodes > quorum change their IPs
if [[ ! -f "${REDIS_VOLUME}/data/nodes.sh" ]]; then
# It is the first initialization so store the nodes
for node in "${nodes[@]}"; do
ip=$(wait_for_dns_lookup "$node" "$REDIS_DNS_RETRIES" 5)
host_2_ip_array["$node"]="$ip"
done
echo "Storing map with hostnames and IPs"
declare -p host_2_ip_array > "${REDIS_VOLUME}/data/nodes.sh"
else
# The cluster was already started
. "${REDIS_VOLUME}/data/nodes.sh"
# Update the IPs in the nodes.conf
for node in "${nodes[@]}"; do
newIP=$(wait_for_dns_lookup "$node" "$REDIS_DNS_RETRIES" 5)
# The node can be new if we are updating the cluster, so catch the unbound variable error
if [[ ${host_2_ip_array[$node]+true} ]]; then
echo "Changing old IP ${host_2_ip_array[$node]} by the new one ${newIP}"
nodesFile=$(sed "s/${host_2_ip_array[$node]}/$newIP/g" "${REDIS_VOLUME}/data/nodes.conf")
echo "$nodesFile" > "${REDIS_VOLUME}/data/nodes.conf"
fi
host_2_ip_array["$node"]="$newIP"
done
declare -p host_2_ip_array > "${REDIS_VOLUME}/data/nodes.sh"
fi
}