backup 3.0.19 → 3.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +9 -8
- data/Gemfile.lock +19 -1
- data/Guardfile +13 -9
- data/README.md +93 -31
- data/backup.gemspec +3 -3
- data/bin/backup +6 -283
- data/lib/backup.rb +101 -72
- data/lib/backup/archive.rb +21 -9
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/cleaner.rb +36 -0
- data/lib/backup/cli/helpers.rb +103 -0
- data/lib/backup/cli/utility.rb +308 -0
- data/lib/backup/compressor/base.rb +2 -2
- data/lib/backup/compressor/pbzip2.rb +76 -0
- data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
- data/lib/backup/configuration/database/riak.rb +25 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +6 -0
- data/lib/backup/configuration/helpers.rb +5 -18
- data/lib/backup/configuration/notifier/base.rb +13 -0
- data/lib/backup/configuration/notifier/hipchat.rb +41 -0
- data/lib/backup/configuration/notifier/mail.rb +38 -0
- data/lib/backup/configuration/notifier/prowl.rb +23 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +4 -0
- data/lib/backup/configuration/storage/dropbox.rb +8 -4
- data/lib/backup/database/base.rb +10 -2
- data/lib/backup/database/mongodb.rb +16 -19
- data/lib/backup/database/mysql.rb +2 -2
- data/lib/backup/database/postgresql.rb +2 -2
- data/lib/backup/database/redis.rb +15 -7
- data/lib/backup/database/riak.rb +45 -0
- data/lib/backup/dependency.rb +21 -7
- data/lib/backup/encryptor/base.rb +1 -1
- data/lib/backup/encryptor/open_ssl.rb +20 -5
- data/lib/backup/errors.rb +124 -0
- data/lib/backup/finder.rb +11 -3
- data/lib/backup/logger.rb +121 -82
- data/lib/backup/model.rb +103 -44
- data/lib/backup/notifier/base.rb +50 -0
- data/lib/backup/notifier/campfire.rb +32 -52
- data/lib/backup/notifier/hipchat.rb +99 -0
- data/lib/backup/notifier/mail.rb +100 -61
- data/lib/backup/notifier/presently.rb +31 -40
- data/lib/backup/notifier/prowl.rb +73 -0
- data/lib/backup/notifier/twitter.rb +29 -39
- data/lib/backup/packager.rb +25 -0
- data/lib/backup/splitter.rb +62 -0
- data/lib/backup/storage/base.rb +178 -18
- data/lib/backup/storage/cloudfiles.rb +34 -28
- data/lib/backup/storage/dropbox.rb +64 -67
- data/lib/backup/storage/ftp.rb +48 -40
- data/lib/backup/storage/local.rb +33 -28
- data/lib/backup/storage/ninefold.rb +40 -26
- data/lib/backup/storage/object.rb +8 -6
- data/lib/backup/storage/rsync.rb +61 -51
- data/lib/backup/storage/s3.rb +29 -27
- data/lib/backup/storage/scp.rb +56 -36
- data/lib/backup/storage/sftp.rb +49 -33
- data/lib/backup/syncer/base.rb +1 -1
- data/lib/backup/syncer/rsync.rb +1 -1
- data/lib/backup/template.rb +46 -0
- data/lib/backup/version.rb +1 -1
- data/spec/archive_spec.rb +34 -9
- data/spec/backup_spec.rb +1 -1
- data/spec/cli/helpers_spec.rb +35 -0
- data/spec/cli/utility_spec.rb +38 -0
- data/spec/compressor/bzip2_spec.rb +1 -1
- data/spec/compressor/gzip_spec.rb +1 -1
- data/spec/compressor/lzma_spec.rb +1 -1
- data/spec/compressor/pbzip2_spec.rb +63 -0
- data/spec/configuration/base_spec.rb +1 -1
- data/spec/configuration/compressor/bzip2_spec.rb +1 -1
- data/spec/configuration/compressor/gzip_spec.rb +1 -1
- data/spec/configuration/compressor/lzma_spec.rb +1 -1
- data/spec/configuration/database/base_spec.rb +1 -1
- data/spec/configuration/database/mongodb_spec.rb +1 -1
- data/spec/configuration/database/mysql_spec.rb +1 -1
- data/spec/configuration/database/postgresql_spec.rb +1 -1
- data/spec/configuration/database/redis_spec.rb +1 -1
- data/spec/configuration/database/riak_spec.rb +31 -0
- data/spec/configuration/encryptor/gpg_spec.rb +1 -1
- data/spec/configuration/encryptor/open_ssl_spec.rb +4 -1
- data/spec/configuration/notifier/campfire_spec.rb +1 -1
- data/spec/configuration/notifier/hipchat_spec.rb +43 -0
- data/spec/configuration/notifier/mail_spec.rb +34 -22
- data/spec/configuration/notifier/presently_spec.rb +1 -1
- data/spec/configuration/notifier/prowl_spec.rb +28 -0
- data/spec/configuration/notifier/twitter_spec.rb +1 -1
- data/spec/configuration/storage/cloudfiles_spec.rb +19 -16
- data/spec/configuration/storage/dropbox_spec.rb +1 -1
- data/spec/configuration/storage/ftp_spec.rb +1 -1
- data/spec/configuration/storage/local_spec.rb +1 -1
- data/spec/configuration/storage/ninefold_spec.rb +1 -1
- data/spec/configuration/storage/rsync_spec.rb +1 -1
- data/spec/configuration/storage/s3_spec.rb +1 -1
- data/spec/configuration/storage/scp_spec.rb +1 -1
- data/spec/configuration/storage/sftp_spec.rb +1 -1
- data/spec/configuration/syncer/rsync_spec.rb +1 -1
- data/spec/configuration/syncer/s3_spec.rb +1 -1
- data/spec/database/base_spec.rb +10 -1
- data/spec/database/mongodb_spec.rb +34 -7
- data/spec/database/mysql_spec.rb +8 -7
- data/spec/database/postgresql_spec.rb +8 -7
- data/spec/database/redis_spec.rb +39 -9
- data/spec/database/riak_spec.rb +50 -0
- data/spec/encryptor/gpg_spec.rb +1 -1
- data/spec/encryptor/open_ssl_spec.rb +77 -20
- data/spec/errors_spec.rb +306 -0
- data/spec/finder_spec.rb +91 -0
- data/spec/logger_spec.rb +254 -33
- data/spec/model_spec.rb +120 -15
- data/spec/notifier/campfire_spec.rb +127 -52
- data/spec/notifier/hipchat_spec.rb +193 -0
- data/spec/notifier/mail_spec.rb +290 -74
- data/spec/notifier/presently_spec.rb +290 -73
- data/spec/notifier/prowl_spec.rb +149 -0
- data/spec/notifier/twitter_spec.rb +106 -41
- data/spec/spec_helper.rb +8 -2
- data/spec/splitter_spec.rb +71 -0
- data/spec/storage/base_spec.rb +280 -19
- data/spec/storage/cloudfiles_spec.rb +38 -22
- data/spec/storage/dropbox_spec.rb +17 -13
- data/spec/storage/ftp_spec.rb +145 -55
- data/spec/storage/local_spec.rb +6 -6
- data/spec/storage/ninefold_spec.rb +70 -29
- data/spec/storage/object_spec.rb +44 -44
- data/spec/storage/rsync_spec.rb +186 -63
- data/spec/storage/s3_spec.rb +23 -24
- data/spec/storage/scp_spec.rb +116 -41
- data/spec/storage/sftp_spec.rb +124 -46
- data/spec/syncer/rsync_spec.rb +3 -3
- data/spec/syncer/s3_spec.rb +1 -1
- data/spec/version_spec.rb +1 -1
- data/templates/cli/utility/archive +13 -0
- data/{lib/templates → templates/cli/utility}/compressor/bzip2 +1 -1
- data/{lib/templates → templates/cli/utility}/compressor/gzip +1 -1
- data/{lib/templates → templates/cli/utility}/compressor/lzma +0 -0
- data/templates/cli/utility/compressor/pbzip2 +7 -0
- data/templates/cli/utility/config +31 -0
- data/{lib/templates → templates/cli/utility}/database/mongodb +1 -1
- data/{lib/templates → templates/cli/utility}/database/mysql +1 -1
- data/{lib/templates → templates/cli/utility}/database/postgresql +1 -1
- data/{lib/templates → templates/cli/utility}/database/redis +1 -1
- data/templates/cli/utility/database/riak +8 -0
- data/{lib/templates → templates/cli/utility}/encryptor/gpg +1 -1
- data/templates/cli/utility/encryptor/openssl +9 -0
- data/templates/cli/utility/model.erb +23 -0
- data/{lib/templates → templates/cli/utility}/notifier/campfire +2 -1
- data/templates/cli/utility/notifier/hipchat +15 -0
- data/{lib/templates → templates/cli/utility}/notifier/mail +6 -1
- data/{lib/templates → templates/cli/utility}/notifier/presently +1 -0
- data/templates/cli/utility/notifier/prowl +11 -0
- data/{lib/templates → templates/cli/utility}/notifier/twitter +2 -1
- data/templates/cli/utility/splitter +7 -0
- data/templates/cli/utility/storage/cloudfiles +12 -0
- data/{lib/templates → templates/cli/utility}/storage/dropbox +1 -1
- data/{lib/templates → templates/cli/utility}/storage/ftp +0 -0
- data/templates/cli/utility/storage/local +7 -0
- data/{lib/templates → templates/cli/utility}/storage/ninefold +1 -1
- data/templates/cli/utility/storage/rsync +11 -0
- data/{lib/templates → templates/cli/utility}/storage/s3 +0 -2
- data/templates/cli/utility/storage/scp +11 -0
- data/templates/cli/utility/storage/sftp +11 -0
- data/{lib/templates → templates/cli/utility}/syncer/rsync +1 -1
- data/{lib/templates → templates/cli/utility}/syncer/s3 +1 -1
- data/templates/general/links +11 -0
- data/templates/general/version.erb +2 -0
- data/templates/notifier/mail/failure.erb +9 -0
- data/templates/notifier/mail/success.erb +7 -0
- data/templates/notifier/mail/warning.erb +9 -0
- data/templates/storage/dropbox/authorization_url.erb +6 -0
- data/templates/storage/dropbox/authorized.erb +4 -0
- data/templates/storage/dropbox/cache_file_written.erb +10 -0
- metadata +81 -45
- data/lib/backup/cli.rb +0 -110
- data/lib/backup/exception/command_failed.rb +0 -8
- data/lib/backup/exception/command_not_found.rb +0 -8
- data/lib/backup/notifier/binder.rb +0 -32
- data/lib/backup/notifier/templates/notify_failure.erb +0 -33
- data/lib/backup/notifier/templates/notify_success.erb +0 -16
- data/lib/templates/archive +0 -7
- data/lib/templates/encryptor/openssl +0 -8
- data/lib/templates/readme +0 -15
- data/lib/templates/storage/cloudfiles +0 -11
- data/lib/templates/storage/local +0 -7
- data/lib/templates/storage/rsync +0 -11
- data/lib/templates/storage/scp +0 -11
- data/lib/templates/storage/sftp +0 -11
data/lib/backup/storage/ftp.rb
CHANGED
|
@@ -24,44 +24,42 @@ module Backup
|
|
|
24
24
|
# use passive mode?
|
|
25
25
|
attr_accessor :passive_mode
|
|
26
26
|
|
|
27
|
-
##
|
|
28
|
-
# Creates a new instance of the FTP storage object
|
|
29
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
30
|
-
# the configuration block which may overwrite these defaults
|
|
31
|
-
def initialize(&block)
|
|
32
|
-
load_defaults!
|
|
33
|
-
|
|
34
|
-
@port ||= 21
|
|
35
|
-
@path ||= 'backups'
|
|
36
|
-
@passive_mode ||= false
|
|
37
|
-
|
|
38
|
-
instance_eval(&block) if block_given?
|
|
39
|
-
|
|
40
|
-
@time = TIME
|
|
41
|
-
@path = path.sub(/^\~\//, '')
|
|
42
|
-
end
|
|
43
|
-
|
|
44
27
|
##
|
|
45
28
|
# This is the remote path to where the backup files will be stored
|
|
46
29
|
def remote_path
|
|
47
|
-
File.join(path, TRIGGER)
|
|
30
|
+
File.join(path, TRIGGER, @time)
|
|
48
31
|
end
|
|
49
32
|
|
|
50
33
|
##
|
|
51
34
|
# Performs the backup transfer
|
|
52
35
|
def perform!
|
|
36
|
+
super
|
|
53
37
|
transfer!
|
|
54
38
|
cycle!
|
|
55
39
|
end
|
|
56
40
|
|
|
57
41
|
private
|
|
58
42
|
|
|
43
|
+
##
|
|
44
|
+
# Set configuration defaults before evaluating configuration block,
|
|
45
|
+
# after setting defaults from Storage::Base
|
|
46
|
+
def pre_configure
|
|
47
|
+
super
|
|
48
|
+
@port ||= 21
|
|
49
|
+
@path ||= 'backups'
|
|
50
|
+
@passive_mode ||= false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Adjust configuration after evaluating configuration block,
|
|
55
|
+
# after adjustments from Storage::Base
|
|
56
|
+
def post_configure
|
|
57
|
+
super
|
|
58
|
+
@path = path.sub(/^\~\//, '')
|
|
59
|
+
end
|
|
60
|
+
|
|
59
61
|
##
|
|
60
62
|
# Establishes a connection to the remote server and returns the Net::FTP object.
|
|
61
|
-
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
62
|
-
# format to a file and will issues. This, however has no impact on performance since it only
|
|
63
|
-
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
64
|
-
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
65
63
|
#
|
|
66
64
|
# Note *
|
|
67
65
|
# Since the FTP port is defined as a constant in the Net::FTP class, and might be required
|
|
@@ -71,31 +69,41 @@ module Backup
|
|
|
71
69
|
Net::FTP.send(:remove_const, :FTP_PORT)
|
|
72
70
|
end; Net::FTP.send(:const_set, :FTP_PORT, port)
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
Net::FTP.open(ip, username, password) do |ftp|
|
|
73
|
+
ftp.passive = true if passive_mode
|
|
74
|
+
yield ftp
|
|
75
|
+
end
|
|
77
76
|
end
|
|
78
77
|
|
|
79
78
|
##
|
|
80
79
|
# Transfers the archived file to the specified remote server
|
|
81
80
|
def transfer!
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
connection do |ftp|
|
|
82
|
+
create_remote_directories(ftp)
|
|
83
|
+
|
|
84
|
+
files_to_transfer do |local_file, remote_file|
|
|
85
|
+
Logger.message "#{storage_name} started transferring " +
|
|
86
|
+
"'#{ local_file }' to '#{ ip }'."
|
|
87
|
+
ftp.put(
|
|
88
|
+
File.join(local_path, local_file),
|
|
89
|
+
File.join(remote_path, remote_file)
|
|
90
|
+
)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
88
93
|
end
|
|
89
94
|
|
|
90
95
|
##
|
|
91
96
|
# Removes the transferred archive file from the server
|
|
92
97
|
def remove!
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
connection do |ftp|
|
|
99
|
+
transferred_files do |local_file, remote_file|
|
|
100
|
+
Logger.message "#{storage_name} started removing " +
|
|
101
|
+
"'#{ local_file }' from '#{ ip }'."
|
|
102
|
+
|
|
103
|
+
ftp.delete(File.join(remote_path, remote_file))
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
ftp.rmdir(remote_path)
|
|
99
107
|
end
|
|
100
108
|
end
|
|
101
109
|
|
|
@@ -105,13 +113,13 @@ module Backup
|
|
|
105
113
|
# paths to directories that don't yet exist when creating new directories.
|
|
106
114
|
# Instead, we split the parts up in to an array (for each '/') and loop through
|
|
107
115
|
# that to create the directories one by one. Net::FTP raises an exception when
|
|
108
|
-
# the directory it's trying
|
|
109
|
-
def create_remote_directories
|
|
116
|
+
# the directory it's trying to create already exists, so we have rescue it
|
|
117
|
+
def create_remote_directories(ftp)
|
|
110
118
|
path_parts = Array.new
|
|
111
119
|
remote_path.split('/').each do |path_part|
|
|
112
120
|
path_parts << path_part
|
|
113
121
|
begin
|
|
114
|
-
|
|
122
|
+
ftp.mkdir(path_parts.join('/'))
|
|
115
123
|
rescue Net::FTPPermError; end
|
|
116
124
|
end
|
|
117
125
|
end
|
data/lib/backup/storage/local.rb
CHANGED
|
@@ -12,53 +12,64 @@ module Backup
|
|
|
12
12
|
# Path to store backups to
|
|
13
13
|
attr_accessor :path
|
|
14
14
|
|
|
15
|
-
##
|
|
16
|
-
# Creates a new instance of the Local storage object
|
|
17
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
18
|
-
# the configuration block which may overwrite these defaults
|
|
19
|
-
def initialize(&block)
|
|
20
|
-
load_defaults!
|
|
21
|
-
|
|
22
|
-
@path ||= "#{ENV['HOME']}/backups"
|
|
23
|
-
|
|
24
|
-
instance_eval(&block) if block_given?
|
|
25
|
-
|
|
26
|
-
@time = TIME
|
|
27
|
-
fix_path!
|
|
28
|
-
end
|
|
29
|
-
|
|
30
15
|
##
|
|
31
16
|
# This is the remote path to where the backup files will be stored.
|
|
32
17
|
# Eventhough it says "remote", it's actually the "local" path, but
|
|
33
18
|
# the naming is necessary for compatibility reasons
|
|
34
19
|
def remote_path
|
|
35
|
-
File.join(path, TRIGGER)
|
|
20
|
+
File.join(path, TRIGGER, @time)
|
|
36
21
|
end
|
|
37
22
|
|
|
38
23
|
##
|
|
39
24
|
# Performs the backup transfer
|
|
40
25
|
def perform!
|
|
26
|
+
super
|
|
41
27
|
transfer!
|
|
42
28
|
cycle!
|
|
43
29
|
end
|
|
44
30
|
|
|
45
31
|
private
|
|
46
32
|
|
|
33
|
+
##
|
|
34
|
+
# Set configuration defaults before evaluating configuration block,
|
|
35
|
+
# after setting defaults from Storage::Base
|
|
36
|
+
def pre_configure
|
|
37
|
+
super
|
|
38
|
+
@path ||= "#{ENV['HOME']}/backups"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
##
|
|
42
|
+
# Adjust configuration after evaluating configuration block,
|
|
43
|
+
# after adjustments from Storage::Base
|
|
44
|
+
def post_configure
|
|
45
|
+
super
|
|
46
|
+
@path = File.expand_path(path)
|
|
47
|
+
end
|
|
48
|
+
|
|
47
49
|
##
|
|
48
50
|
# Transfers the archived file to the specified local path
|
|
49
51
|
def transfer!
|
|
50
|
-
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
51
52
|
create_local_directories!
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
|
|
54
|
+
files_to_transfer do |local_file, remote_file|
|
|
55
|
+
Logger.message "#{storage_name} started transferring '#{ local_file }'."
|
|
56
|
+
FileUtils.cp(
|
|
57
|
+
File.join(local_path, local_file),
|
|
58
|
+
File.join(remote_path, remote_file)
|
|
59
|
+
)
|
|
60
|
+
end
|
|
56
61
|
end
|
|
57
62
|
|
|
58
63
|
##
|
|
59
64
|
# Removes the transferred archive file from the local path
|
|
60
65
|
def remove!
|
|
61
|
-
|
|
66
|
+
messages = []
|
|
67
|
+
transferred_files do |local_file, remote_file|
|
|
68
|
+
messages << "#{storage_name} started removing '#{ local_file }'."
|
|
69
|
+
end
|
|
70
|
+
Logger.message messages.join("\n")
|
|
71
|
+
|
|
72
|
+
FileUtils.rm_r(remote_path)
|
|
62
73
|
end
|
|
63
74
|
|
|
64
75
|
##
|
|
@@ -67,12 +78,6 @@ module Backup
|
|
|
67
78
|
FileUtils.mkdir_p(remote_path)
|
|
68
79
|
end
|
|
69
80
|
|
|
70
|
-
##
|
|
71
|
-
# Replaces ~/ with the full path to the users $HOME directory
|
|
72
|
-
def fix_path!
|
|
73
|
-
@path = path.sub(/^\~\//, "#{ENV['HOME']}/")
|
|
74
|
-
end
|
|
75
|
-
|
|
76
81
|
end
|
|
77
82
|
end
|
|
78
83
|
end
|
|
@@ -16,25 +16,10 @@ module Backup
|
|
|
16
16
|
# Ninefold directory path
|
|
17
17
|
attr_accessor :path
|
|
18
18
|
|
|
19
|
-
##
|
|
20
|
-
# Creates a new instance of the Ninefold storage object
|
|
21
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
22
|
-
# the configuration block which may overwrite these defaults
|
|
23
|
-
#
|
|
24
|
-
def initialize(&block)
|
|
25
|
-
load_defaults!
|
|
26
|
-
|
|
27
|
-
@path ||= 'backups'
|
|
28
|
-
|
|
29
|
-
instance_eval(&block) if block_given?
|
|
30
|
-
|
|
31
|
-
@time = TIME
|
|
32
|
-
end
|
|
33
|
-
|
|
34
19
|
##
|
|
35
20
|
# This is the remote path to where the backup files will be stored
|
|
36
21
|
def remote_path
|
|
37
|
-
File.join(path, TRIGGER).sub(/^\//, '')
|
|
22
|
+
File.join(path, TRIGGER, @time).sub(/^\//, '')
|
|
38
23
|
end
|
|
39
24
|
|
|
40
25
|
##
|
|
@@ -46,12 +31,28 @@ module Backup
|
|
|
46
31
|
##
|
|
47
32
|
# Performs the backup transfer
|
|
48
33
|
def perform!
|
|
34
|
+
super
|
|
49
35
|
transfer!
|
|
50
36
|
cycle!
|
|
51
37
|
end
|
|
52
38
|
|
|
53
39
|
private
|
|
54
40
|
|
|
41
|
+
##
|
|
42
|
+
# Set configuration defaults before evaluating configuration block,
|
|
43
|
+
# after setting defaults from Storage::Base
|
|
44
|
+
def pre_configure
|
|
45
|
+
super
|
|
46
|
+
@path ||= 'backups'
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# Adjust configuration after evaluating configuration block,
|
|
51
|
+
# after adjustments from Storage::Base
|
|
52
|
+
def post_configure
|
|
53
|
+
super
|
|
54
|
+
end
|
|
55
|
+
|
|
55
56
|
##
|
|
56
57
|
# Establishes a connection to Amazon S3 and returns the Fog object.
|
|
57
58
|
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
@@ -59,7 +60,7 @@ module Backup
|
|
|
59
60
|
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
60
61
|
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
61
62
|
def connection
|
|
62
|
-
Fog::Storage.new(
|
|
63
|
+
@connection ||= Fog::Storage.new(
|
|
63
64
|
:provider => provider,
|
|
64
65
|
:ninefold_storage_token => storage_token,
|
|
65
66
|
:ninefold_storage_secret => storage_secret
|
|
@@ -69,26 +70,39 @@ module Backup
|
|
|
69
70
|
##
|
|
70
71
|
# Transfers the archived file to the specified directory
|
|
71
72
|
def transfer!
|
|
72
|
-
|
|
73
|
-
Logger.message
|
|
74
|
-
directory = connection.directories.get
|
|
73
|
+
files_to_transfer do |local_file, remote_file|
|
|
74
|
+
Logger.message "#{storage_name} started transferring '#{ local_file }'."
|
|
75
|
+
directory = connection.directories.get(remote_path)
|
|
75
76
|
directory ||= connection.directories.create(:key => remote_path)
|
|
76
77
|
directory.files.create(
|
|
77
78
|
:key => remote_file,
|
|
78
79
|
:body => File.open(File.join(local_path, local_file))
|
|
79
80
|
)
|
|
80
|
-
rescue Excon::Errors::NotFound
|
|
81
|
-
raise "An error occurred while trying to transfer the file."
|
|
82
81
|
end
|
|
83
82
|
end
|
|
84
83
|
|
|
85
84
|
##
|
|
86
85
|
# Removes the transferred archive file from the Amazon S3 bucket
|
|
87
86
|
def remove!
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
if directory = connection.directories.get(remote_path)
|
|
88
|
+
transferred_files do |local_file, remote_file|
|
|
89
|
+
Logger.message "#{storage_name} started removing " +
|
|
90
|
+
"'#{ local_file }' from Ninefold.'"
|
|
91
|
+
|
|
92
|
+
if file = directory.files.get(remote_file)
|
|
93
|
+
file.destroy
|
|
94
|
+
else
|
|
95
|
+
# Note: Fog-0.11.0 will return nil if remote_file is not found
|
|
96
|
+
raise Errors::Storage::Ninefold::NotFoundError,
|
|
97
|
+
"'#{remote_file}' not found in '#{remote_path}'", caller(1)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
directory.destroy
|
|
101
|
+
else
|
|
102
|
+
# Note: Fog-0.11.0 will return nil if remote_path is not found
|
|
103
|
+
raise Errors::Storage::Ninefold::NotFoundError,
|
|
104
|
+
"Directory at '#{remote_path}' not found", caller(1)
|
|
105
|
+
end
|
|
92
106
|
end
|
|
93
107
|
|
|
94
108
|
end
|
|
@@ -11,8 +11,10 @@ module Backup
|
|
|
11
11
|
##
|
|
12
12
|
# Instantiates a new Backup::Storage::Object and stores the
|
|
13
13
|
# full path to the storage file (yaml) in the @storage_file attribute
|
|
14
|
-
def initialize(type)
|
|
15
|
-
|
|
14
|
+
def initialize(type, storage_id)
|
|
15
|
+
suffix = storage_id.to_s.strip.gsub(/[\W\s]/, '_')
|
|
16
|
+
filename = suffix.empty? ? type : "#{type}-#{suffix}"
|
|
17
|
+
@storage_file = File.join(DATA_PATH, TRIGGER, "#{filename}.yml")
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
##
|
|
@@ -24,11 +26,11 @@ module Backup
|
|
|
24
26
|
# descending. The newest backup storage object comes in Backup::Storage::Object.load[0]
|
|
25
27
|
# and the oldest in Backup::Storage::Object.load[-1]
|
|
26
28
|
def load
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
[]
|
|
29
|
+
objects = []
|
|
30
|
+
if File.exist?(storage_file) and not File.zero?(storage_file)
|
|
31
|
+
objects = YAML.load_file(storage_file).sort { |a,b| b.time <=> a.time }
|
|
31
32
|
end
|
|
33
|
+
objects
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
##
|
data/lib/backup/storage/rsync.rb
CHANGED
|
@@ -11,7 +11,7 @@ Backup::Dependency.load('net-ssh')
|
|
|
11
11
|
module Backup
|
|
12
12
|
module Storage
|
|
13
13
|
class RSync < Base
|
|
14
|
-
include Backup::CLI
|
|
14
|
+
include Backup::CLI::Helpers
|
|
15
15
|
|
|
16
16
|
##
|
|
17
17
|
# Server credentials
|
|
@@ -29,24 +29,6 @@ module Backup
|
|
|
29
29
|
# Flag to use local backups
|
|
30
30
|
attr_accessor :local
|
|
31
31
|
|
|
32
|
-
##
|
|
33
|
-
# Creates a new instance of the RSync storage object
|
|
34
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
35
|
-
# the configuration block which may overwrite these defaults
|
|
36
|
-
def initialize(&block)
|
|
37
|
-
load_defaults!
|
|
38
|
-
|
|
39
|
-
@port ||= 22
|
|
40
|
-
@path ||= 'backups'
|
|
41
|
-
@local ||= false
|
|
42
|
-
|
|
43
|
-
instance_eval(&block) if block_given?
|
|
44
|
-
write_password_file!
|
|
45
|
-
|
|
46
|
-
@time = TIME
|
|
47
|
-
@path = path.sub(/^\~\//, '')
|
|
48
|
-
end
|
|
49
|
-
|
|
50
32
|
##
|
|
51
33
|
# This is the remote path to where the backup files will be stored
|
|
52
34
|
def remote_path
|
|
@@ -56,60 +38,67 @@ module Backup
|
|
|
56
38
|
##
|
|
57
39
|
# Performs the backup transfer
|
|
58
40
|
def perform!
|
|
41
|
+
super
|
|
42
|
+
write_password_file!
|
|
59
43
|
transfer!
|
|
44
|
+
ensure
|
|
60
45
|
remove_password_file!
|
|
61
46
|
end
|
|
62
47
|
|
|
63
|
-
|
|
64
|
-
# Returns Rsync syntax for defining a port to connect to
|
|
65
|
-
def port
|
|
66
|
-
"-e 'ssh -p #{@port}'"
|
|
67
|
-
end
|
|
48
|
+
private
|
|
68
49
|
|
|
69
50
|
##
|
|
70
|
-
#
|
|
71
|
-
|
|
72
|
-
|
|
51
|
+
# Set configuration defaults before evaluating configuration block,
|
|
52
|
+
# after setting defaults from Storage::Base
|
|
53
|
+
def pre_configure
|
|
54
|
+
super
|
|
55
|
+
@port ||= 22
|
|
56
|
+
@path ||= 'backups'
|
|
57
|
+
@local ||= false
|
|
73
58
|
end
|
|
74
59
|
|
|
75
60
|
##
|
|
76
|
-
#
|
|
77
|
-
#
|
|
78
|
-
def
|
|
79
|
-
|
|
61
|
+
# Adjust configuration after evaluating configuration block,
|
|
62
|
+
# after adjustments from Storage::Base
|
|
63
|
+
def post_configure
|
|
64
|
+
super
|
|
65
|
+
@path = path.sub(/^\~\//, '')
|
|
80
66
|
end
|
|
81
67
|
|
|
82
|
-
private
|
|
83
|
-
|
|
84
68
|
##
|
|
85
69
|
# Establishes a connection to the remote server and returns the Net::SSH object.
|
|
86
|
-
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
87
|
-
# format to a file and will issues. This, however has no impact on performance since it only
|
|
88
|
-
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
89
|
-
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
90
70
|
def connection
|
|
91
|
-
Net::SSH.start(ip, username, :password =>
|
|
71
|
+
Net::SSH.start(ip, username, :password => password, :port => port) do |ssh|
|
|
72
|
+
yield ssh
|
|
73
|
+
end
|
|
92
74
|
end
|
|
93
75
|
|
|
94
76
|
##
|
|
95
77
|
# Transfers the archived file to the specified remote server
|
|
96
78
|
def transfer!
|
|
97
|
-
Logger.message("#{ self.class } started transferring \"#{ remote_file }\".")
|
|
98
79
|
create_remote_directories!
|
|
99
|
-
|
|
100
|
-
|
|
80
|
+
|
|
81
|
+
Logger.message "#{storage_name} started transferring " +
|
|
82
|
+
"'#{ filename }' to '#{ ip }'."
|
|
83
|
+
|
|
84
|
+
if local
|
|
85
|
+
run(
|
|
86
|
+
"#{ utility(:rsync) } '#{ File.join(local_path, filename) }' " +
|
|
87
|
+
"'#{ File.join(remote_path, filename[20..-1]) }'"
|
|
88
|
+
)
|
|
101
89
|
else
|
|
102
|
-
run(
|
|
90
|
+
run(
|
|
91
|
+
"#{ utility(:rsync) } #{ rsync_options } #{ rsync_port } " +
|
|
92
|
+
"#{ rsync_password_file } '#{ File.join(local_path, filename) }' " +
|
|
93
|
+
"'#{ username }@#{ ip }:#{ File.join(remote_path, filename[20..-1]) }'"
|
|
94
|
+
)
|
|
103
95
|
end
|
|
104
96
|
end
|
|
105
97
|
|
|
106
98
|
##
|
|
107
|
-
#
|
|
99
|
+
# Note: RSync::Storage doesn't cycle
|
|
108
100
|
def remove!
|
|
109
|
-
|
|
110
|
-
if response =~ /No such file or directory/
|
|
111
|
-
Logger.warn "Could not remove file \"#{ File.join(remote_path, remote_file) }\"."
|
|
112
|
-
end
|
|
101
|
+
nil
|
|
113
102
|
end
|
|
114
103
|
|
|
115
104
|
##
|
|
@@ -119,7 +108,9 @@ module Backup
|
|
|
119
108
|
if @local
|
|
120
109
|
mkdir(remote_path)
|
|
121
110
|
else
|
|
122
|
-
connection
|
|
111
|
+
connection do |ssh|
|
|
112
|
+
ssh.exec!("mkdir -p '#{ remote_path }'")
|
|
113
|
+
end
|
|
123
114
|
end
|
|
124
115
|
end
|
|
125
116
|
|
|
@@ -127,9 +118,9 @@ module Backup
|
|
|
127
118
|
# Writes the provided password to a temporary file so that
|
|
128
119
|
# the rsync utility can read the password from this file
|
|
129
120
|
def write_password_file!
|
|
130
|
-
unless
|
|
121
|
+
unless password.nil?
|
|
131
122
|
@password_file = Tempfile.new('backup-rsync-password')
|
|
132
|
-
@password_file.write(
|
|
123
|
+
@password_file.write(password)
|
|
133
124
|
@password_file.close
|
|
134
125
|
end
|
|
135
126
|
end
|
|
@@ -138,7 +129,26 @@ module Backup
|
|
|
138
129
|
# Removes the previously created @password_file
|
|
139
130
|
# (temporary file containing the password)
|
|
140
131
|
def remove_password_file!
|
|
141
|
-
@password_file.
|
|
132
|
+
@password_file.delete if @password_file
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
##
|
|
136
|
+
# Returns Rsync syntax for using a password file
|
|
137
|
+
def rsync_password_file
|
|
138
|
+
"--password-file='#{@password_file.path}'" if @password_file
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
##
|
|
142
|
+
# Returns Rsync syntax for defining a port to connect to
|
|
143
|
+
def rsync_port
|
|
144
|
+
"-e 'ssh -p #{port}'"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
##
|
|
148
|
+
# RSync options
|
|
149
|
+
# -z = Compresses the bytes that will be transferred to reduce bandwidth usage
|
|
150
|
+
def rsync_options
|
|
151
|
+
"-z"
|
|
142
152
|
end
|
|
143
153
|
|
|
144
154
|
end
|