summaryrefslogtreecommitdiff
path: root/byteback-backup
diff options
context:
space:
mode:
authorSteve Kemp <steve@steve.org.uk>2015-06-03 15:55:28 +0100
committerSteve Kemp <steve@steve.org.uk>2015-06-03 15:55:28 +0100
commita29380762b93737ae6949121010cd9bceb8196b2 (patch)
tree4dfe2931401d0cc73c38b9a90377e31210d6706e /byteback-backup
parentc4da983bd2a1e35450dcb21bdc7110f5fc0d166a (diff)
Relocated the binaries to bin/
Diffstat (limited to 'byteback-backup')
-rwxr-xr-xbyteback-backup264
1 files changed, 0 insertions, 264 deletions
diff --git a/byteback-backup b/byteback-backup
deleted file mode 100755
index ac9165a..0000000
--- a/byteback-backup
+++ /dev/null
@@ -1,264 +0,0 @@
-#!/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 'resolv'
-
-$LOAD_PATH.unshift('/usr/lib/byteback')
-
-require 'trollop'
-require 'byteback/util'
-require 'byteback/log'
-include Byteback::Util
-include Byteback::Log
-
-ME = $PROGRAM_NAME.split('/').last
-
-opts = Trollop.options do
- banner "#{ME}: Back up this system to a byteback-enabled server\n "
-
- opt :destination, 'Backup destination (i.e. user@host:/path)',
- type: :string
-
- opt :source, 'Source paths',
- type: :strings,
- default: ['/']
-
- opt :exclude, 'Paths to exclude',
- type: :strings,
- short: 'x'
-
- opt :verbose, 'Show debugging messages'
-
- opt :retry_number, 'Number of retries on error',
- type: :integer,
- default: 3
-
- opt :retry_delay, 'Number of seconds between retries after an error',
- type: :integer,
- default: 300
-
- opt :ssh_key, 'SSH key filename',
- type: :string,
- default: '/etc/byteback/key',
- short: 'k'
-
- opt :help, 'Show this message',
- short: 'h'
-
- banner "\nAdditional excludes can be specified using /etc/byteback/rsync_filter, which is an rsync filter file. See the rsync man page for information on how this works.\n"
-end
-
-lock_out_other_processes('byteback-backup')
-
-@ssh_key = opts[:ssh_key]
-@verbose = opts[:verbose] ? '--verbose' : nil
-@sources = opts[:source] if opts[:source]
-@excludes = opts[:exclude] if opts[:exclude]
-@destination = opts[:destination]
-@retry_number = opts[:retry_number]
-@retry_delay = opts[:retry_delay]
-
-# Read the default destination
-if File.exist?('/etc/byteback/destination')
- @destination = File.read('/etc/byteback/destination').chomp
-end
-
-# Set the default SSH key
-if File.exist?('/etc/byteback/key')
- @ssh_key = '/etc/byteback/key'
-end
-
-#
-# Check our destination
-#
-if @destination =~ /^(?:(.+)@)?([^@:]+):(.+)?$/
- @destination_user, @destination_host, @destination_path = [Regexp.last_match(1), Regexp.last_match(2), Regexp.last_match(3)]
-else
- fatal('Destination must be a remote path, e.g. ssh@host.com:/store/backups')
-end
-
-#
-# Validate & normalise source directories
-#
-@sources = ['/'] if @sources.nil?
-
-fatal('No sources specified') if @sources.empty?
-
-@sources = @sources.map do |s|
- s = s.gsub(/\/+/, '/')
- fatal("Can't read directory #{s}") unless File.readable?(s)
- s
-end
-
-# Automatically exclude anything mounted on a non-local filesystem, plus
-# various cache and temporary directories common on Bytemark & Debian
-# systems
-#
-if @excludes.nil?
-
- PROBABLY_LOCAL = %w(
- btrfs
- ext2
- ext3
- ext4
- reiserfs
- xfs
- nilfs
- jfs
- reiser4
- zfs
- rootfs
- )
-
- COMMON_JUNK = %w(
- /swap.file
- /tmp
- /var/backups/localhost
- /var/cache/apt/archives
- /var/lib/php5
- /var/tmp
- )
-
- MOUNT_HEADINGS = %w( spec file vfstype mntops freq passno )
- .map(&:to_sym)
-
- mounts = File.read('/proc/mounts').split("\n").map do |line|
- Hash[MOUNT_HEADINGS.zip(line.split(' '))]
- end
-
- @excludes =
-
- mounts
- .select { |m| !PROBABLY_LOCAL.include?(m[:vfstype]) }
- .map { |m| m[:file] } +
-
- COMMON_JUNK.select { |f| File.exist?(f) }
-
-end
-
-@excludes = @excludes.map do |e|
- e.gsub(/\/+/, '/')
-end
-
-fatal('Must suply --destination or put it into /etc/bytebackup/destination') unless @destination
-
-#
-# Test ssh connection is good before we start
-#
-fatal("Could not read ssh key #{@ssh_key}") unless File.readable?(@ssh_key)
-
-def ssh(*ssh_args)
- args = ['ssh',
- '-o', 'BatchMode=yes',
- '-o', 'ConnectionAttempts=5',
- '-o', 'ConnectTimeout=30',
- '-o', 'ServerAliveInterval=60',
- '-o', 'TCPKeepAlive=yes',
- '-x', '-a',
- '-i', @ssh_key,
- '-l', @destination_user,
- @destination_host
- ] +
- ssh_args
- .map { |a| a ? a : '' }
-
- log_system(*args)
-end
-
-fatal("Could not connect to #{@destination}") unless
- ssh('byteback-receive', '--ping', @verbose) == 0
-
-#
-# 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.
- #
- # The timeout is set to 12 hours - rsync can spend a long time at the
- # far end checking over its files at the far end without transfer, so we
- # want to wait as long as possible without jeopardising the timing of the
- # next backup run. Obviously if rsync itself takes nearly 24 hours for a
- # given filesystem, daily backups (with this tool) are out of the question.
- #
- args = %w( rsync --archive --numeric-ids --delete-delay --inplace --relative --timeout 43200 )
-
- args += ['--rsh', "ssh -o BatchMode=yes -x -a -i #{@ssh_key} -l #{@destination_user}"]
- args << '--verbose' if @verbose
- args += @excludes.map { |x| ['--exclude', x] }.flatten
-
- #
- # Add in the rsync excludes and sources files, if present.
- #
- if File.exist?('/etc/byteback/excludes')
- args += ['--exclude-from', '/etc/byteback/excludes']
- end
-
- #
- # Add in an rsync_filter if required.
- #
- if File.exist?('/etc/byteback/rsync_filter')
- args += ['--filter', 'merge /etc/byteback/rsync_filter']
- end
-
- #
- # To add extra rsync flags, a file can be used. This can have flags all on one line, or one per line.
- #
- if File.exist?('/etc/byteback/rsync_flags')
- args += File.readlines('/etc/byteback/rsync_flags').map(&:chomp)
- end
-
- args += ['--rsync-path', 'rsync --fake-super']
-
- args += sources
- args << @destination
-
- log_system(*args)
-end
-
-#
-# We treat exit statuses 0 and 24 as success; 0 is "Success"; 24 is "Partial
-# transfer due to vanished source files", which we treat as success otherwise
-# on some hosts the backup process never finishes.
-#
-RSYNC_EXIT_STATUSES_TO_ACCEPT = [0, 24]
-RSYNC_EXIT_STATUSES_TO_RETRY_ON = [10, 11, 20, 21, 22, 23, 30]
-
-# Run the file copy, retrying if necessary
-#
-loop do
- status = rsync(*@sources)
-
- if RSYNC_EXIT_STATUSES_TO_ACCEPT.any? { |s| s === status }
- break
- elsif RSYNC_EXIT_STATUSES_TO_RETRY_ON.any? { |s| s === status }
-
- warn "rsync exited with status #{status}"
-
- if @retry_number > 0
- warn "rsync will retry #{@retry_number} more times, sleeping #{@retry_delay}s"
- @retry_number -= 1
- sleep @retry_delay
- redo
- else
- fatal('Maximum number of rsync retries reached')
- end
- else
- fatal("Fatal rsync error occurred (#{status})")
- end
-end
-
-info('Backup completed, requesting snapshot')
-
-# Mark the backup as done on the other end
-#
-fatal('Backup could not be marked complete') unless
- ssh('byteback-receive', '--complete', @verbose) == 0
-
-info('Finished')