#!/usr/bin/env bash
# $Id$
#
# Thomas Dreibholz's PlanetLab Script Collection
# Copyright (C) 2005-2022 by Thomas Dreibholz
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Contact: network@iem.uni-due.de


if [ -e ./servicecontrol ] ; then
   SERVICE_CONTROL_CMD=./servicecontrol
elif [ -e ../../servicecontrol ] ; then
   SERVICE_CONTROL_CMD=../../servicecontrol
else
   echo >&2 "ERROR: servicecontrol not found!"
   exit 1
fi
if [ -e ./ssh-tool ] ; then
   SSH_TOOL_CMD=./ssh-tool
elif [ -e ../../ssh-tool ] ; then
   SSH_TOOL_CMD=../../ssh-tool
else
   echo >&2 "ERROR: ssh-tool not found!"
   exit 1
fi


check_variable ()
{
   if [ "$1" = "" ] ; then
      echo >&2 "ERROR: Variable $1 is not set!"
      exit 1
   fi
   echo "   $1=$2"
}


# echo "==== TEST ONLY ==== !!!!!!!!!!!!!!!!!!!!"
# SSH_USER="dreibh"
# SSH_KEY="/home/dreibh/.ssh/test-key"
# SERVICE_DIRECTORY="src/rsplib2/rsplib"
# SERVICE_PRE_PROGRAM=""
# OPT_CSP="-cspserver=127.0.0.1:2960 -cspinterval=1000"
#
# PRNodeList="localhost"
# PENodeList="localhost"
# PUNodeList="localhost"
# AttackerNodeList="localhost"
#
# PortBase=0
# Measurement=Test
# Duration=15
# PRs=3
# PEs=3
# PUs=3
# Policy=RoundRobin
# MaxBadPEReports=3
# MaxHRRate=-1
# MaxEURate=-1
# Capacity=1000000
# ReregInterval=30000
# JobInterval=60.0
# JobSize=10000000
# Attackers=1
# AttackType=handleresolution
# AttackInterval=50
# AttackIdentifier=0
# AttackReportUnreachableProbability=1.0
# echo "==== TEST ONLY ==== !!!!!!!!!!!!!!!!!!!!"


check_variable SSH_USER $SSH_USER
check_variable SSH_KEY $SSH_KEY
check_variable SERVICE_DIRECTORY $SERVICE_DIRECTORY
check_variable SERVICE_PRE_PROGRAM $SERVICE_PRE_PROGRAM

check_variable PRNodeList $PRNodeList
check_variable PENodeList $PENodeList
check_variable PUNodeList $PUNodeList
check_variable AttackerNodeList $AttackerNodeList

check_variable PortBase

check_variable Measurement $Measurement
check_variable Duration $Duration
check_variable PRs $PRs
check_variable PEs $PEs
check_variable PUs $PUs
check_variable LoadDegOverride $LoadDegOverride
check_variable Policy $Policy
check_variable MaxBadPEReports $MaxBadPEReports
check_variable Capacity $Capacity
check_variable ReregInterval $ReregInterval
check_variable JobInterval $JobInterval
check_variable JobSize $JobSize
check_variable Attackers $Attackers
check_variable AttackType $AttackType
check_variable AttackInterval $AttackInterval
check_variable AttackIdentifier $AttackIdentifier
check_variable AttackReportUnreachableProbability $AttackReportUnreachableProbability

ID="$Measurement"
POOLHANDLE="`echo Pool-$ID | md5sum | awk '{ print $1 }'`"

echo "ID=$ID"
echo "PoolHandle=$POOLHANDLE"

# Get list of n nodes
# $1 = Node list
# $2 = n
get_nodes ()
{
   n=0
   NodeList=""
   CandidateList=$1
   if [ "$CandidateList" = "" ] ; then
      echo "ERROR: Empty node list $1!"
      exit 1
   fi

   while [ $n -lt $2 ] ; do
      for node in $CandidateList ; do
         NodeList="$NodeList $node "
         let n=$n+1
         if [ $n -ge $2 ] ; then
            return
         fi
      done
   done
}


# UsefulNodes1="`(grep ".de$" great-planetlab.hosts ; grep ".edu$" great-planetlab.hosts) | xargs -n1 echo | sort -u`"
# UsefulNodes2="`(grep ".de$" great-planetlab.hosts ; grep ".edu$" great-planetlab.hosts) | sort -ru`"
# echo $UsefulNodes

UsefulNodes1="localhost" # "`cat working.hosts`"
UsefulNodes2="localhost" # "`cat working.hosts`"

get_nodes "$PRNodeList" $PRs             ; PRList=$NodeList
get_nodes "$PENodeList" $PEs             ; PEList=$NodeList
get_nodes "$PUNodeList" $PUs             ; PUList=$NodeList
get_nodes "$AttackerNodeList" $Attackers ; AttackerList=$NodeList


MasterPR="`echo $PRList | head -n1`"

let ENRPPortBase=$PortBase+1024
let ASAPPortBase=$PortBase+2048
let AttackerPortBase=$PortBase+3072

echo "Port Bases:"
echo "   ENRP=$ENRPPortBase"
echo "   ASAP=$ASAPPortBase"
echo "   Attacker=$AttackerPortBase"

PR_PROpt=""
PE_PROpt=""
PU_PROpt=""
asapPort=$ASAPPortBase
enrpPort=$ENRPPortBase
for pr in $PRList ; do
   PR_PROpt="$PR_PROpt -peer=$pr:$enrpPort "
   PE_PROpt="$PE_PROpt -registrar=$pr:$asapPort "
   PU_PROpt="$PU_PROpt -registrar=$pr:$asapPort "
   let asapPort=$asapPort+1
   let enrpPort=$enrpPort+1
done

echo PR_PROpt=$PR_PROpt
echo PE_PROpt=$PE_PROpt
echo PU_PROpt=$PU_PROpt


rm -f *.log *.cmd *.sca *.log.bz2 *.cmd.bz2 *.sca.bz2


echo "`date` ###### Starting PRs ###################################################"
id=1
for node in `echo $PRList | xargs -n1 echo | sort -u` ; do
   rm -f $node-pr-start.cmd
done
asapPort=$ASAPPortBase
enrpPort=$ENRPPortBase
for node in $PRList ; do
   echo "PR=$node"
   $SERVICE_CONTROL_CMD restart   "$SSH_TOOL_CMD WriteCmd $node-pr-start.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY registrar \
      "-loglevel=4 -logcolor=off -asap=[::]:$asapPort -enrp=[::]:$enrpPort -asapannounce=off -enrpannounce=off -maxbadpereports=$MaxBadPEReports -maxhrrate=$MaxHRRate -maxeurate=$MaxEURate $OPT_CSP $PR_PROpt -statsfile=$ID-pr-$id-stats.data -statsinterval=1000 -actionlogfile=$ID-pr-$id-action.data"   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
   let asapPort=$asapPort+1
   let enrpPort=$enrpPort+1
done
for node in `echo $PRList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-pr-start.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait

sleep 6

echo "`date` ###### Starting attackers #############################################"
id=1
for node in `echo $AttackerList | xargs -n1 echo | sort -u` ; do
   rm -f $node-attacker-start.cmd
done
for node in $AttackerList ; do
   echo "A=$node"
   aid=0
   if [ $AttackIdentifier -ne 0 ] ; then
      let aid=$AttackIdentifier+$id-1
   fi
   let aport=$AttackerPortBase+$id
   $SERVICE_CONTROL_CMD restart   "$SSH_TOOL_CMD WriteCmd $node-attacker-start.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY attacker \
      "-type=$AttackType -interval=$AttackInterval -port=$aport -identifier=$aid -policy=$Policy -loaddegoverride=$LoadDegOverride -poolhandle=$POOLHANDLE -reportunreachableprobability=$AttackReportUnreachableProbability -asapannounce=off $OPT_CSP $PE_PROpt"   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
for node in `echo $AttackerList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-attacker-start.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait

sleep 6

echo "`date`# ##### Starting PEs ###################################################"
id=1
for node in `echo $PEList | xargs -n1 echo | sort -u` ; do
   rm -f $node-pe-start.cmd
done
for node in $PEList ; do
   echo "PE=$node"
   $SERVICE_CONTROL_CMD restart   "$SSH_TOOL_CMD WriteCmd $node-pe-start.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY server \
      "-loglevel=4 -logcolor=off -calcapp -capcapacity=1000000 -policy=$Policy -poolhandle=$POOLHANDLE -rereginterval=$ReregInterval -capcapacity=$Capacity "-capobject=scenario.calcAppPoolElement[$id]" -capscalar=$ID-pe-$id.sca $PE_PROpt -asapannounce=off $OPT_CSP"   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
v=1
for node in `echo $PEList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-pe-start.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
   let v=$v+1
done
wait

sleep 6

echo "`date` ###### Starting PUs ###################################################"
id=1
for node in `echo $PUList | xargs -n1 echo | sort -u` ; do
   rm -f $node-pu-start.cmd
done
for node in $PUList ; do
echo "PU=$node"
   $SERVICE_CONTROL_CMD restart   "$SSH_TOOL_CMD WriteCmd $node-pu-start.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY calcappclient \
      "-loglevel=4 -logcolor=off -jobsize=$JobSize -jobinterval=$JobInterval -keepalivetransmissioninterval=10000000 -keepalivetimeoutinterval=10000000 -poolhandle=$POOLHANDLE "-object=scenario.calcAppPoolUser[$id]" -scalar=$ID-pu-$id.sca $PE_PROpt -asapannounce=off $OPT_CSP"   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
for node in `echo $PUList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-pu-start.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait


echo "`date` ###### Running test ###################################################"
echo "Duration is $Duration seconds"
echo "Now is `date`"
sleep $Duration


echo "`date` ###### Stopping PUs ###################################################"
id=1
for node in `echo $PUList | xargs -n1 echo | sort -u` ; do
   rm -f $node-pu-stop.cmd
done
for node in $PUList ; do
   $SERVICE_CONTROL_CMD stop  "$SSH_TOOL_CMD WriteCmd $node-pu-stop.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY calcappclient ""   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
for node in `echo $PUList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-pu-stop.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait


echo "`date` ###### Stopping PEs ###################################################"
id=1
for node in `echo $PEList | xargs -n1 echo | sort -u` ; do
   rm -f $node-pe-stop.cmd
done
for node in $PEList ; do
   $SERVICE_CONTROL_CMD stop  "$SSH_TOOL_CMD WriteCmd $node-pe-stop.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY server ""   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
for node in `echo $PEList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-pe-stop.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait


echo "`date` ###### Stopping attackers #############################################"
id=1
for node in `echo $AttackerList | xargs -n1 echo | sort -u` ; do
   rm -f $node-attacker-stop.cmd
done
for node in $AttackerList ; do
   $SERVICE_CONTROL_CMD stop  "$SSH_TOOL_CMD WriteCmd $node-attacker-stop.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY attacker ""   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
for node in `echo $AttackerList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-attacker-stop.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait


echo "`date` ###### Stopping PRs ###################################################"
id=1
for node in `echo $PRList | xargs -n1 echo | sort -u` ; do
   rm -f $node-pr-stop.cmd
done
for node in $PRList ; do
   $SERVICE_CONTROL_CMD stop  "$SSH_TOOL_CMD WriteCmd $node-pr-stop.cmd"  $node  $SSH_NODE $SSH_USER $SSH_KEY   $ID-$id $SERVICE_DIRECTORY registrar ""   "$SERVICE_PRE_PROGRAM"
   let id=$id+1
done
for node in `echo $PRList | xargs -n1 echo | sort -u` ; do
   $SSH_TOOL_CMD RunCmd $node-pr-stop.cmd  $node  $SSH_NODE $SSH_USER $SSH_KEY &
done
wait


echo "`date` ###### Downloading results ############################################"
allNodes="`
(
   for pr in $PRList ; do
      echo $pr
   done
   for pe in $PEList ; do
      echo $pe
   done
   for pu in $PUList ; do
      echo $pu
   done
) | xargs -n1 echo | sort -u`"

for node in $allNodes ; do
   echo "N=$node"
   scp -C -i $SSH_KEY -oConnectTimeout=5 -oConnectionAttempts=4 -oStrictHostKeyChecking=no -oPasswordAuthentication=no "$SSH_USER@$node:$SERVICE_DIRECTORY/$ID-*.*" . &
done
wait
bzip2 *.log *.cmd *.sca *.data
touch status.txt
