#!/bin/sh -p
####################################################################
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP.
# (C) Copyright 2011-2015 Hewlett-Packard Development Company, L.P.
# @(#) Metrocluster with 3PAR Remote Copy utility script.
# @(#) Product Name                :  HP Metrocluster with 3PAR Remote Copy
# @(#) Product Version             :  A.12.00.30
# @(#) Patch Name                  :  
#
# *** Note: This file MUST NOT be edited. *****
#
# Any changes made to it will be overwritten when you upgrade to the
# next release of HP Metrocluster with 3PAR Remote Copy.
#
###################################################################
typeset cluster_nodes;
typeset snamelist
typeset hostlist
typeset platform
. /etc/cmcluster.conf

function get_platform
{
        uname=`uname`
        if [[ "$uname" = "Linux" ]]; then
                if [[ -e /etc/os-release ]]; then
                        /bin/cat /etc/os-release | /usr/bin/grep -q -i "suse" > /dev/null
                        if [[ $? -eq 0 ]]; then
                          distro="sles"
                        else
                          distro="redhat"
                        fi
                else
                        if [[ -e /etc/redhat-release ]]; then
                           distro="redhat"   
                        else
                           distro="sles"
                        fi
                fi
        else
                distro="hpux"
        fi
        echo "${distro}"
}

platform=`get_platform`
if [[ "$platform" = "redhat" ]];then
  sg_conf=/usr/local/cmcluster/conf/3parrc/
	cmviewcl_cmd=/usr/local/cmcluster/bin/cmviewcl
        cmexec_cmd=/usr/local/cmcluster/bin/cmexec
	ping_cmd=/bin/ping
	ping_switches="-c 1 -W 1"
elif [[ "$platform" = "sles" ]];then
  sg_conf=/opt/cmcluster/conf/3parrc/
	cmviewcl_cmd=/opt/cmcluster/bin/cmviewcl
	cmexec_cmd=/opt/cmcluster/bin/cmexec
	ping_cmd=/bin/ping
        ping_switches="-c 1 -W 1"
elif [[ "$platform" = "hpux" ]];then
  sg_conf=/opt/cmcluster/toolkit/SG3PARRC/
	cmviewcl_cmd=/usr/sbin/cmviewcl
	cmexec_cmd=/usr/sbin/cmexec
	ping_cmd=/usr/sbin/ping
	ping_switches="-n 1 -m 1"
fi


function Usage
{
   echo "
usage: $0 [-h] [-k {dsa|rsa}] {[user_name@storage_system_name]...}
  -h -- display this message.
  -k {dsa|rsa} -- type of keys rsa or dsa, the default is rsa.
  user_name@storage_system_name -- specifies a 3PAR storage user and storage system name or IP address.
"
  exit $FAILURE
}

# Internal wrapper for printing various types of messages.
function printme
{
   case $1 in
      E)
          printf "Error: $2\n"
          ;;
      F)
          printf "Failure: $2\n"
          ;;
      S)
          printf "Success: $2\n"
          ;;
      M)
          printf "$2\n"
          ;;
      D)
          $debug && printf "Debug: $2\n"
          ;;
   esac
}

# check if the usage is correct
function CheckUsage
{
    for j in $snamelist
    do
	suser=`echo $j | awk -F "@" '{print $1}'`
	sname=`echo $j | awk -F "@" '{print $2}'`
    done
    if [[ "$suser" = "" || "$sname" = "" ]]; then
	Usage
    fi

}

function checkandcreatepwf
{
    for i in $hostlist
    do 
        $cmexec_cmd $i mkdir -p ${sg_conf} > /dev/null 2>&1
        pwf=${sg_conf}${suser}_${sname}.pwf
		#to ensure in cae of upgrade and downgrade this check is required
        $cmexec_cmd $i ls ${pwf} > /dev/null 2>&1
        if [[ $? -ne 0 ]]; then
            $cmexec_cmd $i touch ${pwf} > /dev/null 2>&1
        fi
    done
    
}

# This quietly tests passwordless SSH 
function TestAccess
{
   typeset fn="TestAccess"
   typeset cmd
   typeset stat
   typeset host=$1
   typeset sdetails=$2
   typeset suser
   typeset sname
   suser=`echo $sdetails | awk -F "@" '{print $1}'`
   sname=`echo $sdetails | awk -F "@" '{print $2}'`
   printme D "Function: in $fn"
   
   # Add the shortname hostname to the known_hosts file.
   cmd="$cmexec_cmd $host ssh -l $suser $quiet $sshctout -o StrictHostKeyChecking=no $batchyes $sname showsshkey"
   printme D "TestAccess start."
   eval $cmd > /dev/null
   stat=$?
   printme D "TestAccess status (0 is good): $stat"
   printme D "TestAccess ended."

   printme D "Function: out $fn"

   return $stat
}

# Tests reachability using ping.
# This is a ping routine that we may use in the future.
function TestReachability
{
   typeset fn="TestReachability"
   typeset shost=$1
   typeset dhost=$2

   printme D "Function: in $fn"

   if [[ $shost != $lhost ]] ; then
      $cmexec_cmd $shost $ping_cmd $dhost $ping_switches > /dev/null
   elif [[ "$shost" = "$lhost" ]] ; then
      $ping_cmd $dhost $ping_switches > /dev/null
   fi
   [[ $? -ne $SUCCESS ]] && {
      printme D "$dhost is not reachable from $shost"
      return $FAILURE
     }
  
   printme D "Function: out $fn"

   return $SUCCESS
}

# Define Filenames prv pub files.
function DefineFilenames
{
   typeset fn="DefineFilenames"
   typeset dfprv=$1
   typeset dfpub=$2

   printme D "Function: in $fn"

   # Define the private filename.
   [[ -n "$dfprv" ]] && {
      gprivkeyfile=$gdfbase
      printme D "Private key file name is $gprivkeyfile"
   }

   # Define the public filename.
   [[ -n "$dfpub" ]] && {
      gpubkeyfile=$gdfbase.pub
      printme D "Public key file name is $gpubkeyfile"
   }

   printme D "Function: out $fn"
}

# Generate key pair and sets up access on the specified host.
function SetupSSHKeys
{
   typeset fn="SetupSSHKeys"
   typeset content
   typeset host=$1
   printme D "Function: in $fn"

   DefineFilenames prvf pubf 
   prvf=$gprivkeyfile
   pubf=$gpubkeyfile
      # Generate keys on local if needed.
      printme D "Base key file is $HOME/$prvf"
      [[ ! -f $HOME/$prvf ]] && {
         ssh-keygen $quiet -P "" -f $HOME/$prvf -t $gkeytype
         [[ $? -ne $SUCCESS ]] && {
            printme E "Unable to generate key pair on local host"
            return $FAILURE
         }
      }
    for i in $hostlist
    do
       if [[ $i != $lhost ]]; then    
          $cmexec_cmd $i "[ -f \$HOME/$prvf ] || /usr/bin/ssh-keygen $quiet -P \"\" -f $HOME/$prvf -t $gkeytype"
          [[ $? -ne $SUCCESS ]] && {
          printme D "Unable to generate key pair on $i"
          return $FAILURE
       }
       fi	
    done  

   printme D "Function: out $fn"

   return $SUCCESS
}

# Setup passwordless SSH so that
# each node should be able to talk to the storage system.
function SetupPasswordlessSSH
{
   typeset fn="SetupPasswordlessSSH"
   typeset i
   typeset j
   typeset sdetails=$1
   printme D "Function: in $fn"
   
   suser=`echo $sdetails | awk -F "@" '{print $1}'`
   sname=`echo $sdetails | awk -F "@" '{print $2}'`
     
   # Check if passwordless ssh is already set
   cmd_output=`ssh -l $suser $quiet $sshctout -o StrictHostKeyChecking=no $batchyes $sname showsshkey`
   if [[ $? -ne 0 ]]; then
      cmd="cat $HOME/$pubf | ssh -l $suser $sshctout -o StrictHostKeyChecking=no $sname setsshkey -add"
      printme D "SetAccess $lhost->$sdetails start."
      # Add the hostname public key to the storage system.
      printme M "If asked, enter password for $suser@$sname"
      eval $cmd > /dev/null
      stat=$?
      printme D "SetAccess status (0 is good): $stat"
      printme D "SetAccess  $lhost->$sdetails ended."
      if [[ $stat -eq 0 ]]; then
         printme M "Success: Passwordless SSH set from the host \"$lhost\" to the storage system \"$sname\" for the user \"$suser\""
      else
         printme M "Failed to set the passwordless SSH from the host \"$lhost\" to the storage system \"$sname\" for the user \"$suser\""
         return $stat
      fi
   else
      printme M "The passwordless SSH is sucessfully set from the host \"$lhost\" to the storage system \"$sname\" for the user \"$suser\""
   fi

   for i in $hostlist
   do
     if [[ $i != $lhost ]]; then
	cmd_output=`$cmexec_cmd $i ssh -l $suser $quiet $sshctout -o StrictHostKeyChecking=no $batchyes $sname showsshkey`
        if [[ $? -ne 0 ]]; then	
           cmd="$cmexec_cmd $i cat $HOME/$pubf | ssh -l $suser $sshctout -o StrictHostKeyChecking=no $sname setsshkey -add"
           printme D "SetAccess $i->$sdetails start."
           eval $cmd > /dev/null
           stat=$?
           printme D "SetAccess status (0 is good): $stat"
           printme D "SetAccess $i->$sdetails ended."
	   if [[ $stat -eq 0 ]]; then
	      printme M "Success: Passwordless SSH set from the host \"$i\" to the storage system \"$sname\" for the user \"$suser\""
	   else
	      printme M "Failed to set the passwordless SSH from the host \"$i\" to the storage system \"$sname\" for the user \"$suser\""
	      return $stat
	   fi
	else
	   printme M "The passwordless SSH is sucessfully set from the host \"$i\" to the storage system \"$sname\" for the user \"$suser\""
	fi
     fi
   done
   printme D "Function: out $fn"
   
   return $SUCCESS
}


# Do a comprehensive test of all nodes.
# Each node should be able to talk to every other node.
function SetupPasswordlessSSHAll
{
   typeset fn="SetupPasswordlessSSHAll"
   typeset i
   typeset j

   printme D "Function: in $fn"

   for j in $snamelist
      do
         SetupPasswordlessSSH $j
         if [[ $? -eq $SUCCESS ]] ; then
            printme D "Successfully set passwordless SSH to $j from all nodes"
         else
            printme D "Failed to set passwordless SSH to $j from one or more nodes"
         fi
      done
   checkandcreatepwf
   printme D "Function: out $fn"
}



# Do a comprehensive test of all nodes.
# Each node should be able to talk to every other node.
function TestThem
{
   typeset fn="TestThem"
   typeset i
   typeset j

   printme D "Function: in $fn"

   for i in $hostlist
   do
      for j in $snamelist
      do
         TestAccess $i $j
         if [[ $? -eq $SUCCESS ]] ; then
            printme S "$i -> $j"
         else
            printme F "$i -> $j"
         fi
      done
   done

   printme D "Function: out $fn"
}


# Do a reachability test of all nodes.
# Each node should be able to talk to every other node.
function TestReachabilityAll
{
   typeset fn="TestReachabilityAll"
   typeset i
   typeset j
   typeset retval=$SUCCESS

   printme D "Function: in $fn"

   for i in $hostlist
   do
      if [[ $i != $lhost ]]; then
         TestReachability $lhost $i
         if [[ $? -eq $SUCCESS ]] ; then
             printme D "Successfully pinged $i from $lhost ($lhost -> $i)"
         else
             printme E "Failed to ping $i from $lhost ($lhost -> $i)"
             retval=$FAILURE
         fi
      fi

      for j in $snamelist
      do
         sname=`echo $j | awk -F "@" '{print $2}'`
         TestReachability $i $sname
         if [[ $? -eq $SUCCESS ]] ; then
            printme D "Successfully pinged $sname from $i ($i -> $sname)"
         else
            printme E "Failed to ping $sname from $i ($i -> $sname)"
	    retval=$FAILURE
         fi
      done
   done
   printme D "Function: out $fn"
   return $retval
}


# Get cluster nodes
function GetClusterNodes
{

   if [ -f $SGCONF/cmclconfig ] && [ -s $SGCONF/cmclconfig ];   then
	if [[ -f ${cmviewcl_cmd} && -x ${cmviewcl_cmd} ]]; then
		cmview_output=$(${cmviewcl_cmd} -v -f line -s config -l node 2>&1)
		if [ $? -ne 0 ]; then
			printme E "cmviewcl command failed to run with the error: $cmview_output"
			return $FAILURE	
		fi
		cluster_nodes=`echo "$cmview_output" | awk -F "[:|=]" '(($1 == "node") && ($3 == "name")){print $4}'`
		return $SUCCESS
	else
		printme E "The command ${cmviewcl_cmd} is not accessible"

	fi

   else
	printme E "Node $lhost is not configured in a Serviceguard cluster"
	return $FAILURE
   fi

}


# Main
#
function Main
{
   # Local variables.
   typeset line
   typeset test_only=false
   

   # Global variables.
   typeset lhost
   typeset debug=false
   typeset gprivkeyfile
   typeset gpubkeyfile

   # General status.
   typeset -i SUCCESS=0
   typeset -i FAILURE=1

   # ssh client options
   typeset quiet="-q"
   typeset batchyes=" -o BatchMode=yes"

   # Create ssh variables to simplify usage.
   typeset sshctout="-o ConnectTimeout=1"

   # Key specific; default key type is rsa.
   typeset gkeytype=rsa
   typeset gdfbase=.ssh/id_rsa

   lhost=`hostname`
   if [[ $? -ne 0 ]]; then
      printme E "Failed to execute \"hostname\" command"
      exit $FAILURE	
   fi
   # Run through the menu options
   while getopts "k:dht" OPT; do
      case $OPT in
          k)
            gkeytype=$OPTARG
            # This tool supports both rsa and dsa key types.
            case $gkeytype in
               rsa)
                  # Already set as the default.
                  continue
                  ;;
               dsa)
                  gdfbase=.ssh/id_dsa
                  ;;
               *)
                  printme E "bad key type $OPTARG"
                  Usage
                  exit $FAILURE
                  ;;
               esac
            ;;

         # The testing and debug options are hidden features.
         t)
            test_only=true
            ;;
         d)
            debug=true
            ;;
         h)
            Usage
            ;;
         *)
            printme E "invalid option"
	    Usage	
            exit $FAILURE
            ;;
      esac
   done
   shift $(($OPTIND - 1))

   printme D "Function: in Main"

   # Get the arguments 
   snamelist=$@
   [[ -z "$snamelist" ]] && {
      Usage
   }
   CheckUsage

   if ! GetClusterNodes ; then
      printme E "Unable to get the cluster nodes "
      exit $FAILURE
   fi

   hostlist=$cluster_nodes
   $debug && for line in $hostlist; do printme D "$line is good host" ; done

#   if ! TestReachabilityAll ; then
#      printme E "One or more cluster nodes do not have access to storage system "
#      exit $FAILURE
#   fi

   # Support for a hidden feature.
   if $test_only ; then
      printme M "\nTesting..."
      TestThem $hostlist
      exit $SUCCESS
   fi

   # Set up the keys on the cluster nodes.
   if ! SetupSSHKeys ; then
      printme E "Unable to setup SSH keys on host systems"
      exit $FAILURE
   fi
   if ! SetupPasswordlessSSHAll ; then
      exit $FAILURE	
   fi

   printme D "Function: done Main"

   exit $SUCCESS
}

Main $@

