Skip to content

Instantly share code, notes, and snippets.

@mmrwoods
Created July 11, 2011 12:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmrwoods/1075722 to your computer and use it in GitHub Desktop.
Save mmrwoods/1075722 to your computer and use it in GitHub Desktop.
Copy dumb-ass daily backups to remote servers using scp, genius!
#!/usr/bin/env ruby
# Dumb-ass Remote Copy - Copy dumb-ass daily backups to remote servers using scp, genius!
#
# Copies today's sub-directory of local source directory to remote destination directory.
# Uses only ssh and scp, but requires batch mode / authorized keys.
# Does not "sync" files, today's destination directory is trashed and everything is copied.
# Copies recursively, maintaining directory structure on remote host, but does so by creating
# directories as required and executing scp once for each file to copy - slow, but robust.
# Create a /etc/dumb_ass_remote_copy.yml config file to override default configuration options.
# Remote host name/address must be provided, as sole command line argument or in config file.
require 'yaml'
require 'fileutils'
require 'find'
require 'shellwords'
include Shellwords
config = File.exist?("/etc/dumb_ass_remote_copy.yml") ? YAML::load_file("/etc/dumb_ass_remote_copy.yml") : {}
source = config['source'] || "/var/local/backup/daily/"
destination = config['destination'] || "backup/remote/" + `hostname`.chomp
host = ARGV.size == 1 ? ARGV[0].split('@').last : config['host']
port = config['port'] || "22"
user = ARGV.size == 1 ? ARGV[0].split('@').first : ( config['user'] || `whoami`.chomp )
raise(ArgumentError, "No host provided") if host.nil? || host.strip == ""
ssh_cmd = "ssh #{user}@#{host} -p #{port} -o ConnectionAttempts=3 -o BatchMode=yes"
puts "Ensuring #{destination} directory exists on #{destination}..."
system("#{ssh_cmd} 'test -d #{destination} || mkdir -p #{destination}'")
today = Time.now.strftime('%A').downcase
source_with_day = File.join(source, today)
destination_with_day = File.join(destination, today)
puts "Deleting #{destination_with_day} if exists on #{host['name']}..."
system("#{ssh_cmd} 'test -d #{destination_with_day} && /bin/rm -rf #{destination_with_day}'")
puts "Copying #{source_with_day} to #{user}@#{host}:#{destination_with_day}..."
Find.find(source_with_day) do |local_path|
if File.directory?(local_path)
puts "\n#{File.basename(local_path)}:" unless File.basename(local_path) == today
remote_dir = File.join(destination_with_day, local_path.sub(source_with_day,''))
system("#{ssh_cmd} 'mkdir -p #{remote_dir}'")
else
puts " -> #{File.basename(local_path)}"
remote_path = File.join(destination_with_day, local_path.sub(source_with_day,''))
system("scp -q -P #{port} -o ConnectionAttempts=3 -o BatchMode=yes \"#{local_path}\" #{user}@#{host}:\"#{shellescape(remote_path)}\"")
end
end
puts "\nCleaning up permissions in destination directory..."
system("#{ssh_cmd} 'find #{destination_with_day} -type d -exec chmod 700 \\{} \\;'")
system("#{ssh_cmd} 'find #{destination_with_day} -type f -exec chmod 600 \\{} \\;'")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment