#!/usr/local/bin/bash # # Hjemmesnekret script som tar backup av PVV-servere. # # orjane - 2008.11.10 # # Oppdatert av pederbs og yorinad 2017.02.04 # # for å legge til en backup jobb: # zfs create principal/backupz/%name% # #sørg for at principal kan logge inn som brukerene på boksen uten passord: # #ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsCm6f5JOlKDbZMiQ6rXvU35QU4Gs/WKKlZymXtFxPhK5jBoZskQjNhfsr+peuhnZ1y+04L9qEBkN3jN0ThROaRaKSFVWfnMnij7pEB0bmJRxDmkQsHL7YsAm6tPn8116tt9m9ASPYE5RpnaDGtxTP7uXa42URvwXdvWY618tdX4z39JG9f85KYexhwRbhaBMLnSPH6JKCKu1tTBwr7oEbuhLFrFXQwqWRip/oN/6/eSxnIrwaey1GM+CdNfeGh/0OeQJ4XIUas2WbgiQRw6Dkxo32FeFS5LVaOYWRys6W3Znw9a9yOYImjJ8WUmiwSeN2bksUizNBNA1HBhoKGM5b root@alphys # declare -ra required_tools=( rsync ssh zfs zpool awk ) for tool in "${required_tools[@]}"; do if ! command -v "$tool" >/dev/null 2>&1; then echo "Mangler påkrevd verktøy: $tool" exit 1 fi done if [ "$(id -u)" -ne 0 ]; then echo "Må kjøres som root!" exit 1 fi # 5.1 er minimum pga. wait '-p' flagget. declare -r minimum_bash_major_version="5" declare -r minimum_bash_minor_version="1" if [ \ "${BASH_VERSINFO[0]}" -lt "$minimum_bash_major_version" ] || \ { [ "${BASH_VERSINFO[0]}" -eq "$minimum_bash_major_version" ] && \ [ "${BASH_VERSINFO[1]}" -lt "$minimum_bash_minor_version" ]; }; then echo "Må kjøres med bash versjon $minimum_bash_major_version eller nyere!" exit 1 fi echo "PVV; hjemmelaget backupscript (\$ git commit sha: $(cd /backupz && git rev-parse HEAD) \$)" echo date # Blir brukt som navn på ZFS-snapshot og logger. declare -r snapshot="$(date +%Y%m%d)" if [ "$1" = "full" ]; then # Fullbackupen starter før midnatt, legg på en dag declare -r snapshot=$(date -v +1d +%Y%m%d) fi declare -r lockfile="/backupz/backup.sh.lock" if [ -e $lockfile ]; then declare -r pid="$(cat $lockfile)" # TODO: Bruk bedre metode for å finne prosess. if ps -p "$pid"; then echo "Backup kjører allerede: $pid" exit 1 fi echo "Forrige backup ble avbrutt, rydder opp..." rm "$lockfile" zfs snapshot -r "principal/backupz@avbrutt_${snapshot}" && \ echo "ZFS-snapshot OK." || echo "ZFS-snapshot FEILET!" # TODO: zfs rollback til forrige komplette backup. echo "Ferdig med oppryddingen." fi # Fang SIGINT, vi vil rydde opp om vi blir avbrutt. on_sigint() { rm $lockfile echo 'Avbrutt, sletter låsfil...' exit 2 } trap on_sigint SIGINT echo "$$" > "$lockfile" echo "Sjekker at det er nok ledig plass på disken..." zfs get available principal/backupz #while [ $(/bin/df /backupz/ | /usr/bin/awk '/^backupz/{print $4}' ) -lt 100000000 ] ; do while [ "$(zfs get -Hp available principal/backupz | cut -f3)" -lt 50000000000 ] ; do echo; echo "Disken er nesten full, rydder"; echo declare -ri min_backups=5 if [ "$(zfs list -t snapshot | grep -c "backupz@")" -lt "$min_backups" ]; then echo; echo "Mindre enn $min_backups backups lagret, feiger ut fra sletting"; echo break; fi declare -r oldest=$(zfs list -t snapshot | grep backupz@ | head -n1 | tr @ ' ' | awk '{print $2}') echo "Kjører zfs destroy på alle disker @$oldest" for d in $(zfs list | grep ^principal/backupz | awk '{print $1}'); do zfs destroy "$d@$oldest" done zfs get available principal/backupz echo done echo "Starter backup..." echo "Snapshot ID: $snapshot" echo echo ### Liste over vertsmaskiner og hva som skal tas backup av. ### # TODO: kanskje noe av dette enklere kunne blitt uttrykt # med en egen json-fil og litt jq-magi? # Liste over vertsmaskiner som skal tas backup av. declare -a hosts=() # SSH-vertsnavn hvis det er forskjellig fra vertsnavnet i listen. declare -A host_ssh_hostname=() # Backup-katalog hvis den er forskjellig fra vertsnavnet i listen. declare -A hosts_output_dir=() # ameno hosts+=("ameno") declare -ra ameno_includes=( "/" "/boot/firmware" ) declare -ra ameno_excludes=( "/var/cache/" "/var/lib/snapd/" "/var/log/journal/" ) # knakelibrak (wiki) # hosts+=("knakelibrak_wiki") # host_ssh_hostname["knakelibrak_wiki"]="wiki" # hosts_output_dir["knakelibrak_wiki"]="wiki" # declare -ra wiki_includes=( # "/var/lib/mediawiki" # ) # declare -ra wiki_excludes=() # knakelibrak (databases) # hosts+=("knakelibrak_databases") # host_ssh_hostname["knakelibrak_databases"]="knakelibrak" # hosts_output_dir["knakelibrak_databases"]="databases" # declare -ra knakelibrak_databases_includes=( # "/var/backups/databases" # ) # declare -ra knakelibrak_databases_excludes=() # jokum (synapse) # hosts+=("jokum_synapse") # host_ssh_hostname["jokum_synapse"]="jokum" # hosts_output_dir["jokum_synapse"]="jokum/synapse" # declare -ra jokum_synapse_includes=( # "/data/synapse/" # ) # declare -ra jokum_synapse_excludes=() # skrotnisse # hosts+=("skrotnisse") # declare -ra skrotnisse_includes=( # "/var/www/" # "/srv/" # ) # declare -ra skrotnisse_excludes=() # dash8 # hosts+=("dash8") # declare -ra dash8_includes=( # "/var/lib/bitlbee/" # ) # declare -ra dash8_excludes=() # tim # hosts+=("tim") # hosts_output_dir["tim"]="web" # declare -ra tim_includes=( # "/var/lib/squirrelmail" # ) # declare -ra tim_excludes=() # microbel (hjemmeområder) hosts+=("homepvv") declare -ra homepvv_includes=( "/" "/boot" "/export/home/pvv" "/var" ) declare -ra homepvv_excludes=( # Se ./homepvv.exclude - den skal bli plukket opp automatisk ) # innovation hosts+=("innovation") declare -ra innovation_includes=( "/" "/boot/efi" ) declare -ra innovation_excludes=( "/srv/minecraft-pvv/" "/var/cache/" "/var/db/freebsd-update/files/" ) # lommel # hosts+=("lommel") # declare -ra lommel_includes=( # "/" # ) # declare -ra lommel_excludes=( # se ./lommel.exclude - den skal bli plukket opp automatisk # ) # sleipner hosts+=("sleipner") declare -ra sleipner_includes=( "/" ) declare -ra sleipner_excludes=( "/scratch/" "/var/cache/" ) # spikkjeposche # hosts+=("spikkjeposche") # declare -ra spikkjeposche_includes=( # "/usr/local/www" # "/usr/local/etc/lighttpd" # "/etc/ssl/private" # ) # declare -ra spikkjeposche_excludes=() # tom hosts+=("tom") declare -ra tom_includes=( "/" "/boot/efi" ) declare -ra tom_excludes=( "/var/cache/" ) ### Slutt på liste over vertsmaskiner og hva som skal tas backup av. ### #export RSYNC_RSH="ssh -c arcfour -v" export RSYNC_RSH="ssh -v" declare -r rsync="/usr/local/bin/rsync" declare -ra rsync_flags=( --archive --hard-links --one-file-system --compress --delete --numeric-ids --stats --inplace --relative --exclude=/.zfs/ ) declare -r logdir="/backupz/log" # Gjør selve overføringen. # Start på en liste over PID vi skal vente på. declare -A venteproc=() # Ikke kjoer med --checkum. Den er nyttig senere for aa detektere bitraate. # # Gjør "full"-backup på søndager. # if [ "$1" = "full" ]; then # Det er søndag # echo "Det er søndag; tar «full»-backup." # rsync_flags="${rsync_flags[@]} --checksum" # fi for host in "${hosts[@]}"; do declare -a command=( "$rsync" "${rsync_flags[@]}" "--log-file=${logdir}/${host}.log.$snapshot" ) declare exclude_paths_var="${host}_excludes[@]" declare -a exclude_paths=("${!exclude_paths_var}") for exclude in "${exclude_paths[@]}"; do command+=("--exclude=${exclude}") done if [ -f "/backupz/${host}.exclude" ]; then command+=("--exclude-from=/backupz/${host}.exclude") fi declare include_paths_var="${host}_includes[@]" declare -a include_paths=("${!include_paths_var}") if [ "${#include_paths[@]}" -eq 0 ]; then echo "Ingen inkluderingsstier for vert $host, hopper over." continue fi for include in "${include_paths[@]}"; do command+=("${host_ssh_hostname[$host]:-$host}:$include") done command+=("/backupz/${hosts_output_dir[$host]:-$host}/") echo "Starter backup for vert: $host" "${command[@]}" >"${logdir}/${host}.out.$snapshot" 2>&1 & venteproc[$!]="$host" echo "Startet $!: ${command[*]}" done echo echo "Rsync er i gang." # Vent til rsync er ferdig. echo "Venter til rsync er ferdig: ${!venteproc[*]}" while true; do wait -n -p pid; code=$? [[ -z "${pid}" ]] && break if [ $code -eq 0 ]; then echo "${pid} (${venteproc["$pid"]:-???}): OK" else echo "${pid} (${venteproc["$pid"]:-???}): Rsync returnerte feil (${code})" fi done echo echo "Rsync er ferdig." # Behoeves ikke da principal ikke har almen brukerinnlogging. # # Gjør hjemmemappene lesbare bare for brukeren. # find /backupz/homepvv/export/home/pvv -maxdepth 2 -mindepth 2 -exec chmod 700 {} \; # Touch home slik at timestamp på snapshot blir når backup var ferdig. touch /backupz/homepvv/export/home # Ta et zfs snapshot echo "Tar ZFS-snapshot..." zfs snapshot -r "principal/backupz@${snapshot}" && \ echo "ZFS-snapshot ferdig." || echo "ZFS-snapshot FEILET!" echo echo Ledig plass: "$(zfs list -H -o avail principal/backupz)" echo # TODO: Slett enkelte gamle snapshots? echo "Backup ferdig: $(date)" rm "$lockfile" zpool status -xv principal