/
sftp.rb
106 lines (89 loc) · 3.13 KB
/
sftp.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# encoding: utf-8
##
# Only load the Net::SFTP library/gem when the Backup::Storage::SFTP class is loaded
Backup::Dependency.load('net-sftp')
module Backup
module Storage
class SFTP < Base
##
# Server credentials
attr_accessor :username, :password
##
# Server IP Address and SFTP port
attr_accessor :ip, :port
##
# Path to store backups to
attr_accessor :path
##
# Creates a new instance of the SFTP storage object
# First it sets the defaults (if any exist) and then evaluates
# the configuration block which may overwrite these defaults
def initialize(&block)
load_defaults!
@port ||= 22
@path ||= 'backups'
instance_eval(&block) if block_given?
@time = TIME
@path = path.sub(/^\~\//, '')
end
##
# This is the remote path to where the backup files will be stored
def remote_path
File.join(path, TRIGGER)
end
##
# Performs the backup transfer
def perform!
transfer!
cycle!
end
private
##
# Establishes a connection to the remote server and returns the Net::SFTP object.
# Not doing any instance variable caching because this object gets persisted in YAML
# format to a file and will issues. This, however has no impact on performance since it only
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
# background anyway so even if it were a bit slower it shouldn't matter.
def connection
Net::SFTP.start(ip, username, :password => password, :port => port)
end
##
# Transfers the archived file to the specified remote server
def transfer!
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
create_remote_directories!
connection.upload!(
File.join(local_path, local_file),
File.join(remote_path, remote_file)
)
end
##
# Removes the transferred archive file from the server
def remove!
begin
connection.remove!(
File.join(remote_path, remote_file)
)
rescue Net::SFTP::StatusException
Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
end
end
##
# Creates (if they don't exist yet) all the directories on the remote
# server in order to upload the backup file. Net::SFTP does not support
# paths to directories that don't yet exist when creating new directories.
# Instead, we split the parts up in to an array (for each '/') and loop through
# that to create the directories one by one. Net::SFTP raises an exception when
# the directory it's trying ot create already exists, so we have rescue it
def create_remote_directories!
path_parts = Array.new
remote_path.split('/').each do |path_part|
path_parts << path_part
begin
connection.mkdir!(path_parts.join('/'))
rescue Net::SFTP::StatusException; end
end
end
end
end
end