Newsgroup: it.comp.os.linux.sys
Titolo: backup con lvm e mirror

Dato che sono "migrato" a lvm anche per usare i mirror, questa è la 
prima versione di un ipotetico script di backup con rdiff-backup su 
un'unità esterna.
LVSRC= dati homes
LVDST= /mnt/snapshots
VG= /dev/ditta
BACK= /mnt/backup/dati
RDIFF= /usr/bin/rdiff-backup
for l in LVSRC
         do
                 lvcreate -s -n $l_snap -L 100M $VG/$l # creo gli snap
                 mount $VG/$l $LVDST/$l
                 xfs_freeze -f $LVDST/$l
                 $RDIFF $LVDST/$l $BACK/$l
                 xfs_freeze -u $LVDST/$l
                 umount $LVDST/$l
                 lvremove $VG/$l_snap
done
Devo però aggiungere parecchi controlli ma vorrei evitare di essere 
prolisso.
L'unità esterna va inserita alla mattina, per cui pensavo che potrebbe
1. vedere se è montata
2. se no riprovare più tardi per un po' di volte
3. se nemmeno così mandare una mail al responsabile dicendo di inserirla 
  n cc a me (può succedere che per qualche giorno sia chiusa l'azienda 
chiaramente)
Poi non saprei se mi conviene usare syslog-ng per loggare o direttamente 
un file da dare poi in pasto a logcheck.
Serviranno poi vari controlli per il mount eseguito, se invece ad 
esempio non riuscissi a fare il freeze potrebbe non essere fatale per 
l'esecuzione, o sbaglio?
Vedete qualche altro possibile problema / fonte di errori?
Grazie

andrea ha scritto:

Pensavo inoltre di fare in questo modo per controllare se il device per 
il backup è montato o no, un while con un contatore tipo a 10 tentavi, 
ma non riesco proprio a mettere due condizioni nel while, la sintassi 
bash è sempre stato un mistero per me..
tipo così:
         COUNT=10
         while ! mount | grep backup do # && [ $COUNT -gt "0" ]
                 sleep 5m
                 mount /mnt/backup # COUNT="$(($COUNT-1))"
         done
In caso andasse male avverte chi di dovere che c'è un problema.
Ho provato inoltre ad usare logger, tipo così
logger -p local0.error $EDISK
A guardare la conf di syslog-ng dovrebbe mettermelo nel file 
$FACILITY.err, ma anche se poi l'ho creato (non esiteva) non logga il 
messaggio da nessuna parte.
Questa i passi interessati della configurazione:
destination df_facility_dot_err { file("/var/log/$FACILITY.err"); };
filter f_at_least_err { level(err..emerg); };
                 and level(crit,err,notice));
Forse scrivendo ho capito, manca il target che assegni la sorgente 
filtrata alla destinazione.
Ora riprovo

Ho impressione che non interessi a nessuno però continuo con le mie
questioni, sto creando un superscript che backuppa tutte varie
categorie di dati, ci sono dati su lvm, dati su partizioni montato
samba, dati estrapolati da comandi (slapcat).
Ora creo una superfunzione che se il disco è montato comincia a
macinare, ma come minimizzare lo sforzo dei controlli senza incorrere
in disastri?
Pensavo di usare logger e poi dare anche il backup.log in pasto a
logcheck, può andare?

Questa poi proprio non la capisco, gli stessi comandi che da cli
funzionano perfettamente nello script non vanno!
Mi spiego meglio, dato che uno dei due filesystem su snapshot lvm
vuole l'opzione nouuid e l'altro no ho pensato di inserire queste
informazioni in /etc/fstab.
Ora da linea di comando una volta creato lo snapshot li monta senza
problemi sia usando
mount <mountpoint>
sia
mount <device lvm>
Lanciando dallo script no! Ho l'impressione che non legga fstab, ma è
possibile/sensato?
function lvm_backup() {
LVDST="/mnt/snapshots"
VG="/dev/calzitex"
DATA=`date +%d-%m-%y`
# controllo che sia montato il volume di backup
for l in "dati" "homeext3"
        do
                name=$l"_snap"
                echo "inizio backup $l"
                echo "creo snapshot"
                lvcreate --snapshot -n $name --size 16m $VG/$l
                echo "monto snap"
                mount $VG/$name
                                        # informazioni e opzioni in
fstab
                echo "inizio backup del volume"
#               $RDIFF $LVDST/$l $BACK/dati/$l
                echo "smonto e rimuovo lo snapshot"
                umount $VG/$name
                lvremove $VG/$name
done
}

 possibile/sensato?
set -x all'inizio e vedi.
-- 
Flavio Visentin
Scientists have finally discovered what's wrong with the female brain:
On the left side, there is nothing right, and on the right side, there
is nothing left.

 
Perfetto poi è andato avevo semplicemente messo caratteri strani (ma non 
visibili), comunque ora lo script è funzionante, ho solo qualche dubbio 
riguardo al logging.
Ho fatto così ora
1. crea un file temporaneo
2. scrive stdout e stderr su di esso con >> e 2>>
3. logga tutto il file temporaneo con logger passandolo a syslog-ng il 
quale è stato istruito a metterlo nel giusto file.
Non ho capito una cosa però, il file è diviso in funzioni, ma non voglio 
che esca brutalmente al primo errore ma logghi comunque tutto.
Ora però come si fa in bash una cosa del genere:
<command> || echo "errore" && return
In pratica vorrei che la funzione stampasse l'errore e tornasse al 
chiamante.
Però in questo modo return è sempre eseguito, e anche mettendolo tra 
parentesi o creando una subshell non funziona uguale.
Questo comunue lo script completo in caso potesse interessare (se avete 
consigli poi siete i benvenuti)
#!/usr/bin/env bash
## scripts di backup, usa diverse impostazioni per tutti i vari tipi di dati
BACK="/mnt/backup"
RDIFF="/usr/bin/rdiff-backup"
RSYNC="/usr/bin/rsync"
EXCLUDE="/usr/local/bin/toexclude"
EDISK="non sono riuscito a montare il disco"
EMOUNT=10
function lvm_backup() {
LVDST="/mnt/snapshots"
VG="/dev/ditta"
DATA=`date +%d-%m-%y`
# controllo che sia montato il volume di backup
for l in "dati" "homeext3"
	do
		name=$l"_snap"
		echo "inizio backup $l"
		echo "creo snapshot"
		lvcreate --snapshot -n $name --size 16m $VG/$l
		echo "monto snap"
		mount $VG/$name
		$RDIFF $LVDST/$l $BACK/dati/$l
		echo "smonto e rimuovo lo snapshot"
		umount $VG/$name
		lvremove -f $VG/$name
done
}
function sys_backup() {
# salvataggio di tutto il sistema
$RSYNC -az --delete-excluded --delete --exclude-from=$EXCLUDE / $BACK/server
}
function gest_backup() {
NEWYORK="/mnt/newyork"
G1="/mnt/zucchetti"
if ! mount | grep newyork
	then mount $NEWYORK || return
	else $RDIFF -v 4 $NEWYORK/Tables $BACK/newyork; umount $NEWYORK
fi
if ! mount | grep zucchetti
	then mount $G1 || return
	else $RDIFF -v 4 $G1/dati/DB $BACK/zucchetti; umount $G1
fi
}
function meccanici_backup() {
BASE="/mnt/meccanici"
DST="$BACK/disegni"
if ! mount | grep "meccanici"
	then mount $BASE || echo $EMOUNT" meccanici" && return
fi
for d in "PITAGORA" "Regina95" "JOLLY98" "JOLLY2001"
	do $RDIFF $BASE/$d $DST/$d
done
umount $BASE
}
function ldap_backup () {
slapcat -l $BACK/ldap/$(date +%d-%m-%y)-backup.ldif
}
 
function backup() {
#set -x
TMPFILE=`mktemp` || echo "impossibile creare il file"
if ! mount | grep backup
	then mount $BACK || echo "backup non trovato" &&  exit $EMOUNT
	else
		echo "inizio la procedura di backup" >> $TMPFILE
		sys_backup 2>> $TMPFILE >> $TMPFILE
		gest_backup 2>> $TMPFILE >> $TMPFILE
		meccanici_backup 2>> $TMPFILE >> $TMPFILE
		ldap_backup 2>> $TMPFILE >> $TMPFILE
		lvm_backup 2>> $TMPFILE >> $TMPFILE
fi
# loggo tutta la situazione
logger -t "backup" -f $TMPFILE
#eject $BACK
}
#backup
Uso rdiff-backup o rsync a seconda di cosa ha più senso, inoltre con lvm 
creo gli snapshots prima di eseguire il backup.

 EXCLUDE="/usr/local/bin/toexclude"
Perché in /usr/local/bin/? E' un file di configurazione, quindi andrebbe in
/etc o in /usr/local/etc


 /etc o in /usr/local/etc
Sì hai ragione è solo per comodità temporanea, lo sposto

 Cosa avrebbe di male questa forma (che č molto piů concisa)?
Le () fanno eseguire i comandi in una subshell, quindi l'ambiente non č
quello della shell corrente. Dovrebbe andare con le graffe {} al posto delle
tonde che servono per raggruppare i comandi nella shell corrente.
man bash e cerca "COMMAND EXECUTION ENVIRONMENT"


 is nothing left.
Sì avevo letto ma non avevo pensato che una subshell avrebbe creato
problemi, in effetti se non ho capito male non ritorna da tutta la
funzione ma solo dalla subshell, ho capito giusto?

Ecco qui lo script finale di backup su disco esterno (bacula con dds-4 è 
ancora in fase di configurazione)
http://paste-it.net/6725
Unica cosa che mi dà un po' fastidio è che viene loggato tutto alla 
fine, però in teoria le varie funzioni non dipendono dall'esecuzione 
delle precedenti, quindi non dovrbebe essere un problema.

 
http://paste-it.net/6725
IMHO troppi nomi fissi "cablati" nel codice, quindi codice troppo poco
generico e poco riutilizzabile. Sarò un maniaco, forse, ma l'avere a che
fare con installazioni replicate spesso decine di volte mi porta a ricercare
sempre la massima generalizzazione possibile/utile.
E' opportuno sempre mettere tutte le variabili ad inizio script, in modo che
 non si debba saltare su e giù quando si debbono fare delle modifiche, ed è
opportuno automatizzare il rilevamento delle impostazioni quando possibile
(
p.es
. i nomi degli lvm).
Se serve qualcosa di più allora meglio un file di configurazione da cui
leggere le variabili.
Es. di uno script generico che usavo su alcune installazioni xen di test:
http://www.zipman.it/ot/backup.sh
Non è un capolavoro, ma è giusto per rendere l'idea di quei due concetti
detti sopra.


 
Hai perfettamente ragione io di solito putroppo procedo in questo modo:
comincio a scrivere in modo abbastanza specifico poi appena mi rendo 
conto che mi sto ripetende generalizzo il più possibile.
Ora la bash è molto comoda per queste cose ma come linguaggio è 
veramente un delirio, se dovessi riscriverlo in python sarebbe 
sicuramente moolto più pulito, però probabilmente non vale la pena 
(tutte chiamate a popen praticamente).
La gestione degli argomenti passati alle funzioni più che altro mi 
angoscia, comunque vedrò di superare la schizzinosità :D
Interessante l'uso di tee per redirigere su file di log, però usando 
logger ho "gratis" le informazioni sull'ora (anche se tutte le 
operazioni vengono loggate come contemporanee ma poco male), tipo così
Feb 26 12:34:10 server backup: inizio backup dati
Feb 26 12:34:10 server backup: + lvcreate --snapshot -n dati_snap --size 
16m /dev/calzitex/dati
Feb 26 12:34:10 server backup:   Logical volume "dati_snap" created
Feb 26 12:34:10 server backup: + mount /dev/calzitex/dati_snap
Una cosa che voglio implementare tra l'altro è un controllo che il 
backup sia effettivamente andato a buon fine.
L'algoritmo di rsync a volte può sbagliare (dato il tipo di controllo 
che fa), ma facendo un check con strumenti esterni dovrei essere a posto.
Quale potrebbe essere la strategia più rapida e valida??
Avevo uno script python che lavorava sul checksum, devo verificare che 
non ci metta una vita.
La cosa più intelligente sarebbe controllare se sono effettivamente 
uguali solo i file modificati da rdiff-backup / rsync, magari basterebbe 
un controllo sui vari c-time / a-time etc etc.. mumble..

 Quale potrebbe essere la strategia più rapida e valida??
Oltre al controllo dell'error code sul rsync, puoi fare un secondo rsync.
Non dovrebbe cambiare nulla se è andato a buon fine il primo


 non ci metta una vita.
Ma l'opzione -c di rsync non fa gia' questa cosa?
-c, --checksum
   This forces the sender to checksum every regular file using  a
   128-bit  MD4  checksum.  It does this during the initial file-
   system scan as it builds the list of all available files.  The
   receiver then checksums its version of each file (if it exists
   and it has the same size as its  sender-side  counterpart)  in
   order  to  decide  which  files need to be updated: files with
   either a changed size or a changed checksum are  selected  for
   transfer.   Since this whole-file checksumming of all files on
   both sides of the connection occurs in addition to  the  auto-
   matic checksum verifications that occur during a file's trans-
   fer, this option can be quite slow.
   Note that rsync always verifies that each transferred file was
   correctly  reconstructed on the receiving side by checking its
   whole-file checksum,  but  that  automatic  after-the-transfer
   verification  has nothing to do with this option's before-the-
   transfer "Does this file need to be updated?" check.
-- 
Ciao.
Alessandro 
"Ubuntu" - an African word, meaning "Slackware is too hard for me".