#!/bin/bash

# ============== Apache Pekko Cluster Administration Tool ==============
#
# This script is meant to be used from within the Pekko 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 '-')



SELF=`basename $0` # script name
HOST=$1            # cluster node to talk to through JMX
PORT=$2
JMXSHJAR_NAME=jmxsh-R5.jar
JMXSHJAR=`dirname $0`/$JMXSHJAR_NAME

shift 2

JMX_CLIENT="java -jar $JMXSHJAR -h $HOST -p $PORT /dev/fd/0"


function mbeanObjectName() {
  if [[ -z "$CLUSTER_PORT" ]]; then
    echo "pekko:type=Cluster"
  else
    echo "pekko:type=Cluster,port=$CLUSTER_PORT"
  fi
}

function invoke() {
  echo jmx_invoke -m $(mbeanObjectName) "$@" | $JMX_CLIENT
}

function get() {
  echo "puts [jmx_get -m $(mbeanObjectName) \"$1\"]" | $JMX_CLIENT
}

function ensureNodeIsRunningAndAvailable {
    REPLY=$(get Available 2>&1) # redirects STDERR to STDOUT before capturing it
    if [[ "$REPLY" != *true ]]; then
        if [[ "$REPLY" == *"Cannot convert result to a string." ]]; then
          echo "Pekko cluster MBean is not available on $HOST:$PORT with MBean name '$(mbeanObjectName)'"
        else
          echo "Pekko cluster node is not available on $HOST:$PORT with MBean name '$(mbeanObjectName)', due to $REPLY"
        fi
        exit 1
    fi
}

function downloadJmxshR5IfNecessary() {
    if [ ! -f "$JMXSHJAR_NAME" ]; then
        echo "downloading $JMXSHJAR"
        curl https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/jmxsh/$JMXSHJAR_NAME -o $JMXSHJAR
    fi
}

echo "This jmx-client/pekko-cluster tool is deprecated; use curl and https://github.com/apache/pekko-management instead." >&2

# switch on command
while [ $# -gt 0 ];
do
  case "$1" in
    join)
        if [ $# -ne 2 ]; then
            echo "Usage: $SELF <node-hostname> <jmx-port> <optional: -p cluster-port> join <node-url-to-join>"
            exit 1
        fi

        downloadJmxshR5IfNecessary
        ACTOR_SYSTEM_URL=$2
        echo "$HOST is JOINING cluster node $ACTOR_SYSTEM_URL"
        invoke join $ACTOR_SYSTEM_URL
        shift 2
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable
        ACTOR_SYSTEM_URL=$2
        echo "Scheduling $ACTOR_SYSTEM_URL to LEAVE cluster"
        invoke leave $ACTOR_SYSTEM_URL
        shift 2
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        ACTOR_SYSTEM_URL=$2
        echo "Marking $ACTOR_SYSTEM_URL as DOWN"
        invoke down $ACTOR_SYSTEM_URL
        shift 2
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        echo "Querying member status for $HOST"
        get MemberStatus
        shift 1
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        get ClusterStatus
        shift 1
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        echo "Querying members"
        get Members
        shift 1
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        echo "Querying unreachable members"
        get Unreachable
        shift 1
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        echo "Checking leader status"
        get Leader
        shift 1
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        echo "Checking for singleton cluster"
        get Singleton
        shift 1
        ;;

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

        downloadJmxshR5IfNecessary
        ensureNodeIsRunningAndAvailable

        echo "Checking if member node on $HOST is AVAILABLE"
        get Available
        shift 1
        ;;

    -p)
        if [[ ! $2 =~ ^[0-9]+$ ]]; then
            echo "-p option requires a cluster port number in digits"
            exit 1
        fi

        CLUSTER_PORT=$2
        shift 2
        ;;
    *)
        printf "Usage: $0 <node-hostname> <jmx-port> <optional: -p cluster-port> <command> ...\n"
        printf "\n"
        printf "-p parameter needs is needed when cluster is run with pekko.cluster.jmx.multi-mbeans-in-same-jvm = on.¥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 'pekko.tcp://actor-system-name@hostname:port'\n"
        printf "\n"
        printf "Examples: $0 localhost 9999 is-available\n"
        printf "          $0 localhost 9999 join pekko.tcp://MySystem@darkstar:7355\n"
        printf "          $0 localhost 9999 cluster-status\n"
        printf "          $0 localhost 9999 -p 7354 is-available\n"
        printf "          $0 localhost 9999 -p 7354 join pekko.tcp://MySystem@darkstar:7355\n"
        printf "          $0 localhost 9999 -p 7354 cluster-status\n"
        exit 1
        ;;
esac
done
