# encoding: utf-8 ## # Only load the Net::SSH and Net::SCP library/gems # when the Backup::Storage::SCP class is loaded Backup::Dependency.load('net-ssh') Backup::Dependency.load('net-scp') module Backup module Storage class SCP < Base ## # Server credentials attr_accessor :username, :password ## # Server IP Address and SCP port attr_accessor :ip, :port ## # Path to store backups to attr_accessor :path ## # Creates a new instance of the storage object def initialize(model, storage_id = nil, &block) super(model, storage_id) @port ||= 22 @path ||= 'backups' instance_eval(&block) if block_given? @path = path.sub(/^\~\//, '') end private ## # Establishes a connection to the remote server # and yields the Net::SSH connection. # Net::SCP will use this connection to transfer backups def connection Net::SSH.start( ip, username, :password => password, :port => port ) {|ssh| yield ssh } end ## # Transfers the archived file to the specified remote server def transfer! remote_path = remote_path_for(@package) connection do |ssh| ssh.exec!("mkdir -p '#{ remote_path }'") files_to_transfer_for(@package) do |local_file, remote_file| Logger.message "#{storage_name} started transferring " + "'#{local_file}' to '#{ip}'." ssh.scp.upload!( File.join(local_path, local_file), File.join(remote_path, remote_file) ) end end end ## # Removes the transferred archive file(s) from the storage location. # Any error raised will be rescued during Cycling # and a warning will be logged, containing the error message. def remove!(package) remote_path = remote_path_for(package) messages = [] transferred_files_for(package) do |local_file, remote_file| messages << "#{storage_name} started removing " + "'#{local_file}' from '#{ip}'." end Logger.message messages.join("\n") errors = [] connection do |ssh| ssh.exec!("rm -r '#{remote_path}'") do |ch, stream, data| errors << data if stream == :stderr end end unless errors.empty? raise Errors::Storage::SCP::SSHError, "Net::SSH reported the following errors:\n" + errors.join("\n") end end end end end