#!/bin/bash

# ============== Akka Cluster Administration Tool ==============
#
# This script is meant to be used from within the Akka distribution.
#
# Add these options to the sbt or startup script:
#   java \
#      -Dcom.sun.management.jmxremote.port=9999 \
#      -Dcom.sun.management.jmxremote.ssl=false \
#      -Dcom.sun.management.jmxremote.authenticate=false \
#      ...
# ==============================================================

# FIXME support authentication? if so add: -Dcom.sun.management.jmxremote.password.file=<path to file> AND tweak this script to support it (arg need 'user:passwd' instead of '-')

declare AKKA_HOME="$(cd "$(cd "$(dirname "$0")"; pwd -P)"/..; pwd)"

[ -n "$JMX_CLIENT_CLASSPATH" ] || JMX_CLIENT_CLASSPATH="$AKKA_HOME/lib/akka/akka-kernel*"

# NOTE: The 'cmdline-jmxclient' is available as part of the Akka distribution.
JMX_CLIENT="java -cp $JMX_CLIENT_CLASSPATH akka.jmx.Client -"

SELF=`basename $0` # script name
HOST=$1            # cluster node:port to talk to through JMX

function ensureNodeIsRunningAndAvailable {
    REPLY=$($JMX_CLIENT $HOST akka:type=Cluster Available 2>&1 >/dev/null) # redirects STDERR to STDOUT before capturing it
    if [[ "$REPLY" != *true ]]; then
        echo "Akka cluster node is not available on $HOST, due to $REPLY"
        exit 1
    fi
}

# switch on command
case "$2" in

    join)
        if [ $# -ne 3 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> join <node-url-to-join>"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        ACTOR_SYSTEM_URL=$2
        echo "$HOST is JOINING cluster node $ACTOR_SYSTEM_URL"
        $JMX_CLIENT $HOST akka:type=Cluster join=$ACTOR_SYSTEM_URL
        ;;

    leave)
        if [ $# -ne 3 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> leave <node-url-to-join>"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        ACTOR_SYSTEM_URL=$2
        echo "Scheduling $ACTOR_SYSTEM_URL to LEAVE cluster"
        $JMX_CLIENT $HOST akka:type=Cluster leave=$ACTOR_SYSTEM_URL
        ;;

    down)
        if [ $# -ne 3 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> down <node-url-to-join>"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        ACTOR_SYSTEM_URL=$2
        echo "Marking $ACTOR_SYSTEM_URL as DOWN"
        $JMX_CLIENT $HOST akka:type=Cluster down=$ACTOR_SYSTEM_URL
        ;;

    member-status)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> member-status"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Querying member status for $HOST"
        $JMX_CLIENT $HOST akka:type=Cluster MemberStatus
        ;;

    cluster-status)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> cluster-status"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Querying cluster status"
        $JMX_CLIENT $HOST akka:type=Cluster ClusterStatus
        ;;

    members)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> members"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Querying members"
        $JMX_CLIENT $HOST akka:type=Cluster Members
        ;;

    unreachable)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> unreachable"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Querying unreachable members"
        $JMX_CLIENT $HOST akka:type=Cluster Unreachable
        ;;

    leader)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> leader"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Checking leader status"
        $JMX_CLIENT $HOST akka:type=Cluster Leader
        ;;

    is-singleton)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> is-singleton"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Checking for singleton cluster"
        $JMX_CLIENT $HOST akka:type=Cluster Singleton
        ;;

    is-available)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname:jmx-port> is-available"
            exit 1
        fi

        ensureNodeIsRunningAndAvailable
        shift

        echo "Checking if member node on $HOST is AVAILABLE"
        $JMX_CLIENT $HOST akka:type=Cluster Available
        ;;

    *)
        printf "Usage: bin/$SELF <node-hostname:jmx-port> <command> ...\n"
        printf "\n"
        printf "Supported commands are:\n"
        printf "%26s - %s\n" "join <node-url>"   "Sends request a JOIN node with the specified URL"
        printf "%26s - %s\n" "leave <node-url>"  "Sends a request for node with URL to LEAVE the cluster"
        printf "%26s - %s\n" "down <node-url>"   "Sends a request for marking node with URL as DOWN"
        printf "%26s - %s\n" member-status       "Asks the member node for its current status"
        printf "%26s - %s\n" members             "Asks the cluster for addresses of current members"
        printf "%26s - %s\n" unreachable         "Asks the cluster for addresses of unreachable members"
        printf "%26s - %s\n" cluster-status      "Asks the cluster for its current status (member ring, unavailable nodes, meta data etc.)"
        printf "%26s - %s\n" leader              "Asks the cluster who the current leader is"
        printf "%26s - %s\n" is-singleton        "Checks if the cluster is a singleton cluster (single node cluster)"
        printf "%26s - %s\n" is-available        "Checks if the member node is available"
        printf "Where the <node-url> should be on the format of 'akka://actor-system-name@hostname:port'\n"
        printf "\n"
        printf "Examples: bin/$SELF localhost:9999 is-available\n"
        printf "          bin/$SELF localhost:9999 join akka://MySystem@darkstar:2552\n"
        printf "          bin/$SELF localhost:9999 cluster-status\n"
        exit 1
        ;;
esac
