]> git.alrj.org Git - brioche.git/blobdiff - brioche
FTP support, less (or different) bugs, updated documentation.
[brioche.git] / brioche
diff --git a/brioche b/brioche
index cedd8ed7b54fa9b92dcee36a167b79ddac2b6897..8e0597af7eb4dd503e769cd8da7402fd4a9cd88c 100755 (executable)
--- a/brioche
+++ b/brioche
 #
 # Note: This script relies on GNU tar specific options,
 # do not attempt to use it as-is with other tar implementations.
-#
-#
-# Example of use, from crontab
-# # Daily incremental backup
-# 30  3  *  *  1-6  /usr/local/bin/brioche > /var/log/backup.`date "+%a"`.log 2>&1
-# # Weekly full backup on Sunday
-# 30  3  *  *  0  /usr/local/bin/brioche -f > /var/log/backup.`date "+%a"`.log 2>&1
 
 
 # Mandatory
@@ -48,12 +41,10 @@ SNAPSHOT_NAME="backup-snap"
 SNAPSHOT_SIZE="5G"
 USAGE_WARN="80"
 
-# TODO: Implement the storage on a distant FTP
 USE_FTP="no"
-#FTP_HOST="ftpback.example.com"
-#FTP_USER="username"
-#FTP_PASS="password"
-#FTP_KEEP="4"
+FTP_HOST="ftpback.example.com"
+FTP_DIR="/"
+FTP_KEEP="4"
 
 # Ensure that we have a minimal PATH
 PATH=/sbin:/bin:/usr/sbin:/usr/bin
@@ -86,6 +77,26 @@ summary()
   echo $@ >> $SUMMARY
 }
 
+# Set final status to CRITICAL
+set_critical()
+{
+  FINAL_STATUS="CRITICAL"
+}
+
+set_error()
+{
+  if [ "$FINAL_STATUS" != "CRITICAL" ]; then
+    FINAL_STATUS="ERROR"
+  fi
+}
+
+set_warning()
+{
+  if [ "$FINAL_STATUS" == "SUCCESS" ]; then
+    FINAL_STATUS="WARNING"
+  fi
+}
+
 finish()
 {
   # Check free space
@@ -93,9 +104,7 @@ finish()
   log "${REPODIR} usage after backup: ${usage}%."
 
   if [ "$usage" -ge "$USAGE_WARN" ]; then
-    if [ "$FINAL_STATUS" = "SUCCESS" ]; then
-      FINAL_STATUS="WARNING"
-    fi
+    set_warning
     summary "Warning : Filesystem ${REPODIR} is ${usage}% full."
   fi
 
@@ -240,23 +249,71 @@ make_incr_backup()
   fi
 
   # Prepare the copy of the snar file
-  cp $fullsnar $destsnar
+  cp "$fullsnar" "$destsnar"
 
   # Do the actual backup. Destination file name and snar are like
   # /backup/valeron/root.incr.20090105.tar.bz2
   # /backup/valeron/root.incr.20090105.snar
   log "Running tar..."
-  tar -caf ${destfile} ${TAR_OPTS} ${COMPRESS_OPT} -g ${destsnar} $1
+  tar -cf ${destfile} ${TAR_OPTS} ${COMPRESS_OPT} -g ${destsnar} $1
 
   if [ ! "$?" = "0" ]; then
-    log "Error $?: Could not archive $hostname - $volumename"
+    log "Error $?: Could not archive $2 - $3"
     return 1
   fi
   return 0
 }
 
 
+#######################################################################
+#  FTP functions
+#######################################################################
 
+# Push everything in the directory given in $1 to the FTP server, under
+# /FTP_DIR/$2/latest
+ftp_push()
+{
+  log "Mirror $1 on FTP (${FTP_HOST})."
+  local source="${1}"
+  local target="${FTP_DIR}/${2}/latest"
+  local command="mkdir -p ${target}; cd ${target}"
+  command="${command}; mirror --reverse --only-newer --verbose ${source}"
+
+  lftp -e "${command}; exit" ${FTP_HOST}
+}
+
+# Rotate old files on FTP
+# Usage: ftp_rotate group
+ftp_rotate()
+{
+  log "Rotating backups of $1 on FTP (${FTP_HOST})."
+  local lastrun="run-${FTP_KEEP}"
+  local target="${FTP_DIR}/${1}"
+  local commands="mkdir -p ${target}; cd ${target}"
+
+  # Build commands
+  # Remove oldest run
+  if [ "$FTP_KEEP" != "0" ]; then
+    commands="$commands; rmdir ${lastrun}"
+
+    # Move everything back
+    for run in `seq $FTP_KEEP -1 2`; do
+      local newer=$run
+      let "newer -= 1"
+      commands="$commands; mv run-$newer run-$run"
+    done
+    # Move "old latest" to run-1
+    commands="$commands; mv latest run-1"
+  else
+    commands="$commands; rmdir latest"
+  fi
+
+  # Create "new latest" directory
+  commands="$commands; mkdir latest; exit"
+
+  # Run the commands on the FTP server
+  lftp -e "$commands" $FTP_HOST
+}
 #######################################################################
 #  Start here
 #######################################################################
@@ -270,14 +327,14 @@ then
   source "${CONFIG_FILE}"
 else
   summary "Error: Unable to read configuration file ${CONFIG_FILE}. Aborting."
-  FINAL_STATUS="CRITICAL"
+  set_critical
   finish
 fi
 
 if [ ! -r "${BACKUPTAB}" ]
 then
   summary "Error: Unable to read ${BACKUPTAB}. Aborting."
-  FINAL_STATUS="CRITICAL"
+  set_critical
   finish
 fi
 
@@ -315,6 +372,14 @@ esac
 #  Parse backuptab file, call backup functions for each line
 #######################################################################
 
+# Rotate FTP groups on full
+if [ "$USE_FTP" = "yes" -a "$DO_FULL_BACKUP" = "yes" ]; then
+  for group in `grep -v -E '^[[:space:]]*(#.*)?$' $BACKUPTAB | awk '{print $3}' | sort -u`
+  do
+    ftp_rotate $group
+  done
+fi
+
 # Ignore empty and commented lines
 grep -v -E '^[[:space:]]*(#.*)?$' $BACKUPTAB | tr -s [:space:]| while read line
 do
@@ -332,7 +397,7 @@ do
     make_snapshot $vg $lv
     if [ "$?" != "0" ]; then
       summary "Could not take a snapshot of $device"
-      FINAL_STATUS="ERROR"
+      set_error
       continue
       # Next one
     fi
@@ -341,10 +406,10 @@ do
     RETVAL="$?"
     if [ "$RETVAL" != "0" ]; then
       summary "Could not mount the snapshot of $device"
-      FINAL_STATUS="ERROR"
+      set_error
       if [ "$RETVAL" = "100" ]; then
         summary "Could not remove the snapshot !"
-        FINAL_STATUS="CRITICAL"
+        set_critical
         finish
       fi
       continue
@@ -364,7 +429,7 @@ do
       summary "INCREMENTAL backup of $device done on `NOW`."
     elif [ "$RETVAL" = "1" ]; then
       summary "Error during incremental backup of $device"
-      FINAL_STATUS="ERROR"
+      set_error
     elif [ "$RETVAL" = "2" ]; then
       summary "Can't do an incremental backup without a full one being present."
       summary "Switching to full backup for $device"
@@ -373,11 +438,11 @@ do
         summary "FULL backup of $device done on `NOW`."
       else
         summary "Error during full backup of $device"
-        FINAL_STATUS="ERROR"
+        set_error
       fi
     else
       summary "Unknown error during incremental backup of $device"
-      FINAL_STATUS="ERROR"
+      set_error
     fi
   else # Do a full backup
     make_full_backup ${BACKUP_SOURCE} $group $volume
@@ -385,7 +450,7 @@ do
       summary "FULL backup of $device done on `NOW`."
     else
       summary "Error during full backup of $device"
-      FINAL_STATUS="ERROR"
+      set_error
     fi
   fi
 
@@ -396,35 +461,31 @@ do
     unmount_snapshot $vg
     if [ "$?" != "0" ]; then
       summary "Could not unmount snapshot !"
-      FINAL_STATUS="CRITICAL"
+      set_critical
       finish
     fi
 
     remove_snapshot $vg
     if [ "$?" != "0" ]; then
       summary "Could not destroy the snapshot !"
-      FINAL_STATUS="CRITICAL"
+      set_critical
       finish
     fi
   fi
+
 done
 
-finish
+# Push everything on the FTP
+if [ "$USE_FTP" = "yes" ]; then
+  summary ""
+  for group in `grep -v -E '^[[:space:]]*(#.*)?$' $BACKUPTAB | awk '{print $3}' | sort -u`
+  do
+    ftp_push "$REPODIR/$group" $group
+    summary "Mirrored ${group} to ${FTP_HOST}."
+  done
+fi
 
-## Example Backup description table
-##
-## Can handle logical volumes, with snapshots, or plain mountpoints.
-## Priority is not used yet.
-#
-## Partition or LV        Snapshot     Host name       Volume name     Priority
-## ----------------------------------------------------------------------------
-#/                        no           cottman         root            1
-#/dev/vg00/kadarin-root   yes          kadarin         root            1
-#/dev/vg00/valeron-root   yes          valeron         root            1
-#/dev/vg00/syrtis-root    yes          syrtis          root            1
-#/dev/vg00/syrtis-home    yes          syrtis          home            1
-#/dev/vg00/syrtis-usr     yes          syrtis          usr             1
-#/dev/vg00/syrtis-var     yes          syrtis          var             1
-#/dev/vg00/syrtis-srv     yes          syrtis          srv             1
+
+finish