• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Täglicher cron Auftrag scheint nicht zu funktionieren

$cruffy

Member
Moin!

Ich habe ein Problem mit einem Backup Auftrag (duplicity). Der Auftrag für den Vollbackup soll immer an einem Samstag, zwischen den 21 und 28. Tag des Monats um 1930 Starten. Zusätzlich sollen 3x am Tag inkrementelle Sicherungen angelegt werden. Meine /etc/crontab sieht so aus:

Code:
root@server1:~# cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

30 19   21-28 1-12 6 root /usr/local/sbin/backup.sh full >/dev/null 2>&1

Mein /etc/cron.daily/ Verzeichnis beinhaltet die Datei "backup" mit folgenden Inhalt:
Code:
root@server1:~# cat /etc/cron.daily/backup
# /etc/cron.d/duplicity

00 18   * * *   root /usr/local/sbin/backup.sh >/dev/null 2>&1
00 02   * * *   root /usr/local/sbin/backup.sh >/dev/null 2>&1
00 10   * * *   root /usr/local/sbin/backup.sh >/dev/null 2>&1

Ich habe zunächst einen Vollbackup angelegt und dann sollte alles alle 8 Stunden inkrementell laufen bis zum nächsten Backup.

Jetzt zu meinem Problem - der Backup schien ein paar Tage zu laufen, doch jetzt merke ich, daß das letzte Backup vom 05. Mai, also schon 5 Tage her, ist.

Der Server speichert auf einen Netzwerkserver per scp die Dateien ab. Es ist noch mehr als genügend Speicherplatz am Ziel vorhanden. Zudem kann ich das Backup Script manuell ausführen:
Code:
root@server1:~# sh /usr/local/sbin/backup.sh

Das ist kein Problem - das Backup wird dann ausgeführt (inkrementell oder auch vollbackup - mit parameter "full").
 
A

Anonymous

Gast
$cruffy schrieb:
Mein /etc/cron.daily/ Verzeichnis beinhaltet die Datei "backup" mit folgenden Inhalt:
Code:
root@server1:~# cat /etc/cron.daily/backup
# /etc/cron.d/duplicity

00 18   * * *   root /usr/local/sbin/backup.sh >/dev/null 2>&1
00 02   * * *   root /usr/local/sbin/backup.sh >/dev/null 2>&1
00 10   * * *   root /usr/local/sbin/backup.sh >/dev/null 2>&1
Diese Datei gehört aber nicht in das /etc/cron.daily Verzeichnis sondern nach /etc/cron.d so wie es auch im Kommentar steht. Unter /etc/cron.daily stehen Scripte, keine crontab Dateien.
Sollte die Datei auch schon unterhalb von /etc/cron.d stehen, und der Prozess crond laufen, dann man einen touch auf /etc/cron.d/duplicity. Sollte crond nicht laufen dann
Code:
insserv cron 
service cron restart
und danach mal das Ende von /var/log/messages anschauen, ob es dort Probleme gab.

robi
 
OP
$

$cruffy

Member
Hi robi,
thx für die Erklärung. Ich habe die Veränderung vorgenommen und werde jetzt 1-2 Tage abwarten um festzustellen ob alles klappt.

Ist die Eintragung für den monatlichen Vollbackup Auftrag - in der cat /etc/crontab - richtig so?
Code:
30 19   21-28 1-12 6 root /usr/local/sbin/backup.sh full >/dev/null 2>&1

$cruffy schrieb:
Der Auftrag für den Vollbackup soll immer an einem Samstag, zwischen den 21 und 28. Tag des Monats um 1930 Starten.
 
A

Anonymous

Gast
$cruffy schrieb:
Ist die Eintragung für den monatlichen Vollbackup Auftrag - in der cat /etc/crontab - richtig so?
Code:
30 19   21-28 1-12 6 root /usr/local/sbin/backup.sh full >/dev/null 2>&1
Der Auftrag für den Vollbackup soll immer an einem Samstag, zwischen den 21 und 28. Tag des Monats um 1930 Starten.

bei den Monaten statt 1-12 kannst du genauso gut auch * nehmen, ein bisschen darauf achten, das dort immer nur ein Leerzeichen dazwischen ist
und 21-28 ist für meinen Geschmack ein Tag zu viel. In einem Monat an dem der Samstag auf einen 21 fällt, wäre der 28 auch ein Samstag.

funktioniert aber so nicht, denn der "Tag des Monats" und der "Tag der Woche" sind hier bei cron nicht wie die anderen Felder untereinander mit "und" logisch verbunden, sondern mit "einer von beiden"
bei deiner Konfiguration wird also jeden Sonnabend und zusätzlich noch vom 21 bis zum 28 jeden Tag eine Vollsicherung erzeugt.
Das ist eine sehr beliebte böse Falle bei den verschiedensten Prüfungen.
Manpage crontab(5) schrieb:
Note: The day of a command's execution can be specified in the following two fields — 'day of month', and 'day of week'. If both fields are restricted (i.e., do not contain the "*" character), the command will be run when either field matches the current
time. For example,
"30 4 1,15 * 5" would cause a command to be run at 4:30 am on the 1st and 15th of each month, plus every Friday.

Empfehlung:
cron jeden Sonnabend laufen lassen und im Backupscript abfragen ob der 21 des Monats schon vorbei ist oder die letzte Voll-Sicherung älter als 5 Wochen ist, ansonsten Script beenden.

robi
 
OP
$

$cruffy

Member
Wäre die Abfrage dann ung. so?

Code:
if [[ $(date -d "now + 1 day" +"%d") = "22,23,24,25,26,27,28" ]] 
then 'backup' 
else exit

Sorry, das scripten ist eindeutig meine Schwachstelle - kennst du vielleicht ein Beispielscript welches ich nutzen kann?
 
A

Anonymous

Gast
$cruffy schrieb:
Sorry, das scripten ist eindeutig meine Schwachstelle - kennst du vielleicht ein Beispielscript welches ich nutzen kann?

Das Problem hier den richtigen Test bei IF zu ermitteln, und zu testen.
einfach mal eine kleine Schleife bauen und 1 bis 31 drüber rauschen lassen zum spielen.
Code:
for TAGNR in $(seq 1 31); 
    do 
    echo " es ist der $TAGNR "
done
dort jetzt mal einen Test rein
Wenn man im Test versucht das auszufiltern was weniger Befehle in der Abarbeitung dieses Falles benötigt, wird das Gesamtscript meistens wesentlich übersichtlicher und leichter lesbar.
In diesem Fall den Programmabbruch, dort reicht ein exit.
Dieser Fall wäre zu definieren als zB. ((Zu Groß) oder (zu Klein))
setzen wir die Werte ein dann ( (größer als 28) oder ( kleiner als 22) )
Code:
for TAGNR in $(seq 1 31); 
    do 
    if test $TAGNR -gt 28 -o $TAGNR -lt 22 
        then 
        echo "heute ist $TAGNR kein Backup" 
    else
        echo "heute ist $TAGNR Backuptime"
   fi
done
wenn das soweit alles richtig aussieht dann wird die äußere Zahlschleife nicht mehr gebraucht, die Tagesnummer beziehen wir aus "date" ;
und auch die Anzeigen werden nicht mehr gebraucht, Wo bisher "kein Backup" angezeigt wurde muss einfach das Script beendet werden.
Den Else-Zeig "Backuptime" brauchen wird dann gar nicht mehr als Else Zeig zu schreiben, an dieser Stelle soll das Script einfach weiterlaufen und das Backupscript ausführen.
Code:
TAGNR=$(date +%d)
if test $TAGNR -gt 28 -o $TAGNR -lt 22 
     then exit
fi
# ab hier beginnt jetzt dein schon funktionierendes Backupscript
Da das Ganze in einem Cron-Job laufen soll, müssen wir uns jetzt nur noch die verwendeten Befehle anschauen. if then else und exit ist in der Bash enthalten, bleiben als Befehle nur test und date, die sind beide unterhalb von /usr/bin

"PATH=/usr/bin" sollte normalerweise schon bei Cron voreingestellt sein. ansonsten kann man sicherheitshalber die Befehle mit vollem Pathnamen schreiben
Code:
TAGNR=$(/usr/bin/date +%d)
if /usr/bin/test $TAGNR -gt 28 -o $TAGNR -lt 22 
     then exit
fi
# ab hier beginnt jetzt dein schon funktionierendes Backupscript

oder andere Möglichkeit, am Anfang des Backupscripts die PATH-Variable selbst nochmal so anpassen wie man sie benötigt.
Code:
PATH=$PATH:/usr/bin
(was aber wohl hier im Normalfall doppelt gemoppelt währe, da /usr/bin voreingestellt sein sollte.)

robi
 
OP
$

$cruffy

Member
Dann müsste ja die zusätzliche Abfrage wg. des Alters meines Vollbackups so ung. aussehen:
Code:
#!/bin/bash

TAGNR=$(date +%d)
if test $TAGNR -gt 28 -o $TAGNR -lt 22
     then exit
fi

if test %date /mnt/backup/backup-full* -lt 28
     then exit

fi

ab hier weiter im Script

Bitte nicht lachen wenn ich zuviele Fehler gemacht habe.

"backup-full*" ist der Namenpräfix der Dateien und davor der mount Pfad.
 
A

Anonymous

Gast
Zuerst mal was ganz Allgemeines.
Es ist schier unmöglich ein Script zu verbessern oder Vorschläge für Verbesserungen zu geben ohne es wenigstens ausschnittweise gesehen zu haben, bzw. eine exakte Beschreibung seiner Schnittstellen zu haben.

Irgendwo muss dein Script die Option "full" auswerten, da sowohl Inkrementelle als auch Vollbackups mit dem selben Script gemacht werden. Du kannst also keine Abbruch Abfrage einfach so an den Anfang des Scriptes stellen, sondern diese muss gezielt an die richtige Stelle.

Bei diesem Mountpath "/mnt/backup" muss man davon ausgehen das für Backups vorher gemountet werden muss, und dann nach dem Backup auch wieder umountet. In diesem Fall kann man aber ein Script nicht einfach mit exit beenden. Man muss eine Exit Prozedur schreiben, die sicher stellt, das das Dateisystem beim Abbruch ausgehängt wird.

Die Abfrage der Zeit der letzten Vollsicherung war nur ein optionaler Vorschlag für ein Sicherheitspolster, falls mal eine Vollsicherung ausgefallen ist, zB weil der Server down war. In diesem Fall sollten nicht ewige Zeit nur Inkrementelle Sicherungen gemacht werden, sondern bei dir zB an einem Sonnabend wenn die letzte Vollsicherung schon älter als 36 Tage ist ein Vollbackup eingeschoben werden. Das musst du nicht unbedingt haben.
Manchmal macht man dieses wie folgt. Ist die Sicherung gelaufen, überprüft man ob sich komplett ist und legt dann sich eine kleine Flag-Datei an, um das zu bestätigen. Was da drin steht ist eigentlich Wurscht, praktisch ist Datum, Rechnername und der Sicherungspath also zB sowas hier.
"12.05.2013 Vollsicherung Rechnername: Frieda ; Path:/....... Status : ok"
den Zeitstempel dieser Datei kann man dann heranziehen um zu erkennen wann das letzte Backup okay gelaufen ist.

Andere Möglichkeit das Backup trägt im Verzeichnisnamen das Datum. Dann wird es besonders einfach, da man nicht auf Zeitfunktionen zurückgreifen muss,

"backup-full*" ist der Namenpräfix der Dateien und davor der mount Pfad.
Mit diesen Informationen kann man nichts anfangen, sind das Archive, Verzeichnisse, Einzeldateien oder was sonst. Dieses hätte natürlich Einfluss wie man das Alter der letzten letzten Sicherung ermitteln kann.
Um das Alter von Datein zu bestimmen gibt es verschiedene Wege. oftmals wird sowas hier verwendet
Code:
if test $(find /mnt/backup -maxdepth 1 -name "testfile*" -daystart -mtime -35 2>/dev/null | wc -l) -lt 1 ; then ........

es geht aber auch so hier
Code:
SEC=$(($(date +%s) - $(stat -c %Z testfile)))
TAG=$(($SEC / 86400))
if test $TAG -gt 35 ; then .......
und dieses geht auch noch recht paraktisch bei verwickten Zeitproblemen mit Zuhilfenahme von Programmen die wirklich richtig rechnen und kaltulieren können, wie bc oder awk
Man kann auch viel einfachere Tests machen, wo man nur testet ob eine Datei älter als eine andere ist, und was weiß ich noch für 1000 andere Möglichkeiten.

Aber für alles muss man ein bischen programmieren können. sonst kann man nicht mal solche fast fertigen Konstrukte anpassen und verwenden ;)
Mache es dir nicht komplizierter wie du es im Moment mit deinen Kenntnissen verstehen kannst, oder nimm ein fix und fertiges Konzept, ohne das du da noch dran rumschrauben müsstest.

Backup ist übrigens keine richtige Speilwiese um Scripten zu erlenen, dazu ist die Sache viel zu ernst.

robi
 
OP
$

$cruffy

Member
Jop, das ist bei mir so eine Sache mit den Scripten. Ich versuche mich zu verbessern, allerdings habe ich viel zu wenig mit linux zu tun. Dieses script habe ich benutzt.

Code:
#!/bin/bash
#
# Simple script for creating backups with Duplicity.
# Full backups are made on the 1st day of each month or with the 'full' option.
# Incremental backups are made on any other days.
#
# USAGE: backup.sh [full]
#

# get day of the month
DATE=`date +%d`

# Set protocol (use scp for sftp and ftp for FTP, see manpage for more)
BPROTO=scp

# set user and hostname of backup account
BUSER='u10000'
BHOST='u10000.your-backup.de'

# Setting the password for the Backup account that the
# backup files will be transferred to.
# for sftp a public key can be used, see:
# http://wiki.hetzner.de/index.php/Backup
#BPASSWORD='yourpass'

# directories to backup (but . for /)
BDIRS="etc home srv ."
LOGDIR='/var/log/duplicity'

# Setting the pass phrase to encrypt the backup files. Will use symmetrical keys in this case.
PASSPHRASE='yoursecretgpgpassphrase'
export PASSPHRASE

# encryption algorithm for gpg, disable for default (CAST5)
# see available ones via 'gpg --version'
ALGO=AES

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

if [ $ALGO ]; then
 GPGOPT="--gpg-options '--cipher-algo $ALGO'"
fi

if [ $BPASSWORD ]; then
 BAC="$BPROTO://$BUSER:$BPASSWORD@$BHOST"
else
 BAC="$BPROTO://$BUSER@$BHOST"
fi

# Check to see if we're at the first of the month.
# If we are on the 1st day of the month, then run
# a full backup. If not, then run an incremental
# backup.

if [ $DATE = 01 ] || [ "$1" = 'full' ]; then
 TYPE='full'
else
 TYPE='incremental'
fi

for DIR in $BDIRS
do
  if [ $DIR = '.' ]; then
    EXCLUDELIST='/usr/local/etc/duplicity-exclude.conf'
  else
    EXCLUDELIST="/usr/local/etc/duplicity-exclude-$DIR.conf"
  fi

  if [ -f $EXCLUDELIST ]; then
    EXCLUDE="--exclude-filelist $EXCLUDELIST"
  else
    EXCLUDE=''
  fi

  # first remove everything older than 2 months
  if [ $DIR = '.' ]; then
   CMD="duplicity remove-older-than 2M -v5 $BAC/system >> $LOGDIR/system.log"
  else
   CMD="duplicity remove-older-than 2M -v5 $BAC/$DIR >> $LOGDIR/$DIR.log"
  fi
  eval $CMD

  # do a backup
  if [ $DIR = '.' ]; then
    CMD="duplicity $TYPE -v5 $GPGOPT $EXCLUDE / $BAC/system >> $LOGDIR/system.log"
  else
    CMD="duplicity $TYPE -v5 $GPGOPT $EXCLUDE /$DIR $BAC/$DIR >> $LOGDIR/$DIR.log"
  fi
  eval  $CMD

done

# Check the manpage for all available options for Duplicity.
# Unsetting the confidential variables
unset PASSPHRASE
unset FTP_PASSWORD

exit 0
 
A

Anonymous

Gast
Das Script ist doch fertig, du musst dich nur verabschieden von der Idee ein Vollbackup an einem Sonnabend zu machen und täglich 3 Incrementelle. Dieses Script wird am 1. des Monats sowieso immer automatisch Vollbackup machen, ob du willst oder nicht. Du brauchst dieses Script nur täglich 1 mal zu starten und nicht 3 Mal. Sonst bekommst du am 1. jeweils 3 Vollbackups. Dieses dem Script auszutreiben, würde bedeuten
Code:
if [ $DATE = 01 ] || [ "$1" = 'full' ]; then
 TYPE='full'
else
 TYPE='incremental'
fi
umzubauen und massiv zu erweitern.

Vollbackup mit der Option "full" ist in diesem Script wohl nur für einen händischen Start des Scriptes vorgesehen.

robi
 
OP
$

$cruffy

Member
Hallo robi.

Oder ich mache es aber so. Ich erstelle ein Script /usr/local/sbin/fullbackup.sh
Code:
#!/bin/sh

TAGNR=$(date +%d)
if test $TAGNR -gt 28 -o $TAGNR -lt 22
     then exit
fi

if test %date /mnt/backup/backup-full* -lt 28
     then exit

nohup sh /usr/local/sbin/backup.sh full >/dev/null 2>&1

exit 0

In der /etc/crontab schreibe ich dann:
Code:
30 19   * * 6 root /usr/local/sbin/fullbackup.sh >/dev/null 2>&1

Das müsste auch gehen... denke ich.
 
Oben