#!/bin/bash
#
# zfs-transfer-cron
#
# Trabajo de cron para respaldar datasets ZFS
# mediante zfs-transfer
#
# zfs-transfer-cron [opciones] zftdir
#
#
# zftdir contiene:
#
#  datasets: Nombre de los datasets que vamos a respaldar por default
#  sshkey:   Ruta a la llave por default
#  sshuser:  Usuario ssh por default
#  zftopts:  Opciones que se pasaran a zft-transfer-receive
#  destination: Destino de la transferencia ZFS. Ej. pool/cliente
#  logdir:   Ruta al directorio de log
#
#  Un directorio por cada host, que puede contener los archivos de arriba con
#  configuracion personalizada para cada host, mas estos archivos:
#  
#  hostalias:  Nombre o direccion IP para este host
#  hostdisable: Si este archivo existe, este directorio de host es ignorado
#

set -o pipefail

zftdir="$1"

mkdir -p /var/log/mon

error_exit () {
   local errstatus
   errstatus=1
   [[ "$2" ]] || errstatus="$2"
   echo "$1" >&2
   exit $errstatus
}

# Verificaciones de sanidad

if [[ -z "$1" ]]; then
   error_exit "Uso: $(basename $0) <zftdir>"
fi

for f in datasets sshkey destination logdir; do
   if ! [[ -f "${zftdir}/${f}" ]]; then
      error_exit "El archivo ${zftdir}/${f} es requerido."
   fi
done

#######################################################
#                      Defaults                       #
#######################################################

# Ruta a zfs-transfer-receive
[[ "$ZFTREC" ]] || ZFTREC="/usr/sbin/zfs-transfer-receive"

# Opciones para zfs-transfer-receive
[[ "$zftopts" ]] || zftopts="-a -d -D"

# El usuario para la transferencia
[[ "$sshuser" ]] || sshuser="zfs-transfer"

# Rutas a binarios importantes
[[ "$ZFS"   ]] || ZFS=/sbin/zfs
[[ "$RSYNC" ]] || RSYNC=/usr/bin/rsync


#######################################################


echo "Inicio de zfs-transfer-cron: zftdir: ${zftdir}"
echo "-----------------------------------------------------------------"

generror=0

# Iteramos sobre la lista de hosts
for hdir in $(find "${zftdir}/hosts" -maxdepth 1 -type d); do
   hname=$(basename "$hdir")

   # Es un directorio de host?
   [[ -f "${hdir}/hostalias" ]] || continue
   echo "Processing host: $hname"
   hostalias=$(cat ${hdir}/hostalias)

   # Esta desactivada la transferencia para este host?
   if [[ -f "${hdir}/hostdisable" ]]; then
      echo -e "\t'hostdisable' file found. Ignoring host: $hname."
      continue
   fi

   # Conseguir configuracion por default
   datasets="${zftdir}/datasets"
   sshkey=$(cat "${zftdir}/sshkey")
   destination=$(cat "${zftdir}/destination")
   logdir=$(cat "${zftdir}/logdir")

   [[ -f "${zftdir}/sshuser" ]] && sshuser=$(cat  "${zftdir}/sshuser")
   [[ -f "${zftdir}/zftopts" ]] && zftopts=$(cat  "${zftdir}/zftopts")

   # Conseguir configuracion especifica
   rsyncopts=""
   [[ -f "${hdir}/datasets" ]] && datasets="${hdir}/datasets"
   [[ -f "${hdir}/sshkey"   ]] && sshkey=$(cat   "${hdir}/sshkey")
   [[ -f "${hdir}/sshuser"  ]] && sshuser=$(cat  "${hdir}/sshuser")
   [[ -f "${hdir}/zftopts"  ]] && zftopts=$(cat  "${hdir}/zftopts")
   [[ -f "${hdir}/rsyncopts"  ]] && rsyncopts=$(cat  "${hdir}/rsyncopts")
   [[ -f "${hdir}/destination"  ]] && destination=$(cat  "${hdir}/destination")


  # zft-transfer-receive de este host
  hlogdir="${logdir}/${hname}"

  for ds_origen in $(cat "$datasets"); do
     dserror=0
     ds_destino="${destination}/${hname}/$(basename "$ds_origen")"
     if [[ -f "${hdir}/use-rsync"  ]]; then
        echo -e "\tprocessing rsync module: ${ds_origen}"
        echo "Running '"$RSYNC $rsyncopts --delete -a --password-file "${hdir}/pwfile" "rsync://${sshuser}@${hostalias}/${ds_origen}" "/${ds_destino}""'" |& common-logger "$hlogdir"
        $RSYNC $rsyncopts --delete -a --password-file "${hdir}/pwfile" "rsync://${sshuser}@${hostalias}/${ds_origen}" "/${ds_destino}" |& common-logger "$hlogdir"
        if [[ $? -eq 0 ]]; then
           snapname="${ds_destino}@zft-$(date +%Y%m%d-%H%M)"
           echo "[$(hostname)] Creando snapshot $snapname" |& common-logger "$hlogdir"
           $ZFS snap "$snapname" |& common-logger "$hlogdir"
           echo -e "\trsync module '${ds_origen}' processed."
        else
          echo "${RSYNC} exit with error: code\($?\)" |& common-logger "$hlogdir"
          dserror=1
          generror=1
          touch "/var/log/mon/zfs-transfer-cron-${hname}-$(echo ${ds_origen} | tr / _)"
        fi
     else
        echo -e "\tprocessing zfs dataset: ${ds_origen}"
        echo "Running '"$ZFTREC $zftopts -i "$sshkey" "${sshuser}@${hostalias}" "$ds_origen" "$ds_destino""'" |& common-logger "$hlogdir"
        $ZFTREC $zftopts -i "$sshkey" "${sshuser}@${hostalias}" "$ds_origen" "$ds_destino" |& common-logger "$hlogdir"
 
        if [[ $? -gt 0 ]]; then
           echo "$ZFTREC exit with error: code\($?\)" |& common-logger "$hlogdir"
           dserror=1
           generror=1
           touch "/var/log/mon/zfs-transfer-cron-${hname}-$(echo ${ds_origen} | tr / _)"
        fi
        echo -e "\tdataset '${ds_origen}' processed."
     fi
     if [[ $dserror -gt 0 ]]; then
       echo -e "\t***There were errors processing '${ds_origen}'\n"
     fi 
  done 

  echo -e "\thost '${hname}' processed." 
done

witherrors=""
if [[ $generror -gt 0 ]]; then
   echo -e "\n***** There were errors processing some hosts ***** \n"
   witherrors="(with errors)"
fi

echo "-----------------------------------------------------------------"
echo "Fin de zfs-transfer-cron: zftdir: ${zftdir} ${witherrors}"
echo ""

exit $generror
