diff options
author | Matthew Bloch <matthew@bytemark.co.uk> | 2014-01-08 13:19:01 +0000 |
---|---|---|
committer | Matthew Bloch <matthew@bytemark.co.uk> | 2014-01-08 13:19:01 +0000 |
commit | ae4967f4cf354a76af18e8d4af91f73af7d648d2 (patch) | |
tree | 1f92dcb35506f6d793250db76cc7b6cc56ff122d /byteback-backup | |
parent | 54d53f2091a90e7ab75033a74f29ab9c2cb029c7 (diff) |
Normalized line endings
Diffstat (limited to 'byteback-backup')
-rwxr-xr-x | byteback-backup | 358 |
1 files changed, 179 insertions, 179 deletions
diff --git a/byteback-backup b/byteback-backup index ffc4186..430975e 100755 --- a/byteback-backup +++ b/byteback-backup @@ -1,179 +1,179 @@ -#!/usr/bin/ruby -# -# Back up this system to a byteback-enabled server (just some command line -# tools and SSH setup). We aim to make sure this backups are easy, complete -# and safe for most types of hosting customer. -# -# See 'man byteback' for more information. - -require 'trollop' -require 'resolv' - -@sources = ["/"] -@exclude = ["/swap.file", "/var/backups/localhost"] - -def error(message) - STDERR.print "*** #{message}\n" - exit 1 -end - -def verbose(message) - print "#{message}\n" -end - -opts = Trollop::options do - - opt :destination, "Backup destination (i.e. user@host:/path)", - :type => :string - - opt :source, "Source paths", - :type => :strings - - opt :verbose, "Show rsync command and progress" - - opt :retry_number, "Number of retries on error", - :type => :integer, - :default => 3 - - opt :retry_delay, "Wait number of seconds between retries", - :type => :integer, - :default => 1800 - - opt :ssh_key, "SSH key for connection", - :type => :string, - :default => "/etc/byteback/key" -end - -@ssh_key = opts[:ssh_key] -@verbose = opts[:verbose] ? "--verbose" : nil -@sources = opts[:source] if opts[:source] -@destination = opts[:destination] -@retry_number = opts[:retry_number] -@retry_delay = opts[:retry_delay] - -if !@destination && File.exists?("/etc/byteback/destination") - @destination = File.read("/etc/byteback/destination").chomp -end -error("Must suply --destination or put it into /etc/bytebackup/destination") unless @destination - -_dummy, @destination_user, @destination_host, colon, @destination_path = - /^(.*)?(?:@)([^:]+)(:)(.*)?$/.match(@destination).to_a - -error("Must be a remote path") unless colon - -# Validate & normalise source directories -# -error("No sources specified") if @sources.empty? -@sources = @sources.map do |s| - s = s.gsub(/\/+/,"/") - error("Can't read directory #{s}") unless File.readable?(s) - s -end - -# Guess destination for backup -# -if !@destination - guesses = [] - hostname = `hostname -f` - Resolv::DNS.open do |dns| - suffix = hostname.split(".")[2..-1].join(".") - ["byteback." + suffix].each do |name| - [Resolv::DNS::Resource::IN::AAAA, - Resolv::DNS::Resource::IN::A].each do |record_type| - next if !guesses.empty? # only care about first result - guesses += dns.getresources(name, record_type) - end - end - end - - if guesses.empty? - error "Couldn't guess at backup host, please specify --destination" - end - - # ick, do I really have to do this to get a string represnetion of - # the IP address? - # - guess = guesses.first.inspect - match = / (.*)>$/.match(guess)[1] - error "Result #{guesses} is not an IP" if !match - @destination = "byteback@#{match[1]}:#{HOSTNAME}/current/" - - verbose "Guessed destination=#{@destination} from #{guess}" -end - -# Test ssh connection is good before we start -# -error("Could not read ssh key #{@ssh_key}") unless File.readable?(@ssh_key) - -def ssh(*args) - ["ssh", - "-o", "BatchMode=yes", - "-x", "-a", - "-i", @ssh_key, - "-l", @destination_user - ] + - args -end - -error("Could not connect to #{@destination}") unless - system(*ssh("byteback-receive", "--ping", @verbose)) - -# Call rsync to copy certain sources, returns exit status (see man rsync) -# -def rsync(*sources) - # Default options include --inplace because we only care about consistency - # at the end of the job, and rsync will do more work for big files without - # it. - # - args = [ - "rsync", - "--archive", - "--numeric-ids", - "--delete", - "--inplace", - "--rsync-path", - "rsync --fake-super", - "--rsh", - ssh.join(" "), - "--delete", - "--one-file-system", - "--relative" - ] - - args << "--verbose" if @verbose - args += @exclude.map { |x| ["--exclude", x] }.flatten - args += sources - args << @destination - - print args.map { |a| / /.match(a) ? "\"#{a}\"" : a }.join(" ")+"\n" if @verbose - system(*args) - - return $?.exitstatus -end - -RSYNC_EXIT_STATUSES_TO_RETRY_ON = [10,11,20,21,22,23,24,30] - -# Run the file copy, retrying if necessary -# -loop do - status = rsync(*@sources) - - if status === 0 - break - elsif RSYNC_EXIT_STATUSES_TO_RETRY_ON.include?(status) - if @retry_number > 0 - @retry_number -= 1 - sleep @retry_delay - redo - else - error("Maximum number of rsync retries reached") - end - else - error("Fatal rsync error occurred (#{status})") - end -end - -# Mark the backup as done on the other end -# -error("Backup could not be marked complete") unless - system(*ssh("sudo", "byteback-snapshot", "--snapshot", @verbose)) +#!/usr/bin/ruby
+#
+# Back up this system to a byteback-enabled server (just some command line
+# tools and SSH setup). We aim to make sure this backups are easy, complete
+# and safe for most types of hosting customer.
+#
+# See 'man byteback' for more information.
+
+require 'trollop'
+require 'resolv'
+
+@sources = ["/"]
+@exclude = ["/swap.file", "/var/backups/localhost"]
+
+def error(message)
+ STDERR.print "*** #{message}\n"
+ exit 1
+end
+
+def verbose(message)
+ print "#{message}\n"
+end
+
+opts = Trollop::options do
+
+ opt :destination, "Backup destination (i.e. user@host:/path)",
+ :type => :string
+
+ opt :source, "Source paths",
+ :type => :strings
+
+ opt :verbose, "Show rsync command and progress"
+
+ opt :retry_number, "Number of retries on error",
+ :type => :integer,
+ :default => 3
+
+ opt :retry_delay, "Wait number of seconds between retries",
+ :type => :integer,
+ :default => 1800
+
+ opt :ssh_key, "SSH key for connection",
+ :type => :string,
+ :default => "/etc/byteback/key"
+end
+
+@ssh_key = opts[:ssh_key]
+@verbose = opts[:verbose] ? "--verbose" : nil
+@sources = opts[:source] if opts[:source]
+@destination = opts[:destination]
+@retry_number = opts[:retry_number]
+@retry_delay = opts[:retry_delay]
+
+if !@destination && File.exists?("/etc/byteback/destination")
+ @destination = File.read("/etc/byteback/destination").chomp
+end
+error("Must suply --destination or put it into /etc/bytebackup/destination") unless @destination
+
+_dummy, @destination_user, @destination_host, colon, @destination_path =
+ /^(.*)?(?:@)([^:]+)(:)(.*)?$/.match(@destination).to_a
+
+error("Must be a remote path") unless colon
+
+# Validate & normalise source directories
+#
+error("No sources specified") if @sources.empty?
+@sources = @sources.map do |s|
+ s = s.gsub(/\/+/,"/")
+ error("Can't read directory #{s}") unless File.readable?(s)
+ s
+end
+
+# Guess destination for backup
+#
+if !@destination
+ guesses = []
+ hostname = `hostname -f`
+ Resolv::DNS.open do |dns|
+ suffix = hostname.split(".")[2..-1].join(".")
+ ["byteback." + suffix].each do |name|
+ [Resolv::DNS::Resource::IN::AAAA,
+ Resolv::DNS::Resource::IN::A].each do |record_type|
+ next if !guesses.empty? # only care about first result
+ guesses += dns.getresources(name, record_type)
+ end
+ end
+ end
+
+ if guesses.empty?
+ error "Couldn't guess at backup host, please specify --destination"
+ end
+
+ # ick, do I really have to do this to get a string represnetion of
+ # the IP address?
+ #
+ guess = guesses.first.inspect
+ match = / (.*)>$/.match(guess)[1]
+ error "Result #{guesses} is not an IP" if !match
+ @destination = "byteback@#{match[1]}:#{HOSTNAME}/current/"
+
+ verbose "Guessed destination=#{@destination} from #{guess}"
+end
+
+# Test ssh connection is good before we start
+#
+error("Could not read ssh key #{@ssh_key}") unless File.readable?(@ssh_key)
+
+def ssh(*args)
+ ["ssh",
+ "-o", "BatchMode=yes",
+ "-x", "-a",
+ "-i", @ssh_key,
+ "-l", @destination_user
+ ] +
+ args
+end
+
+error("Could not connect to #{@destination}") unless
+ system(*ssh("byteback-receive", "--ping", @verbose))
+
+# Call rsync to copy certain sources, returns exit status (see man rsync)
+#
+def rsync(*sources)
+ # Default options include --inplace because we only care about consistency
+ # at the end of the job, and rsync will do more work for big files without
+ # it.
+ #
+ args = [
+ "rsync",
+ "--archive",
+ "--numeric-ids",
+ "--delete",
+ "--inplace",
+ "--rsync-path",
+ "rsync --fake-super",
+ "--rsh",
+ ssh.join(" "),
+ "--delete",
+ "--one-file-system",
+ "--relative"
+ ]
+
+ args << "--verbose" if @verbose
+ args += @exclude.map { |x| ["--exclude", x] }.flatten
+ args += sources
+ args << @destination
+
+ print args.map { |a| / /.match(a) ? "\"#{a}\"" : a }.join(" ")+"\n" if @verbose
+ system(*args)
+
+ return $?.exitstatus
+end
+
+RSYNC_EXIT_STATUSES_TO_RETRY_ON = [10,11,20,21,22,23,24,30]
+
+# Run the file copy, retrying if necessary
+#
+loop do
+ status = rsync(*@sources)
+
+ if status === 0
+ break
+ elsif RSYNC_EXIT_STATUSES_TO_RETRY_ON.include?(status)
+ if @retry_number > 0
+ @retry_number -= 1
+ sleep @retry_delay
+ redo
+ else
+ error("Maximum number of rsync retries reached")
+ end
+ else
+ error("Fatal rsync error occurred (#{status})")
+ end
+end
+
+# Mark the backup as done on the other end
+#
+error("Backup could not be marked complete") unless
+ system(*ssh("sudo", "byteback-snapshot", "--snapshot", @verbose))
|