# Shared support for MongoDB sharded-cluster scripts. # This file is sourced and should not itself be executed. . ./_mongodb_script_common.bash gs_mongodb_require_mode cluster gs_mongodb_require_command mongod gs_mongodb_require_command mongos gs_mongodb_require_command "$GS_MONGODB_SHELL" : "${GS_MONGODB_ROUTER_HOSTNAME:?Missing GS_MONGODB_ROUTER_HOSTNAME}" : "${GS_MONGODB_ROUTER_PORT:?Missing GS_MONGODB_ROUTER_PORT}" : "${GS_MONGODB_CONFIG_SERVER_HOSTNAME:?Missing GS_MONGODB_CONFIG_SERVER_HOSTNAME}" : "${GS_MONGODB_CONFIG_SERVER_PORT:?Missing GS_MONGODB_CONFIG_SERVER_PORT}" : "${GS_MONGODB_CONFIG_REPLSET:?Missing GS_MONGODB_CONFIG_REPLSET}" : "${GS_MONGODB_SHARD_PORT:?Missing GS_MONGODB_SHARD_PORT}" : "${GS_MONGODB_SHARD_REPLSET_PREFIX:?Missing GS_MONGODB_SHARD_REPLSET_PREFIX}" : "${GS_MONGODB_CLUSTER_HOME:?Missing GS_MONGODB_CLUSTER_HOME}" : "${GS_MONGODB_REMOTE_SOURCE_DIR:?Missing GS_MONGODB_REMOTE_SOURCE_DIR}" GS_MONGODB_START_TIMEOUT="${GS_MONGODB_START_TIMEOUT:-60}" GS_MONGODB_PRIMARY_TIMEOUT="${GS_MONGODB_PRIMARY_TIMEOUT:-60}" GS_MONGODB_CLUSTER_LOOPBACK_ADDRESS="${GS_MONGODB_CLUSTER_LOOPBACK_ADDRESS:-127.0.0.1}" GS_MONGODB_SSH_COMMAND="${GS_MONGODB_SSH_COMMAND:-ssh}" GS_MONGODB_SCP_COMMAND="${GS_MONGODB_SCP_COMMAND:-scp}" gs_mongodb_cluster_validate_port() { name=$1 port=$2 case "$port" in ''|*[!0-9]*) gs_mongodb_die "$name is not a numeric port: $port" ;; esac [ "$port" -ge 1 ] && [ "$port" -le 65535 ] || gs_mongodb_die "$name is outside the range 1-65535: $port" } gs_mongodb_cluster_short_hostname() { echo "${1%%.*}" } gs_mongodb_cluster_host_is_local() { configured_host=$1 configured_short=$(gs_mongodb_cluster_short_hostname "$configured_host") local_short=$(hostname -s 2>/dev/null || hostname) local_full=$(hostname -f 2>/dev/null || hostname) [ "$configured_host" = "$local_short" ] && return 0 [ "$configured_host" = "$local_full" ] && return 0 [ "$configured_short" = "$local_short" ] && return 0 # Also recognise a configured DNS alias that resolves to a local address. if command -v getent >/dev/null 2>&1; then configured_addresses=$(getent ahostsv4 "$configured_host" 2>/dev/null | awk '{print $1}' | sort -u) local_addresses="$(hostname -I 2>/dev/null || true) $(getent ahostsv4 "$local_short" 2>/dev/null | awk '{print $1}' || true) $(getent ahostsv4 "$local_full" 2>/dev/null | awk '{print $1}' || true)" for configured_address in $configured_addresses; do for local_address in $local_addresses; do [ "$configured_address" = "$local_address" ] && return 0 done done fi return 1 } gs_mongodb_cluster_shard_replset() { shard_index=$1 echo "${GS_MONGODB_SHARD_REPLSET_PREFIX}$((shard_index + 1))" } gs_mongodb_cluster_shard_host() { shard_index=$1 echo "${GS_MONGODB_SHARD_HOSTNAMES[$shard_index]}" } gs_mongodb_cluster_shard_connection() { shard_index=$1 shard_host=$(gs_mongodb_cluster_shard_host "$shard_index") shard_replset=$(gs_mongodb_cluster_shard_replset "$shard_index") echo "${shard_replset}/${shard_host}:${GS_MONGODB_SHARD_PORT}" } gs_mongodb_cluster_find_local_shard() { found_index=-1 for shard_index in "${!GS_MONGODB_SHARD_HOSTNAMES[@]}"; do if gs_mongodb_cluster_host_is_local "${GS_MONGODB_SHARD_HOSTNAMES[$shard_index]}"; then if [ "$found_index" -ne -1 ]; then gs_mongodb_die "The local machine appears more than once in GS_MONGODB_SHARD_HOSTNAMES." fi found_index=$shard_index fi done [ "$found_index" -ne -1 ] || return 1 echo "$found_index" } gs_mongodb_cluster_require_local_role() { role=$1 host=$2 if ! gs_mongodb_cluster_host_is_local "$host"; then gs_mongodb_die "This script is for the $role host '$host'; the current host is '$(hostname -s)'." fi } gs_mongodb_cluster_configdb() { echo "${GS_MONGODB_CONFIG_REPLSET}/${GS_MONGODB_CONFIG_SERVER_HOSTNAME}:${GS_MONGODB_CONFIG_SERVER_PORT}" } gs_mongodb_cluster_prepare_common_dirs() { mkdir -p \ "$GS_MONGODB_CLUSTER_HOME/config-server/data" \ "$GS_MONGODB_CLUSTER_HOME/config-server/log" \ "$GS_MONGODB_CLUSTER_HOME/config-server/run" \ "$GS_MONGODB_CLUSTER_HOME/router/log" \ "$GS_MONGODB_CLUSTER_HOME/router/run" } gs_mongodb_cluster_prepare_shard_dirs() { shard_index=$1 shard_number=$((shard_index + 1)) mkdir -p \ "$GS_MONGODB_CLUSTER_HOME/shards/shard-${shard_number}/data" \ "$GS_MONGODB_CLUSTER_HOME/shards/shard-${shard_number}/log" \ "$GS_MONGODB_CLUSTER_HOME/shards/shard-${shard_number}/run" } gs_mongodb_cluster_shell_eval() { host=$1 port=$2 javascript=$3 "$GS_MONGODB_SHELL" \ --quiet \ --host "$host" \ --port "$port" \ --eval "$javascript" } gs_mongodb_cluster_wait_for_ping() { description=$1 host=$2 port=$3 timeout=${4:-60} echo "Waiting for $description at $host:$port ..." elapsed=0 while [ "$elapsed" -lt "$timeout" ]; do if gs_mongodb_cluster_shell_eval \ "$host" "$port" \ 'quit(db.getSiblingDB("admin").runCommand({ping:1}).ok === 1 ? 0 : 1)' \ >/dev/null 2>&1 then echo "$description is accepting connections." return 0 fi sleep 1 elapsed=$((elapsed + 1)) done echo "Timed out waiting for $description at $host:$port." >&2 return 1 } gs_mongodb_cluster_wait_for_primary() { description=$1 host=$2 port=$3 timeout=${4:-60} echo "Waiting for $description to become PRIMARY ..." elapsed=0 while [ "$elapsed" -lt "$timeout" ]; do if gs_mongodb_cluster_shell_eval \ "$host" "$port" \ 'var s=db.getSiblingDB("admin").runCommand({isMaster:1}); quit(s.ismaster ? 0 : 1)' \ >/dev/null 2>&1 then echo "$description is PRIMARY." return 0 fi sleep 1 elapsed=$((elapsed + 1)) done echo "Timed out waiting for $description to become PRIMARY." >&2 return 1 } gs_mongodb_cluster_remote_run() { host=$1 script_name=$2 shift 2 if gs_mongodb_cluster_host_is_local "$host"; then (cd "$GS_MONGODB_SOURCE_HOME" && "./CLUSTER-SERVER/$script_name" "$@") return fi printf -v remote_dir_q '%q' "$GS_MONGODB_REMOTE_SOURCE_DIR" remote_command="cd $remote_dir_q && ./CLUSTER-SERVER/$script_name" for argument in "$@"; do printf -v argument_q '%q' "$argument" remote_command="$remote_command $argument_q" done "$GS_MONGODB_SSH_COMMAND" \ "${GS_MONGODB_SSH_OPTIONS[@]}" \ "$host" \ "$remote_command" } gs_mongodb_cluster_validate_configuration() { case "$GS_MONGODB_ROUTER_HOSTNAME $GS_MONGODB_CONFIG_SERVER_HOSTNAME ${GS_MONGODB_SHARD_HOSTNAMES[*]}" in *hostname-mongo-*) gs_mongodb_die "The cluster setup still contains hostname-mongo-* template values." ;; esac [ "${#GS_MONGODB_SHARD_HOSTNAMES[@]}" -gt 0 ] || gs_mongodb_die "GS_MONGODB_SHARD_HOSTNAMES must contain at least one hostname." gs_mongodb_cluster_validate_port GS_MONGODB_ROUTER_PORT "$GS_MONGODB_ROUTER_PORT" gs_mongodb_cluster_validate_port GS_MONGODB_CONFIG_SERVER_PORT "$GS_MONGODB_CONFIG_SERVER_PORT" gs_mongodb_cluster_validate_port GS_MONGODB_SHARD_PORT "$GS_MONGODB_SHARD_PORT" for first_index in "${!GS_MONGODB_SHARD_HOSTNAMES[@]}"; do first_host=${GS_MONGODB_SHARD_HOSTNAMES[$first_index]} [ -n "$first_host" ] || gs_mongodb_die "Shard hostname $((first_index + 1)) is empty." for second_index in "${!GS_MONGODB_SHARD_HOSTNAMES[@]}"; do [ "$second_index" -le "$first_index" ] && continue second_host=${GS_MONGODB_SHARD_HOSTNAMES[$second_index]} [ "$first_host" != "$second_host" ] || gs_mongodb_die "Shard hostname '$first_host' occurs more than once." done done } gs_mongodb_cluster_validate_configuration