#!/bin/bash

# Provide serial console access to nodes

# To handle cases like running this via sudo, get the home dir properly
os=`uname`
if [ "$os" == "Linux" ]; then 
    HOME=`getent passwd $(whoami)|cut -d: -f 6`
    export HOME
fi
if [ "$os" == "AIX" ]; then
    HOME=`lsuser -a home $(whoami)|cut -d= -f 2`
    export HOME
fi

if [ -z "$1" ] || [ "$1" = "-h"  ] || [ "$1" = "-help"  ] || [ "$1" = "--help"  ]; then
    echo "rcons - remotely accesses the serial console of a node"
    echo "rcons <singlenode> [conserver] [-f]"
    echo "rcons <singlenode> [conserver] [-s]"
    echo "rcons [-h|--help|-v|--version]"
    exit 0
fi
if [ "$1" = "-v" -o "$1" = "--version" ]; then
    if [ -z "$XCATROOT" ]; then
        XCATROOT="/opt/xcat"
    fi
    perl -e 'use lib "$ENV{XCATROOT}/lib/perl"; use xCAT::Version; print xCAT::Version->Version() . "\n"'
    exit 0
fi

if [ -n "$3" ] && [ "$3" = "-f" ]; then
    FORCE=-f
    CONSERVER=$2
fi

#console spy mode
if [ -n "$3" ] && [ "$3" = "-s" ]; then
    FORCE=-s
    CONSERVER=$2
fi

if [ -n "$2" ]; then
    if [ "$2" = "-f" ]; then
	FORCE=-f
    else
	if [ "$2" = "-s" ]; then
	    FORCE=-s
	else
	    CONSERVER=$2
	fi
    fi
fi

# xCAT 2.9.1 allows for an option to use confluent as a rcons replacement and only use
# confluent if this keyword is defined in the site table.  This allows for confluent to 
# be installed on the xCAT management node and switch between conserver & confluent
USE_CONFLUENT=0
CONSOLE_SERVICE_KEYWORD=`tabdump site | grep consoleservice | cut -d, -f1 | tr -d '"'`
CONSOLE_SERVICE_VALUE=`tabdump site | grep consoleservice | cut -d, -f2 | tr -d '"'`

if [ "$CONSOLE_SERVICE_KEYWORD" == "consoleservice" ]; then
    if [ "$CONSOLE_SERVICE_VALUE" == "confluent" ]; then
        USE_CONFLUENT=1
    fi
fi

if [ $USE_CONFLUENT == "1" ] && ([ -x "/opt/confluent/bin/confetty" ] || [ -x "/usr/bin/confetty" ] || [ -x "/usr/local/bin/confetty" ]); then
    # use confluent, make sure conserver is not also running
    CONSERVER_RC=`service conserver status >> /dev/null; echo $?`
    if [[ ${CONSERVER_RC} == 0 ]]; then 
        echo "Error: consoleservice is set to 'confluent' but conserver is running.  Stop conserver, run makeconfluentcfg, and retry..."
        exit 1
    fi
    CONFETTY="confetty"
    if [ -x "/opt/confluent/bin/confetty" ]; then
	CONFETTY="/opt/confluent/bin/confetty"
    fi
    if [ ! -z "$CONSCONTROLPATH" ]; then
        CONSCONTROLPATH="-c $CONSCONTROLPATH"
    fi
    if [ -z "$CONSERVER" ]; then
        CONSERVER=`nodels $1 nodehm.conserver 2>/dev/null | awk -F: '{print $2}' | tr -d ' '`
        declare -a ipaddrs=`ip addr | grep 'inet' | awk {'print $2'} | cut -d/ -f1 | grep -v : | tr '\n' ' '`
        for IP in ${ipaddrs[*]}; do 
            if [[ "${CONSERVER}" == "${IP}" ]]; then 
                # conserver is the same node, do not connect using -s
                CONSERVER=""
                break
            fi
        done
    fi
    if [ -z "$CONSERVER" ]; then
	CONSERVER=$XCATHOST
    fi
    if [ ! -z "$CONSERVER" ]; then
	CONSERVER="-s $CONSERVER"
    fi
    $CONFETTY $CONSCONTROLPATH $CONSERVER  $1
elif [ -f "/usr/bin/console" ] || [ -f "/bin/console" ]; then
    # use conserver
    # make sure confluent is not also running, only if confluent is installed
    if [[ -f "/etc/init.d/confluent" ]]; then 
        CONFLUENT_RC=`service confluent status >> /dev/null; echo $?`
        if [[ ${CONFLUENT_RC} == 0 ]]; then 
            echo "Error: consoleservice is set to 'conserver' but confluent is running.  Stop confluent, run makeconservercf, and retry..."
            exit 1
        fi
    fi

    if [ -z "$CONSERVER" ]; then
        CONSERVER=`nodels $1 nodehm.conserver 2>/dev/null | awk -F: '{print $2}' | tr -d ' '`
    fi
    
    if [ -z "$CONSERVER" ]; then
	CONSERVER=$XCATHOST
    fi
    if [ -z "$CONSERVER" ]; then
	CONSERVER=localhost
    fi
    #NOTE: IPv6 is not good with the below if going by IP, needs more sophisticated
    #parsing
    CONSERVER=`echo $CONSERVER|cut -d: -f 1`

    #Detect console support of SSL, only fixup consolerc if encryption is detected
    if ! console -h 2>&1 | grep "encryption not compiled" > /dev/null; then
        # generate .consolerc if it does not exist or is empty
        if [ ! -s $HOME/.consolerc ]; then
            cat > $HOME/.consolerc << EOF
config * {
      port 782;
      sslenabled yes;
      sslauthority $HOME/.xcat/ca.pem;
      sslcredentials $HOME/.xcat/client-cred.pem;
}
EOF
        fi
    else
        # ssl is not enabled, comment out the ssl settings in .consolerc
	if [ -f $HOME/.consolerc ]; then
            sed -i 's/\Wssl/#ssl/1' $HOME/.consolerc
	fi
    fi

    exec console $FORCE -M $CONSERVER $1
else 
    if [[ "$FORCE" == "-s" ]]; then
	echo "Read-only mode is not supported, please run rcons without -s option."
	exit 1
    fi
    #deal with consoles directly
    output=`nodels $1 nodehm.conserver nodehm.cons nodehm.mgt 2>&1` 
    if [ $? -ne 0 ]; then
	echo "$output"
	exit 1
    fi 

    if [ -z "$CONSERVER" ]; then  
	CONSERVER=`echo "$output"|grep nodehm.conserver|cut -d: -f3|tr -d ' \n'`
    fi
    CONS=`echo "$output" |grep /nodehm.cons$/|cut -d: -f3 | tr -d ' \n'`
    if [ -z "$CONS" ]; then
	CONS=`echo "$output"|grep nodehm.mgt|cut -d: -f3 | tr -d ' \n'`
    fi
    if [ -z "$CONS" ]; then
	echo "Error: nodehm.mgt or nodehm.cons for node $1 not setup."
	exit 1;
    fi
    
    #check if conserver is local host
    result=`ping -c1 $CONSERVER 2>&1`
    if [ $? -eq 0 ]; then
        index1=`expr index "$result" "\("`
        index2=`expr index "$result" "\)"`
        pos=`expr $index1 + 1`
        length=`expr $index2 - $index1`
        length=`expr $length - 1`
        cons_ip=`expr substr "$result" $pos $length`
        if [ "$os" == "AIX" ]; then
          ifconfig |grep "$cons_ip"
        else
          ip addr |grep "$cons_ip"
        fi
        if [ $? -eq 0 ]; then
           CONSERVER=""
        fi
    else 
	echo "Error: conserver $CONSERVER is not reachable."
        exit 1;
    fi
    #echo "CONS=$CONS CONSERVER=$CONSERVER"

    # check if others are using the console
    if [[ -n $CONSERVER ]]; then
        ssh $CONSERVER ps -ef |grep $1 |grep -v grep |grep "$XCATROOT/share/xcat/cons" > /dev/null
    else 
        ps -ef |grep $1 |grep -v grep |grep "$XCATROOT/share/xcat/cons" > /dev/null
    fi
    if [ $? -eq 0 ]; then
        if [[ "$FORCE" == "-f" ]] ; then
           echo "Only one console can be run at a time for a node. Other consoles will be closed."
        else
           echo "Only one console can be run at a time for a node. Please close other consoles or run rcons with -f option."
           exit 1;
        fi
    fi

    echo "**** Enter ~? for help *****"
    if [ -z "$XCATROOT" ]; then
        cmdpath="/opt/xcat/share/xcat/cons"	
    else
        cmdpath="$XCATROOT/share/xcat/cons"
    fi
    if [ -z "$CONSERVER" ]; then
        exec $cmdpath/$CONS $1
    else
        exec ssh -t  $CONSERVER "$cmdpath/$CONS $1"
    fi
fi
