#!/bin/bash
set -eu
set -o pipefail

SCRIPT_NAME="$(basename $0)"

function show_options () {
    echo "Usage: ${SCRIPT_NAME} [options]"
    echo "Tells the local RabbitMQ to join the remote node's cluster."
    echo "Options:"
    echo "    --clean-on-error         - Attempts to clear down the local"
    echo "                               Mnesia database on failure to join"
    echo "                               a cluster, cleaning all persistent"
    echo "                               messages."
    echo "    --remote-node <NODENAME> - The Rabbit remote node name to use."
    echo "                               Defaults to rabbit."
    echo "    --remote-host <HOSTNAME> - The Rabbit remote host name to use."
    exit ${1}
}

# RabbitMQ database is tied to the system hostname.
LOCAL_HOST="$(hostname)"
CLEAN_ON_ERROR="0"
REMOTE_NODE="rabbit"
REMOTE_HOST=""

TEMP=$(getopt -o h -l help,remote-node:,remote-host:,clean-on-error -n "${SCRIPT_NAME}" -- "${@}")
[ ${?} -ne 0 ] && { echo "Terminating..." >&2; exit 1; };

# Note the quotes around "$TEMP": they are essential!
eval set -- "${TEMP}"

while true ; do
    case "${1}" in
        --clean-on-error) CLEAN_ON_ERROR="1"; shift ;;
        --remote-node) REMOTE_NODE="${2}"; shift 2 ;;
        --remote-host) REMOTE_HOST="${2}"; shift 2 ;;
        -h | --help) show_options 0 ;;
        --) shift ; break ;;
        *) echo "Error: unsupported option ${1}." >&2 ; exit 1 ;;
    esac
done


function join_cluster_with() {
    local remote_node="${1}"
    local remote_host="${2}"
    rabbitmqctl stop_app
    # If we are in the cluster already or have just joined we may need to
    # update our status to become running. In all error case we return true
    # so we can test the node cluster status later.
    { rabbitmqctl join_cluster "${remote_node}@${remote_host}" &&
        rabbitmqctl update_cluster_nodes "${remote_node}@${remote_host}"; } ||
        true
    rabbitmqctl start_app
}

[ -z "${REMOTE_HOST}" ] && { echo "Failed: A remote host must be given" >&2; exit 255; }

# Check not already clustered with the remote host.
if ! rabbitmq_is_in_cluster --check-host "${REMOTE_HOST}"; then
    { join_cluster_with "${REMOTE_NODE}" "${REMOTE_HOST}" &&
        rabbitmq_is_in_cluster --check-host "${REMOTE_HOST}"; } ||
        RET_VAL=${?}

    if [ ${RET_VAL:-0} -ne 0 ]; then
        echo "Failed to join host [${LOCAL_HOST}] with [${REMOTE_NODE}@${REMOTE_HOST}]..." >&2
        if [ ${CLEAN_ON_ERROR} -eq 1 ]; then
            # Try to leave the cluster gracefully and unregister with
            # REMOTE_HOST. This reset will try to inform the peers that we are
            # leaving. Even if this succeeds, we might be holding messages
            # from a corrupt remote node.
            rabbitmq_reset_node || true
            # Now we've at least tried to sync our messages out to the cluster,
            # simply wipe the DB. --force-reset does not communicate with the
            # peers about the node exiting cluster.
            rabbitmq_reset_node --force-reset || true
        fi
        exit ${RET_VAL}
    fi
fi
