diff --git a/ChangeLog b/ChangeLog index 7ead3730466988fa05f9c5f145492dc39aeeaebd..a6089a85d10a0edbef4229a576ab2ec9197ccce2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,27 @@ +2006-10-23 Per Cederqvist <ceder@lysator.liu.se> + + LYSrdiff can now backup up to separate partitions, creates more + state timestamp files, randomizes the backup order, and backs up + most user data. + + * fetch-backup-work: Fetch all lsvn, lyscvs, lyswww and home + tasks, not just a select few. Fetch roxen tasks. + + * backup-all: New arguments: a list of lysrdiffpart partitions to + run. Check that the correct filesystems are mounted before doing + anything. + + * backup-one-task: New argument: lysrdiffpart. That argument + specifies which lysrdiff partition that the backup should be + stored on. It is a small integer. Adjusted the paths to handle + it. Skip manhattan, since it is (temporarily) dead. Store state + information in a separate directory, and touch flag files for when + a backup starts and ends, fails and is being attempted. + + * distribute-tasks: New script. This script is responsible for + assigning new tasks to lysrdiff partitions. It also randomizes + the order of the tasks, to make the backup more fair. + 2006-10-14 Per Cederqvist <ceder@lysator.liu.se> Initial checkin of the proof-of-concept scripts used to backup diff --git a/backup-all b/backup-all index 94473d0ec358155ed9488bbcc7a4b1693c5bbe00..5bd1a0fdcd5e37f6f30102da28a3cd29e7b21e4b 100755 --- a/backup-all +++ b/backup-all @@ -1,11 +1,37 @@ #!/bin/sh -df -h /nobackup/backup.lysator/backups +PARTS="$@" -while read category subcategory server serverpath +if [ "$PARTS" = "" ] +then + echo $0: you forgot to specify what parts to back up >&2 + exit 1 +fi + +df -h /lysrdiff/0/perm | sed -n 1p +for lysrdiffpart in $PARTS +do + df -h /lysrdiff/$lysrdiffpart/perm | sed 1d +done + +for lysrdiffpart in $PARTS +do + if [ "`cat /lysrdiff/$lysrdiffpart/perm/lysrdiff.id`" != "$lysrdiffpart perm" ] + then + echo lysrdiffpart $lysrdiffpart not found >&2 + exit 1 + fi +done + +/nobackup/backup.lysator/bin/distribute-tasks + +for lysrdiffpart in $PARTS do - /nobackup/backup.lysator/bin/backup-one-task \ - "$category" "$subcategory" "$server" "$serverpath" -done < /nobackup/backup.lysator/var/tasks + while read category subcategory server serverpath + do + /nobackup/backup.lysator/bin/backup-one-task \ + $lysrdiffpart "$category" "$subcategory" "$server" "$serverpath" + done < /lysrdiff/$lysrdiffpart/perm/lysrdiff/tasks +done -df -h /nobackup/backup.lysator/backups +df -h /lysrdiff/0/perm /lysrdiff/1/perm diff --git a/backup-one-task b/backup-one-task index f0c918e8413b37605fee51809ccf4920a6ac365d..cf9805fa7cbd738bd5bf5cc334347090888ba8fd 100755 --- a/backup-one-task +++ b/backup-one-task @@ -1,16 +1,17 @@ #!/bin/sh -if [ $# != 4 ] +if [ $# != 5 ] then - echo $0: usage: $0 category subcategory server serverpath >&2 - echo Example: $0 home ceder inservitus /export/home/ceder >&2 + echo $0: usage: $0 lysrdiffpart category subcategory server serverpath >&2 + echo Example: $0 0 home ceder inservitus /export/home/ceder >&2 exit 1 fi -category="$1" -subcategory="$2" -server="$3" -serverpath="$4" +lysrdiffpart="$1" +category="$2" +subcategory="$3" +server="$4" +serverpath="$5" case "$server" in manhattan) remoterdiff=/usr/bin/rdiff-backup;; @@ -18,19 +19,46 @@ case "$server" in *) remoterdiff=/usr/local/bin/rdiff-backup;; esac -base="/nobackup/backup.lysator/backups/$category/$subcategory" +lysrdiff="/lysrdiff/$lysrdiffpart/perm/lysrdiff" +base="$lysrdiff/backups/$category/$subcategory" exclude="$base"/exclude files="$base"/files +state="$lysrdiff"/state mkdir -p "$files" -rm -f "$exclude" + +statebase="$state"/"$category"-"$subcategory" + +#if [ ! -f "$statebase"-fail ] +#then +# exit 0 +#fi + +if [ "$server" = manhattan ] +then + exit 0 +fi # Fetch an up-to-date exclude file. +rm -f "$exclude" scp -i /root/.ssh/backupkey "$server":"$serverpath"/.lysbackupexclude \ "$exclude" -rdiff-backup --exclude-other-filesystems --null-separator \ - --remote-schema \ - 'ssh -a -k -x -i /root/.ssh/backupkey %s '$remoterdiff' --server' \ - "$server"::"$serverpath" "$files" \ - && touch "$base"/last-good-backup +touch "$base"/backup-attempt-start +touch "$statebase"-attempt + +if rdiff-backup --exclude-other-filesystems --null-separator \ + --remote-schema \ + 'ssh -a -k -x -i /root/.ssh/backupkey %s '$remoterdiff' --server' \ + "$server"::"$serverpath" "$files" +then + touch "$base"/last-good-backup + mv "$base"/backup-attempt-start "$base"/last-good-start + touch "$statebase"-end + mv "$statebase"-attempt "$statebase"-start + rm -f "$base"/last-failure + rm -f "$statebase"-fail +else + mv "$base"/backup-attempt-start "$base"/last-failure + mv "$statebase"-attempt "$statebase"-fail +fi diff --git a/distribute-tasks b/distribute-tasks new file mode 100755 index 0000000000000000000000000000000000000000..067568225444f8d30d5cbb6c236f36e988714b7a --- /dev/null +++ b/distribute-tasks @@ -0,0 +1,114 @@ +#!/usr/bin/env python + +import os +import sys +import random + +ROOT = "/lysrdiff" + +class JobInfo(object): + def __init__(self, category, subcategory, host, directory, + lysrdiffpart=None): + self.__category = category + self.__subcategory = subcategory + self.__host = host + self.__directory = directory + self.__lysrdiffpart = lysrdiffpart + + def set_lysrdiffpart(self, part): + self.__lysrdiffpart = part + + def category(self): + return self.__category + + def subcategory(self): + return self.__subcategory + + def host(self): + return self.__host + + def directory(self): + return self.__directory + + def lysrdiffpart(self): + return self.__lysrdiffpart + + def source(self): + return (self.host(), self.directory()) + + def rdiff_dest(self): + return "/lysrdiff/%d/perm/lysrdiff/backups/%s/%s" % ( + self.lysrdiffpart(), self.category(), self.subcategory()) + + def task_desc(self): + return "%s %s %s %s" % ( + self.category(), self.subcategory(), + self.host(), self.directory()) + +def newtasks(): + return int(open("/nobackup/backup.lysator/var/newtasks").read()) + +# key: (host, directory) +# value: JobInfo +tasks_per_source = {} + +fatal = False + +def tasklist_file(lysrdiffpart): + return "/lysrdiff/%d/perm/lysrdiff/tasks" % lysrdiffpart + +def parse_line(line, lysrdiffpart=None): + [category, subcategory, host, directory] = line.split() + info = JobInfo(category, subcategory, host, directory, lysrdiffpart) + return info + +def read_tasks(lysrdiffpart): + global fatal + + for line in file(tasklist_file(lysrdiffpart), "r"): + info = parse_line(line, lysrdiffpart) + + if (info.host(), info.directory()) in tasks_per_source: + sys.stderr.write("Duplicate backup detected!\n %s\n %s\n" % ( + tasks_per_source[info.source()].task_desc(), + info.task_desc())) + fatal = True + + tasks_per_source[info.source()] = info + +def read_new_tasks(): + new_found = False + for line in file("/nobackup/backup.lysator/var/tasks"): + info = parse_line(line) + if (info.host(), info.directory()) not in tasks_per_source: + info.set_lysrdiffpart(newtasks()) + tasks_per_source[(info.host(), info.directory())] = info + new_found = True + + return new_found + +def write_task_lists(): + jobs = tasks_per_source.values() + random.shuffle(jobs) + files = {} + for job in jobs: + if job.lysrdiffpart() not in files: + files[job.lysrdiffpart()] = file( + tasklist_file(job.lysrdiffpart()) + ".new", "w") + files[job.lysrdiffpart()].write(job.task_desc() + "\n") + for lysrdiffpart, fp in files.items(): + fp.close() + fn = tasklist_file(lysrdiffpart) + os.rename(fn + ".new", fn) + +def main(): + global fatal + + for lysrdiffpart in range(2): + read_tasks(lysrdiffpart) + read_new_tasks() + if not fatal: + write_task_lists() + +if __name__ == '__main__': + main() diff --git a/fetch-backup-work b/fetch-backup-work index 9fa70b11184938b5a99b3988f3864bed81467cf6..1f0ab021630d5608ef09c73914dc217fdb79c804 100755 --- a/fetch-backup-work +++ b/fetch-backup-work @@ -4,14 +4,14 @@ rm /nobackup/backup.lysator/var/tasks ssh stalingrad ls -1 /svnroot \ | sort \ - | head -10 \ - | awk '{print "lsvn", $1, "stalingrad /svnroot/" $1}' \ + | awk '$1 == "lost+found" { next } + {print "lsvn", $1, "stalingrad /svnroot/" $1}' \ >> /nobackup/backup.lysator/var/tasks ssh stalingrad ls -1 /cvsroot \ | sort \ - | head -10 \ - | awk '{print "lyscvs", $1, "stalingrad /cvsroot/" $1}' \ + | awk '$1 == "lost+found" { next } + {print "lyscvs", $1, "stalingrad /cvsroot/" $1}' \ >> /nobackup/backup.lysator/var/tasks ssh uhumhummy ls -1 /lysator/lyswww/users/common \ @@ -19,17 +19,42 @@ ssh uhumhummy ls -1 /lysator/lyswww/users/common \ | grep -v THIS_IS_USERWEB \ | grep -v '^cap\.fm$' \ | sort \ - | grep -v '^a' \ - | grep -v '^b' \ - | head -50 \ | awk '{print "lyswww", $1, "uhumhummy /lysator/lyswww/users/common/" $1}' \ >> /nobackup/backup.lysator/var/tasks +ssh uhumhummy ls -1 /lysator/lyswww/users/roxen_only \ + | sort \ + | awk '{print "roxen", $1, "uhumhummy /lysator/lyswww/users/roxen_only/" $1}'\ +>> /nobackup/backup.lysator/var/tasks + ssh nema.lysator.liu.se ypcat -k auto_home \ | sort \ | grep -v DELETE \ | grep -v '^ *$' \ - | head -75 \ | sed 's/:/ /' \ + | awk '$1 == "mailman" { next } + $1 == "patrick" { next } + $1 == "snapshot" { next } + $1 == "u1" { next } + $1 == "u2" { next } + $1 == "u3" { next } + $1 == "u4" { next } + $1 == "u5" { next } + $1 == "u6" { next } + $1 == "lysdisk1" { next } + $1 == "lysdisk2" { next } + $1 == "lysdisk3" { next } + $1 == "lysdisk4" { next } + $1 == "lysdisk5" { next } + $1 == "lysdisk6" { next } + $1 == "lysdisk7" { next } + $1 == "lysdisk8" { next } + $1 == "lysdisk9" { next } + $1 == "lysdisk10" { next } + $1 == "lysdisk11" { next } + $1 == "kheldar" { next } + $1 == "quota1" { next } + $1 == "sge" { next } + { print }' \ | sed 's/^/home /' \ >> /nobackup/backup.lysator/var/tasks