#!/bin/bash
# To move a machine onto a new ZFS
# Load some settings
. /etc/default/zfs-backup

# To move a machine from one zpool to another
function dosql_local() {
 SQL="$1"
 psql -q -A -t -c "$SQL"
}

function dosql_remote() {
 SQL="$1"
 psql -q -A -h $NEW_SERVER -t -c "$SQL"
}

function cmd_remote() {
 CMD="$1"
 ssh root@$NEW_SERVER $CMD
}

function create_host_record() {
 FQDN=$1
 # NB we start with offline=t,disabled=t whilst we migrate the backup.
 HOSTID=`dosql_remote "
 insert into host (hostname, offline, disabled) values ('$FQDN',true,true);
 select host_id from host where hostname='$FQDN';"`
 echo $HOSTID
}

function backuptask() {
 HOSTID=$1
 TASKNAME="$2"
 TARGET=$3
 SOURCEDIR=$4
 SOFT=$5
 HARD=$5

if [ -z "$SOFT" ]; then
  SOFT=14400
 fi
 if [ -z "$HARD" ]; then
  HARD=86400
 fi
 BTID=`dosql_remote "
 insert into backup_task(host_id,backup_task_name,timeout_soft,timeout_hard,zfs_target,backup_type_id) values
 ($HOSTID,'$TASKNAME',$SOFT,$HARD,'$TARGET',3);
 
 insert into zfs_rsync_detail (backup_task_id,directory_source) values
 ((select backup_task_id from backup_task where zfs_target='$TARGET' and host_id=$HOSTID),'$SOURCEDIR');

 select backup_task_id from backup_task natural join host natural join zfs_rsync_detail where hostname='$FQDN' and directory_source='$SOURCEDIR' and backup_type_id=3;"`
 echo $BTID
}

function configure_pruning() {
 CURRENT_TASK_ID=$1
 NEW_TASK_ID=$2
 PRUNING_IDS=$(dosql_local "select zfs_pruning_id from zfs_pruning where backup_task_id=$CURRENT_TASK_ID")
 for PRUNING_ID in $PRUNING_IDS; do
   PRUNING_AGE=$(dosql_local "select zfs_pruning_age from zfs_pruning where zfs_pruning_id=$PRUNING_ID")
   PRUNING_COUNT=$(dosql_local "select zfs_pruning_count from zfs_pruning where zfs_pruning_id=$PRUNING_ID")
   FLAGNAME=$(dosql_local "select flagname from zfs_pruning where zfs_pruning_id=$PRUNING_ID")

   dosql_remote "insert into zfs_pruning (backup_task_id, zfs_pruning_age,zfs_pruning_count,flagname) values 
   ($NEW_TASK_ID, $PRUNING_AGE, $PRUNING_COUNT, '$FLAGNAME')"
 done
}
 
if [ $# -lt 2 ] ; then
 echo Usage: $0 backup_target_fqdn new_backup_server [zpool_name]
 echo Moves the named machine to a new server
 exit 1
fi

HN=$1
# Find FQDN for $HN
FQDN=`getent hosts $HN | awk ' { print $2 } '`
NEW_SERVER=$2
ZPOOL_TARGET=$3
# Which zfs is it already on?
echo Finding source ZFS for $FQDN
SOURCES=`zfs list -H -o name | grep -v  zroot | grep /$FQDN$ | sed "sZ/'$FQDN$'ZZ" | wc -l `
#echo Found $SOURCES possibilities
if [ $SOURCES != 1 ] ;then
 echo Found more than one possible ZFS for $HN
 exit 2
fi

if ! grep -q ^$NEW_SERVER: $PGPASSFILE ; then
  echo $NEW_SERVER not found in $PGPASSFILE \(use fqdn?\)
  exit 5
fi


SOURCE=`zfs list -H -o name | grep -v  zroot | grep /$FQDN$ | sed "sZ/$FQDN\\$ZZ"`

# Which target is it?
if [ -z "$ZPOOL_TARGET" ] ; then
 echo Finding a target ZFS automatically
 ZPOOL=$(cmd_remote "zfs list -H -oname -S avail -d0 | grep -v zroot | head -n1")
 ZPOOL_TARGET=$ZPOOL
fi

if ! ssh root@$NEW_SERVER zpool list $ZPOOL_TARGET &>/dev/null ; then
  echo $ZPOOL_TARGET does not exist on $NEW_SERVER
  exit 3
fi

echo moving $FQDN from $SOURCE to $ZPOOL_TARGET on $NEW_SERVER

set -e
RUNNING=`dosql_local "select count(*) from backup_log natural join backup_task natural join host where hostname='$FQDN' and ended_processing is null and started_processing is not null"`
RUNNING=`echo $RUNNING` # chomp
#echo RUNNING $RUNNING
if ! [ "$RUNNING" = 0 ] ;  then
 echo $FQDN has a job running
 exit 3
fi

# Disable this host locally
dosql_local "update host set disabled='t' where hostname='$FQDN';"
# De-queue jobs for this host
dosql_local "delete from backup_log where backup_task_id in (select backup_task_id from backup_task natural join host where hostname='$FQDN') and ended_processing is null and started_processing is null;"

# Move ZFS
NOW=$(date +%s)
zfs snapshot -r $SOURCE/$FQDN@$NOW
zfs hold zfs-moving $SOURCE/$FQDN@$NOW
SIZE=`zfs list -H -o used $SOURCE/$FQDN`
echo Sending  ZFS [ $SIZE]
zfs send -R $SOURCE/$FQDN@$NOW | mbuffer | ssh root@$NEW_SERVER zfs receive $ZPOOL_TARGET/$FQDN
CURRENT_HOST_ID=$(dosql_local "select host_id from host where hostname='$FQDN'")
NEW_HOST_ID=$(create_host_record $FQDN)

# get current tasks
TASK_IDS=$(dosql_local "select backup_task_id from backup_task where host_id='$CURRENT_HOST_ID'")

# create new tasks
for TASK_ID in $TASK_IDS; do
  echo got task $TASK_ID

  SOURCEDIR=$(dosql_local "select directory_source from zfs_rsync_detail where backup_task_id='$TASK_ID'")
  SOFT=$(dosql_local "select timeout_soft from backup_task where backup_task_id='$TASK_ID'")
  HARD=$(dosql_local "select timeout_hard from backup_task where backup_task_id='$TASK_ID'")

  TASKNAME=$(dosql_local "select backup_task_name from backup_task where backup_task_id='$TASK_ID'")
  CURRENT_ZFS_TARGET=$(dosql_local "select zfs_target from backup_task where backup_task_id='$TASK_ID'")
  NEW_ZFS_TARGET=${ZPOOL_TARGET}/$(echo $CURRENT_ZFS_TARGET | cut -d '/' -f 2-)
  
  NEW_TASK_ID=$(backuptask $NEW_HOST_ID "$TASKNAME" $NEW_ZFS_TARGET $SOURCEDIR $SOFT $HARD)
  configure_pruning $TASK_ID $NEW_TASK_ID  

  scp /etc/chem-zfs-backup-server/zfs-rsync.d/${FQDN}_${SOURCEDIR//\//.} $NEW_SERVER:/etc/chem-zfs-backup-server/zfs-rsync.d
  rsync -av /etc/chem-zfs-backup-server/zfs-rsync.d/${FQDN} $NEW_SERVER:/etc/chem-zfs-backup-server/zfs-rsync.d
done

dosql_remote "update host set disabled='f',offline='f' where host_id=$NEW_HOST_ID"



