mirror of https://github.com/apache/lucene.git
166 lines
4.5 KiB
Bash
166 lines
4.5 KiB
Bash
|
#!/bin/bash
|
||
|
#
|
||
|
# A helper script to wait for ZooKeeper
|
||
|
#
|
||
|
# This script waits for a ZooKeeper master to appear.
|
||
|
# It repeatedly looks up the name passed as argument
|
||
|
# in the DNS using getent, and then connects to the
|
||
|
# ZooKeeper admin port and uses the 'srvr' command to
|
||
|
# obtain the server's status.
|
||
|
# You can use this in a Kubernetes init container to
|
||
|
# delay Solr pods starting until the ZooKeeper service
|
||
|
# has settled down. Or you could explicitly run this in
|
||
|
# the Solr container before exec'ing Solr.
|
||
|
#
|
||
|
# Inspired by https://github.com/helm/charts/blob/9eba7b1c80990233a68dce48f4a8fe0baf9b7fa5/incubator/solr/templates/statefulset.yaml#L60
|
||
|
#
|
||
|
# Usage: wait-for-zookeeper.sh [--max-attempts count] [--wait-seconds seconds] zookeeper-service-name
|
||
|
#
|
||
|
# If no argument is provided, but a Solr-style ZK_HOST is set,
|
||
|
# that will be used. If neither is provided, the default
|
||
|
# name is 'solr-zookeeper-headless', to match the helm chart.
|
||
|
|
||
|
set -euo pipefail
|
||
|
|
||
|
SCRIPT="$0"
|
||
|
|
||
|
if [[ "${VERBOSE:-}" == "yes" ]]; then
|
||
|
set -x
|
||
|
fi
|
||
|
|
||
|
function usage {
|
||
|
echo "$1"
|
||
|
echo "Usage: $SCRIPT [--max-attempts count] [--wait-seconds seconds ] zookeeper-service-name"
|
||
|
exit 1
|
||
|
}
|
||
|
|
||
|
TMP_HOSTS="/tmp/hosts.$$"
|
||
|
TMP_STATUS="/tmp/status.$$"
|
||
|
|
||
|
function cleanup {
|
||
|
rm -f $TMP_HOSTS $TMP_STATUS
|
||
|
}
|
||
|
|
||
|
trap cleanup EXIT
|
||
|
|
||
|
function check_zookeeper {
|
||
|
local host=$1
|
||
|
local port="${2:-2181}"
|
||
|
if ! echo srvr | nc "$host" "$port" > $TMP_STATUS; then
|
||
|
echo "Failed to get status from $host"
|
||
|
return
|
||
|
fi
|
||
|
if [ ! -s $TMP_STATUS ]; then
|
||
|
echo "No data from $ip"
|
||
|
return
|
||
|
fi
|
||
|
if grep -q 'not currently serving requests' $TMP_STATUS; then
|
||
|
echo "Node $ip is not currently serving requests"
|
||
|
return
|
||
|
fi
|
||
|
mode=$(grep "Mode: " $TMP_STATUS | sed 's/Mode: //');
|
||
|
if [ -z "$mode" ]; then
|
||
|
echo "Cannot determine mode from:"
|
||
|
cat $TMP_STATUS
|
||
|
return
|
||
|
fi
|
||
|
echo "Node $ip is a $mode"
|
||
|
if [ "$mode" = "leader" ] || [ "$mode" = "standalone" ]; then
|
||
|
echo "Done"
|
||
|
exit 0
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
max_attempts=120
|
||
|
wait_seconds=2
|
||
|
while (( $# > 0 )); do
|
||
|
case "$1" in
|
||
|
--help)
|
||
|
cat <<EOM
|
||
|
Usage: $SCRIPT [options] zookeeper-service-name
|
||
|
|
||
|
Options:
|
||
|
--max-attempts count: number of attempts to check Solr is up. Default: $max_attempts
|
||
|
--wait-seconds seconds: number of seconds to wait between attempts. Default: $wait_seconds
|
||
|
EOM
|
||
|
exit 0
|
||
|
;;
|
||
|
|
||
|
--max-attempts)
|
||
|
max_attempts="$2";
|
||
|
shift 2;
|
||
|
;;
|
||
|
|
||
|
--wait-seconds)
|
||
|
wait_seconds="$2";
|
||
|
shift 2;
|
||
|
;;
|
||
|
|
||
|
*)
|
||
|
if [ -n "${lookup_arg:-}" ]; then
|
||
|
usage "Cannot specify multiple zookeeper service names"
|
||
|
fi
|
||
|
lookup_arg=$1;
|
||
|
shift;
|
||
|
break;
|
||
|
;;
|
||
|
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
grep -q -E '^[0-9]+$' <<<"$max_attempts" || usage "--max-attempts $max_attempts: not a number"
|
||
|
if (( max_attempts == 0 )); then
|
||
|
echo "The --max-attempts argument should be >0"
|
||
|
exit 1
|
||
|
fi
|
||
|
grep -q -E '^[0-9]+$' <<<"$wait_seconds" || usage "--wait-seconds $wait_seconds: not a number"
|
||
|
|
||
|
if [ -z "${lookup_arg:-}" ]; then
|
||
|
if [ -n "$ZK_HOST" ]; then
|
||
|
lookup_arg="$ZK_HOST"
|
||
|
else
|
||
|
lookup_arg=solr-zookeeper-headless
|
||
|
fi
|
||
|
fi
|
||
|
|
||
|
echo "Looking up '$lookup_arg'"
|
||
|
# split on commas, for when a ZK_HOST string like zoo1:2181,zoo2:2181 is used
|
||
|
IFS=',' read -ra lookups <<< "$lookup_arg"
|
||
|
((attempts_left=max_attempts))
|
||
|
while (( attempts_left > 0 )); do
|
||
|
for lookup in "${lookups[@]}"; do
|
||
|
if grep -q -E "^\[[0-9].*\]" <<<"$lookup"; then
|
||
|
# looks like an IPv6 address, eg [2001:DB8::1] or [2001:DB8::1]:2181
|
||
|
# getent does not support the bracket notation, but does support IPv6 addresses
|
||
|
host=$(sed -E 's/\[(.*)\].*/\1/' <<<"$lookup")
|
||
|
port=$(sed -E 's/^\[(.*)\]:?//' <<<"$lookup")
|
||
|
else
|
||
|
# IPv4, just split on :
|
||
|
IFS=: read -ra split <<<"$lookup"
|
||
|
host="${split[0]}"
|
||
|
port="${split[1]:-}"
|
||
|
fi
|
||
|
if [[ "${VERBOSE:-}" == "yes" ]]; then
|
||
|
echo "Parsed host=$host port=${port:-}"
|
||
|
fi
|
||
|
if getent hosts "$host" > $TMP_HOSTS; then
|
||
|
while read -r ip hostname ; do
|
||
|
echo "${hostname:-}">/dev/null # consume for shellcheck
|
||
|
check_zookeeper "$ip" "$port"
|
||
|
done <$TMP_HOSTS
|
||
|
else
|
||
|
echo "Cannot find $lookup yet"
|
||
|
fi
|
||
|
done
|
||
|
(( attempts_left-- ))
|
||
|
if (( attempts_left == 0 )); then echo "Still no master found; giving up"
|
||
|
exit 1
|
||
|
fi
|
||
|
sleep "$wait_seconds"
|
||
|
done
|
||
|
|
||
|
# To test the parsing:
|
||
|
# bash scripts/wait-for-zookeeper.sh foo
|
||
|
# bash scripts/wait-for-zookeeper.sh 'ZK_HOST=[2001:DB8::1]:2181,[2001:DB8::1],127.0.0.1:2181,127.0.0.2'
|
||
|
# ZK_HOST=[2001:DB8::1]:2181,[2001:DB8::1],127.0.0.1:2181,127.0.0.2 bash scripts/wait-for-zookeeper.sh
|