Raspberry PI Backup incrementale

Come creare un sistema di backup incrementale tramite Raspberry PI

 

 

1. La storia

In passato ho sempre creato periodicamente il Backup incrementale dei dati maggiormente utilizzati e allo scopo ho utilizzato il sempre validissimo e completo Cobian Backup che sebbene non sia più supportato esegue in modo assolutamente egregio e direi professionale il suo compito.

Era pero' necessario mantenere il PC acceso in quanto sebbene in Background Cobian Backup ha bisogno di una macchina windows per girare.

Recentemente ho rivisto la mia rete di casa creando mediante il nuovo FritzBox 3490 e un disco USB (Samsung D3 4TB) un NAS sempre disponibile da qualsiasi periferica connessa alla rete e anche in remoto tramite VPN. Il NAS che avevo un Synology 108j da 1TB è infatti diventato obsoleto per supportare tutto il carico domestico e rimane dedicato a fare da server multimediale.

Si riporta nel seguito il sistema implementato con la precisazione che nella definizione del sistema si è preso spunto adattandolo alle esigenze personali di quanto riportato da Grabriele Merli in merito, articolo di sicuro aiuto per capire, analizzare e impostare un buon sistema di backup incrementale.

2. Sorgente - destinazione - nomi dei file di backup

Il file di backup sarà del tipo:

  • mntPnt/dstDsk/dstDir/souDsk/_souDir_fff_iii_AAAAMMGG_hhmmss.tar.gz
  • /mnt/LCIE_Y/ZBK/M4TB_Q/_App_001_005_20170530_201001.tar.gz

Dove:

  • mntPnt   --> punto di mount dei dischi;
  • dstDsk   --> nome del disco destinazione;
  • dstDir   --> nome della cartella all'interno della quale creare il backup;
  • souDsk   --> nome del disco sorgente;
  • souDir   --> nome della cartella di cui si creerà il backup;
  • fff      --> indice del numero del backup completo (full);
  • iii      --> indice del numero del backup incrementale;
  • AAAAMMGG --> data del backup Anno Mese Giorno;
  • hhmmss   --> ora del backup ora minuti secondi;
  • .tar.gz  --> estenzione del backup in formato tar compresso con gzip (GNU zip);

 

3. Montaggio sorgente destinazione:

  • verifica della presenza di un file nella directory sorgente
  • montaggio del disco corrispondente
  • sudo mount......
  • verifica della presenza di un file nella directory destinazione
  • montaggio del disco corrispondente
  • sudo mount......

Codice sorgente

  #
  # controllo mount disco sorgente --> verica presenza della cartella
  #
  while true; do
    if [ -d ${souFil} ]
    then
      echo "Mount disco ${souFil} --> Ok"               >> ${logFil}
      echo $linea                                       >> ${logFil}
      break
    else
      echo "Mount disco ${souFil} --> No Ok"            >> ${logFil}
      echo $linea                                       >> ${logFil}
      #
      sudo mount -t cifs  -o user=Utente,pass=Password //192.168.188.1/Zappoco/Seagate-D3Station-01/_DiscoW ${mntPnt}${souDsk}
      sleep 30s
    fi
  done
  #
  # controllo mount disco destinazione --> verica presenza della cartella
  #
  while true; do
    if [ -d ${dstFil} ]
    then
      echo "Mount disco ${dstFil} --> Ok"               >> ${logFil}
      echo $linea                                       >> ${logFil}
      break
    else
      echo "Mount disco ${dstFil} --> No Ok"            >> ${logFil}
      echo $linea                                       >> ${logFil}
      #
      sudo mount -t cifs  -o user=Utente,pass=Password //192.168.188.1/Zappoco/  /mnt/LCIE_Y
      echo  "ho montato ${mntPnt}${dstDsk}"
      sleep 30s
    fi
  done

 

4. Ricerca dell'ultimo backup:

  • esecuzione di un ciclo di for
  • determinazione del numero di backup full {ultF}
  • determinazione del numero di backup incrementale {ultI}

Codice sorgente

  #
  # cerca la prima e ultima versione Full
  #

  for (( inF = 0 ; inF < ${maxT} ; inF++))
  do
    NinF=$( printf "%03d" ${inF} )
    tarTmp="${dstFil}/${souDsk}/${tarFil}_${NinF}*"
    cmdTmp="ls -1 ${tarTmp} 2> /dev/null | wc -l"
    nTmp=`eval $cmdTmp`
    
    if [ ! ${nTmp} -eq 0 ]
    then
      if [ ${prmF} -eq -1 ]
      then
        prmF=${inF}
        ultI=${nTmp}
      else [ ${ultF} -gt 0 ]
        ultF=${inF}
        ultI=${nTmp}
      fi
    else
      if [ ${ultF} -gt 0 ]
      then
        break
      fi

    fi
  done

  if [ ${prmF} -eq -1 ]
  then
    prmF=0
    ultI=0
  fi
  if [ ${ultF} -eq -1 ]
  then
    ultF=${prmF}
  fi

  echo "prmF = ${prmF}"
  echo "ultF = ${ultF}"
  echo "ultI = ${ultI}"
  
  if [ ${ultI} -ge ${maxI} ]
  then
    ultI=0
    ultF=$((${ultF}+1))
  fi
  tmpF=$(( ${ultF} - ${maxF} - 1 ))
  echo "prmF = ${prmF}"
  echo "tmpF = ${tmpF}"


  if [ ${prmF} -eq ${tmpF} ]
  then
    NinF=$( printf "%03d" ${prmF} )
    tarTmp="${dstFil}/${souDsk}/${tarFil}_${NinF}*"
    echo $linea "Cancellazione ${tarTmp}" >> ${logFil}
    echo $linea                           >> ${logFil}
    echo "prmF = ${prmF}"
    #
    # rimuove i file 000
    #

    rm -f ${tarTmp} >> ${logFil}
  fi
  #
  echo "ultF = ${ultF}"
  echo "ultI = ${ultI}"
  echo "Indice del backup completo     --> ${ultF}"  >> ${logFil}
  echo "Indice del backup incrementale --> ${ultI}"  >> ${logFil}
  echo $linea                                        >> ${logFil}
  #
  if [ ${ultI} -eq 0 ]
  then
    echo "Cancellazione ${snaFil}" >> ${logFil}
    echo $linea                                    >> ${logFil}
    rm -f ${snaFil} >> ${logFil}
    echo "Conversione del backup in completo"      >> ${logFil}
  else
    echo "Creazione backup incrementale"           >> ${logFil}
  fi
  echo $linea                                               >> ${logFil}
 

5. Composizione del nome e del comando:

  • composizione del nome
  • composizione del comando
  • esecuzione comando

Codice sorgente



  NinF=$( printf "%03d" ${ultF} )
  NinI=$( printf "%03d" ${ultI} )
  #
  tarTmp="${dstFil}/${souDsk}/${tarFil}_${NinF}_${NinI}_${dateSt}"        
  echo "Backup         --> ${tarTmp}"    	 >> ${logFil}


  echo $linea                              >> ${logFil}
  #
  # esegue il comando tar
  #
  tar  --listed-incremental=${snaFil} --no-check-device -zcvf ${tarTmp}.tar.gz ${souFil} ${excCm1} ${excCm2} ${excCm3} ${excCm4} >> ${logFil}
  cp  ${snaFil} "${dstFil}/${souDsk}/${tarFil}S${NinF}_${NinI}_${dateSt}.snar"        



6. Codice completo

#! /bin/bash
#
# 2017 05 01 ZappocoS --> versione 001 --> partendo da schema RSYNC
# 2017 05 05 ZappocoS --> versione 003 --> inserimento funzione
#
#
#Per ripristinare
#
#Prima il full
#
#tar --listed-incremental=/dev/null -xzvf DirBak_000_000_20170505_180537.tar.gz
#
#Poi i vari incrementali dal più vecchio al più nuovo (e ti fermi dove vuoi arrivare)
#
#tar --listed-incremental=/dev/null -xzvf DirBak_000_001_20170506_190537.tar.gz
#tar --listed-incremental=/dev/null -xzvf DirBak_000_002_20170506_200537.tar.gz
#tar --listed-incremental=/dev/null -xzvf DirBak_000_003_20170507_210537.tar.gz
#SE SEI ROOT E VUOI RIPRISTINARE ANCHE I PERMESSI METTICI UN -p
#
#--------------------------

function tar_directory ()
{
  linea="----------"
  #linea=""


  souDsk=$1                      #disco di mount sorgente
  souDir=$2                      #cartella di cui creare TAR
  dstDsk=$3                      #disco di mount destinazione
  dstDir=$4                      #cartella dove creare TAR

  mntPnt="/mnt/"                 #punto di mount
  logPnt="/home/pi/Z_LOG/"       #posizione file log
  dateSt=`date +%Y%m%d_%H%M%S`   #rappresentazione completa della data

  souFil="${mntPnt}${souDsk}/${souDir}"                 #Nome completo della directory sorgente 
  dstFil="${mntPnt}${dstDsk}/${dstDir}"                 #Nome completo della directory destinazione
  tarFil="${souDir}"

  if [[ -z "$5" ]] ; then
     excCm1=""
  else
     excCm1="--exclude ${souFil}/$5"             #directory da escludere
  fi

  if [[ -z "$6" ]] ; then
     excCm2=""
  else
     excCm2="--exclude ${souFil}/$6"             #directory da escludere
  fi

  if [[ -z "$7" ]] ; then
     excCm3=""
  else
     excCm3="--exclude ${souFil}/$7"             #directory da escludere
  fi

  if [[ -z "$8" ]] ; then
     excCm4=""
  else
     excCm4="--exclude ${souFil}/$8"             #directory da escludere
  fi

  snaFil="${dstFil}/${souDsk}/${tarFil}.snar"               #Nome del file contenente gli elenchi (listed-incremental)
  logFil="${logPnt}${dateSt}_ZBK_${souDsk}__${tarFil}.log"  #Nome completo del file di log


  echo $linea
  echo "Creazione del backup (zbk) by Zappoco 1.03"
  echo "Data           --> ${dateSt}"
  echo $linea

  echo "souFil = $souFil"
  echo "dstFil = $dstFil"
  echo "tarFil = $tarFil"
  echo "dstPnt = $dstPnt"
  echo "dstDir = $dstDir"
  echo "logPnt = $logPnt"
  echo "dateSt = $dateSt"
  echo "snaFil = $snaFil"
  echo "logFil = $logFil"
  echo "excCm1 = $excCm1"
  echo "excCm2 = $excCm2"
  echo "excCm3 = $excCm3"
  echo "excCm4 = $excCm4"
  echo $linea
  #
  # inizializzazione dei parametri per il backup completo e incrementale
  #
  maxT=100   # numero massimo di backup ---> inserire 999
  maxF=6     # numero massimo di back Full da mantenere
  maxI=26    # numero massimo di back Incrementali per ogni Full
  prmF=-1    # primo  back full
  ultF=-1    # ultimo back full

  echo $linea                                           >> ${logFil}
  echo "Creazione del backup (zbk) by Zappoco 1.03"     >> ${logFil}
  echo "Data           --> ${dateSt}"                   >> ${logFil}
  
  echo $linea                                           >> ${logFil}
  echo "Sorgente       --> ${souFil}"    	        >> ${logFil}
  echo "Destinazione   --> ${dstFil}"                   >> ${logFil}
  echo "     --> ${excCm1}"    	      		        >> ${logFil}
  echo "     --> ${excCm2}"                      	>> ${logFil}
  echo "     --> ${excCm3}"                     	>> ${logFil}
  echo "     --> ${excCm4}"                     	>> ${logFil}
  echo ""                                        	>> ${logFil}

  echo "Num. max di backup completi      --> ${maxF}"   >> ${logFil}
  echo "Num. max di backup incrementali  --> ${maxI}"   >> ${logFil}
  echo $linea                                           >> ${logFil}
  #
  # controllo mount disco sorgente --> verica presenza della cartella
  #
  while true; do
    if [ -d ${souFil} ]
    then
      echo "Mount disco ${souFil} --> Ok"               >> ${logFil}
      echo $linea                                       >> ${logFil}
      break
    else
      echo "Mount disco ${souFil} --> No Ok"            >> ${logFil}
      echo $linea                                       >> ${logFil}
      #
      sudo mount -t cifs  -o user=Utente,pass=Password //192.168.188.1/Zappoco/Seagate-D3Station-01/_DiscoW ${mntPnt}${souDsk}
      sleep 30s
    fi
  done
  #
  # controllo mount disco destinazione --> verica presenza della cartella
  #
  while true; do
    if [ -d ${dstFil} ]
    then
      echo "Mount disco ${dstFil} --> Ok"               >> ${logFil}
      echo $linea                                       >> ${logFil}
      break
    else
      echo "Mount disco ${dstFil} --> No Ok"            >> ${logFil}
      echo $linea                                       >> ${logFil}
      #
      sudo mount -t cifs  -o user=Utente,pass=Password //192.168.188.1/Zappoco/  /mnt/LCIE_Y
      echo  "ho montato ${mntPnt}${dstDsk}"
      sleep 30s
    fi
  done
  #
  # cerca la prima e ultima versione Full
  #
  for (( inF = 0 ; inF < ${maxT} ; inF++))
  do
    NinF=$( printf "%03d" ${inF} )
    #tarTmp="${dstPnt}${dstDsk}/${souDsk}/${tarFil}_${NinF}*"        
    tarTmp="${dstFil}/${souDsk}/${tarFil}_${NinF}*"
    cmdTmp="ls -1 ${tarTmp} 2> /dev/null | wc -l"
    nTmp=`eval $cmdTmp`
    #echo "${nTmp} ${prmF} ${ultF} $tarTmp"
    
    if [ ! ${nTmp} -eq 0 ]
    then
      if [ ${prmF} -eq -1 ]
      then
        prmF=${inF}
        ultI=${nTmp}
        #echo "primo full ${NinF} -SI- ${prmF}"
      else [ ${ultF} -gt 0 ]
        ultF=${inF}
        ultI=${nTmp}
        #echo "utimo full ${NinF} -SI- ${ultF}"
      fi
    else
      if [ ${ultF} -gt 0 ]
      then
        #echo trovato ultimo
        break
      fi

    fi
  done

  #
  if [ ${prmF} -eq -1 ]
  then
    prmF=0
    ultI=0
  fi
  #
  if [ ${ultF} -eq -1 ]
  then
    ultF=${prmF}
  fi
  #
  echo "prmF = ${prmF}"
  echo "ultF = ${ultF}"
  echo "ultI = ${ultI}"
  #
  if [ ${ultI} -ge ${maxI} ]
  then
    ultI=0
    ultF=$((${ultF}+1))
  fi
  tmpF=$(( ${ultF} - ${maxF} - 1 ))
  echo "prmF = ${prmF}"
  echo "tmpF = ${tmpF}"


  if [ ${prmF} -eq ${tmpF} ]
  then
    NinF=$( printf "%03d" ${prmF} )
    #tarTmp="${dstPnt}${souDsk}/${souDsk}/${tarFil}_${NinF}*"        
    tarTmp="${dstFil}/${souDsk}/${tarFil}_${NinF}*"
    echo $linea "Cancellazione ${tarTmp}" >> ${logFil}
    echo $linea                           >> ${logFil}
    echo "prmF = ${prmF}"
    #
    # rimuove i file 000
    #
    rm -f ${tarTmp} >> ${logFil}
  fi
  #
  echo "ultF = ${ultF}"
  echo "ultI = ${ultI}"
  echo "Indice del backup completo     --> ${ultF}"  >> ${logFil}
  echo "Indice del backup incrementale --> ${ultI}"  >> ${logFil}
  echo $linea                                        >> ${logFil}
  #
  if [ ${ultI} -eq 0 ]
  then
    echo "Cancellazione ${snaFil}" >> ${logFil}
    echo $linea                                    >> ${logFil}
    rm -f ${snaFil} >> ${logFil}
    echo "Conversione del backup in completo"      >> ${logFil}
  else
    echo "Creazione backup incrementale"           >> ${logFil}
  fi
  echo $linea                                               >> ${logFil}

  #
  NinF=$( printf "%03d" ${ultF} )
  NinI=$( printf "%03d" ${ultI} )
  #
  tarTmp="${dstFil}/${souDsk}/${tarFil}_${NinF}_${NinI}_${dateSt}"        
  echo "Backup         --> ${tarTmp}"    	 >> ${logFil}


  echo $linea                              >> ${logFil}
  #
  # esegue il comando tar
  #
  tar  --listed-incremental=${snaFil} --no-check-device -zcvf ${tarTmp}.tar.gz ${souFil} ${excCm1} ${excCm2} ${excCm3} ${excCm4} >> ${logFil}
  cp  ${snaFil} "${dstFil}/${souDsk}/${tarFil}S${NinF}_${NinI}_${dateSt}.snar"        


  #if [ ${ultI} -eq 0 ]
  #then
  #  echo "${NinF}_${NinI}"         >> ${snaFil}
  #fi
  #echo "${NinF}_${NinI}"         >> ${tarTmp}.txt

  #
  echo $linea                                           >> ${logFil}
  echo "Creazione del backup completata"   >> ${logFil}
  dateSt=`date +%Y%m%d_%H%M%S`   #rappresentazione completa della data
  echo "Data           --> ${dateSt}"                   >> ${logFil}
  echo $linea                                           >> ${logFil}
  #echo " ${logFil} ${dstFil} "
  cp ${logFil} ${dstFil}

}  
#
#               souDsk   souDir                  dstDsk   dstDir  excDi1    excDi2    excDi3    excDi4
#
tar_directory   "M4TB_W" "Doc_ZappocoS"             "LCIE_Y" "ZBK" 
tar_directory   "M4TB_W" "Doc_Nadia"             "LCIE_Y" "ZBK" 
tar_directory   "M4TB_W" "Doc_ZappocoJ"            "LCIE_Y" "ZBK"            
tar_directory   "M4TB_W" "Musica"                "LCIE_Y" "ZBK"            
tar_directory   "M4TB_W" "Pdf"                   "LCIE_Y" "ZBK"            
tar_directory   "M4TB_W" "Sys"                   "LCIE_Y" "ZBK"            
tar_directory   "M4TB_W" "V_Foto"                "LCIE_Y" "ZBK"   2016      2015      2014      2013 
tar_directory   "M4TB_W" "V_Video"               "LCIE_Y" "ZBK"            
tar_directory   "M4TB_W" "Manuali_Libri_Ebook" "LCIE_Y" "ZBK"   "Z_Libri_Liceo_CD"
#
echo
echo "ZBK processo completato"
echo
exit



ZappocoS, aprile maggio 2017