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/s3.rb
CHANGED
|
@@ -20,27 +20,10 @@ module Backup
|
|
|
20
20
|
# Region of the specified S3 bucket
|
|
21
21
|
attr_accessor :region
|
|
22
22
|
|
|
23
|
-
##
|
|
24
|
-
# Creates a new instance of the Amazon S3 storage object
|
|
25
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
26
|
-
# the configuration block which may overwrite these defaults
|
|
27
|
-
#
|
|
28
|
-
# Currently available regions:
|
|
29
|
-
# eu-west-1, us-east-1, ap-southeast-1, us-west-1
|
|
30
|
-
def initialize(&block)
|
|
31
|
-
load_defaults!
|
|
32
|
-
|
|
33
|
-
@path ||= 'backups'
|
|
34
|
-
|
|
35
|
-
instance_eval(&block) if block_given?
|
|
36
|
-
|
|
37
|
-
@time = TIME
|
|
38
|
-
end
|
|
39
|
-
|
|
40
23
|
##
|
|
41
24
|
# This is the remote path to where the backup files will be stored
|
|
42
25
|
def remote_path
|
|
43
|
-
File.join(path, TRIGGER).sub(/^\//, '')
|
|
26
|
+
File.join(path, TRIGGER, @time).sub(/^\//, '')
|
|
44
27
|
end
|
|
45
28
|
|
|
46
29
|
##
|
|
@@ -52,12 +35,28 @@ module Backup
|
|
|
52
35
|
##
|
|
53
36
|
# Performs the backup transfer
|
|
54
37
|
def perform!
|
|
38
|
+
super
|
|
55
39
|
transfer!
|
|
56
40
|
cycle!
|
|
57
41
|
end
|
|
58
42
|
|
|
59
43
|
private
|
|
60
44
|
|
|
45
|
+
##
|
|
46
|
+
# Set configuration defaults before evaluating configuration block,
|
|
47
|
+
# after setting defaults from Storage::Base
|
|
48
|
+
def pre_configure
|
|
49
|
+
super
|
|
50
|
+
@path ||= 'backups'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Adjust configuration after evaluating configuration block,
|
|
55
|
+
# after adjustments from Storage::Base
|
|
56
|
+
def post_configure
|
|
57
|
+
super
|
|
58
|
+
end
|
|
59
|
+
|
|
61
60
|
##
|
|
62
61
|
# Establishes a connection to Amazon S3 and returns the Fog object.
|
|
63
62
|
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
@@ -65,7 +64,7 @@ module Backup
|
|
|
65
64
|
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
66
65
|
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
67
66
|
def connection
|
|
68
|
-
Fog::Storage.new(
|
|
67
|
+
@connection ||= Fog::Storage.new(
|
|
69
68
|
:provider => provider,
|
|
70
69
|
:aws_access_key_id => access_key_id,
|
|
71
70
|
:aws_secret_access_key => secret_access_key,
|
|
@@ -76,26 +75,29 @@ module Backup
|
|
|
76
75
|
##
|
|
77
76
|
# Transfers the archived file to the specified Amazon S3 bucket
|
|
78
77
|
def transfer!
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
connection.sync_clock
|
|
79
|
+
files_to_transfer do |local_file, remote_file|
|
|
80
|
+
Logger.message "#{storage_name} started transferring " +
|
|
81
|
+
"'#{ local_file }' to bucket '#{ bucket }'"
|
|
82
|
+
|
|
82
83
|
connection.put_object(
|
|
83
84
|
bucket,
|
|
84
85
|
File.join(remote_path, remote_file),
|
|
85
86
|
File.open(File.join(local_path, local_file))
|
|
86
87
|
)
|
|
87
|
-
rescue Excon::Errors::NotFound
|
|
88
|
-
raise "An error occurred while trying to transfer the backup, please make sure the bucket exists."
|
|
89
88
|
end
|
|
90
89
|
end
|
|
91
90
|
|
|
92
91
|
##
|
|
93
92
|
# Removes the transferred archive file from the Amazon S3 bucket
|
|
94
93
|
def remove!
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
connection.sync_clock
|
|
95
|
+
transferred_files do |local_file, remote_file|
|
|
96
|
+
Logger.message "#{storage_name} started removing " +
|
|
97
|
+
"'#{ local_file }' from bucket '#{ bucket }'"
|
|
98
|
+
|
|
97
99
|
connection.delete_object(bucket, File.join(remote_path, remote_file))
|
|
98
|
-
|
|
100
|
+
end
|
|
99
101
|
end
|
|
100
102
|
|
|
101
103
|
end
|
data/lib/backup/storage/scp.rb
CHANGED
|
@@ -23,31 +23,16 @@ module Backup
|
|
|
23
23
|
# Path to store backups to
|
|
24
24
|
attr_accessor :path
|
|
25
25
|
|
|
26
|
-
##
|
|
27
|
-
# Creates a new instance of the SCP storage object
|
|
28
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
29
|
-
# the configuration block which may overwrite these defaults
|
|
30
|
-
def initialize(&block)
|
|
31
|
-
load_defaults!
|
|
32
|
-
|
|
33
|
-
@port ||= 22
|
|
34
|
-
@path ||= 'backups'
|
|
35
|
-
|
|
36
|
-
instance_eval(&block) if block_given?
|
|
37
|
-
|
|
38
|
-
@time = TIME
|
|
39
|
-
@path = path.sub(/^\~\//, '')
|
|
40
|
-
end
|
|
41
|
-
|
|
42
26
|
##
|
|
43
27
|
# This is the remote path to where the backup files will be stored
|
|
44
28
|
def remote_path
|
|
45
|
-
File.join(path, TRIGGER)
|
|
29
|
+
File.join(path, TRIGGER, @time)
|
|
46
30
|
end
|
|
47
31
|
|
|
48
32
|
##
|
|
49
33
|
# Performs the backup transfer
|
|
50
34
|
def perform!
|
|
35
|
+
super
|
|
51
36
|
transfer!
|
|
52
37
|
cycle!
|
|
53
38
|
end
|
|
@@ -55,34 +40,69 @@ module Backup
|
|
|
55
40
|
private
|
|
56
41
|
|
|
57
42
|
##
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
43
|
+
# Set configuration defaults before evaluating configuration block,
|
|
44
|
+
# after setting defaults from Storage::Base
|
|
45
|
+
def pre_configure
|
|
46
|
+
super
|
|
47
|
+
@port ||= 22
|
|
48
|
+
@path ||= 'backups'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Adjust configuration after evaluating configuration block,
|
|
53
|
+
# after adjustments from Storage::Base
|
|
54
|
+
def post_configure
|
|
55
|
+
super
|
|
56
|
+
@path = path.sub(/^\~\//, '')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# Establishes a connection to the remote server
|
|
61
|
+
# and yields the Net::SSH connection.
|
|
62
|
+
# Net::SCP will use this connection to transfer backups
|
|
65
63
|
def connection
|
|
66
|
-
Net::SSH.start(
|
|
64
|
+
Net::SSH.start(
|
|
65
|
+
ip, username, :password => password, :port => port
|
|
66
|
+
) {|ssh| yield ssh }
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
##
|
|
70
70
|
# Transfers the archived file to the specified remote server
|
|
71
71
|
def transfer!
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
connection do |ssh|
|
|
73
|
+
create_remote_directories(ssh)
|
|
74
|
+
|
|
75
|
+
files_to_transfer do |local_file, remote_file|
|
|
76
|
+
Logger.message "#{storage_name} started transferring " +
|
|
77
|
+
"'#{local_file}' to '#{ip}'."
|
|
78
|
+
|
|
79
|
+
ssh.scp.upload!(
|
|
80
|
+
File.join(local_path, local_file),
|
|
81
|
+
File.join(remote_path, remote_file)
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
78
85
|
end
|
|
79
86
|
|
|
80
87
|
##
|
|
81
88
|
# Removes the transferred archive file from the server
|
|
82
89
|
def remove!
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
messages = []
|
|
91
|
+
transferred_files do |local_file, remote_file|
|
|
92
|
+
messages << "#{storage_name} started removing '#{local_file}' from '#{ip}'."
|
|
93
|
+
end
|
|
94
|
+
Logger.message messages.join("\n")
|
|
95
|
+
|
|
96
|
+
errors = []
|
|
97
|
+
connection do |ssh|
|
|
98
|
+
ssh.exec!("rm -r '#{remote_path}'") do |ch, stream, data|
|
|
99
|
+
errors << data if stream == :stderr
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
unless errors.empty?
|
|
103
|
+
raise Errors::Storage::SCP::SSHError,
|
|
104
|
+
"Net::SSH reported the following errors:\n" +
|
|
105
|
+
errors.join("\n"), caller(1)
|
|
86
106
|
end
|
|
87
107
|
end
|
|
88
108
|
|
|
@@ -93,11 +113,11 @@ module Backup
|
|
|
93
113
|
# Instead, we split the parts up in to an array (for each '/') and loop through
|
|
94
114
|
# that to create the directories one by one. Net::SCP raises an exception when
|
|
95
115
|
# the directory it's trying ot create already exists, so we have rescue it
|
|
96
|
-
def create_remote_directories
|
|
116
|
+
def create_remote_directories(ssh)
|
|
97
117
|
path_parts = Array.new
|
|
98
118
|
remote_path.split('/').each do |path_part|
|
|
99
119
|
path_parts << path_part
|
|
100
|
-
|
|
120
|
+
ssh.exec!("mkdir '#{path_parts.join('/')}'")
|
|
101
121
|
end
|
|
102
122
|
end
|
|
103
123
|
|
data/lib/backup/storage/sftp.rb
CHANGED
|
@@ -20,37 +20,39 @@ module Backup
|
|
|
20
20
|
# Path to store backups to
|
|
21
21
|
attr_accessor :path
|
|
22
22
|
|
|
23
|
-
##
|
|
24
|
-
# Creates a new instance of the SFTP storage object
|
|
25
|
-
# First it sets the defaults (if any exist) and then evaluates
|
|
26
|
-
# the configuration block which may overwrite these defaults
|
|
27
|
-
def initialize(&block)
|
|
28
|
-
load_defaults!
|
|
29
|
-
|
|
30
|
-
@port ||= 22
|
|
31
|
-
@path ||= 'backups'
|
|
32
|
-
|
|
33
|
-
instance_eval(&block) if block_given?
|
|
34
|
-
|
|
35
|
-
@time = TIME
|
|
36
|
-
@path = path.sub(/^\~\//, '')
|
|
37
|
-
end
|
|
38
|
-
|
|
39
23
|
##
|
|
40
24
|
# This is the remote path to where the backup files will be stored
|
|
41
25
|
def remote_path
|
|
42
|
-
File.join(path, TRIGGER)
|
|
26
|
+
File.join(path, TRIGGER, @time)
|
|
43
27
|
end
|
|
44
28
|
|
|
45
29
|
##
|
|
46
30
|
# Performs the backup transfer
|
|
47
31
|
def perform!
|
|
32
|
+
super
|
|
48
33
|
transfer!
|
|
49
34
|
cycle!
|
|
50
35
|
end
|
|
51
36
|
|
|
52
37
|
private
|
|
53
38
|
|
|
39
|
+
##
|
|
40
|
+
# Set configuration defaults before evaluating configuration block,
|
|
41
|
+
# after setting defaults from Storage::Base
|
|
42
|
+
def pre_configure
|
|
43
|
+
super
|
|
44
|
+
@port ||= 22
|
|
45
|
+
@path ||= 'backups'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# Adjust configuration after evaluating configuration block,
|
|
50
|
+
# after adjustments from Storage::Base
|
|
51
|
+
def post_configure
|
|
52
|
+
super
|
|
53
|
+
@path = path.sub(/^\~\//, '')
|
|
54
|
+
end
|
|
55
|
+
|
|
54
56
|
##
|
|
55
57
|
# Establishes a connection to the remote server and returns the Net::SFTP object.
|
|
56
58
|
# Not doing any instance variable caching because this object gets persisted in YAML
|
|
@@ -58,29 +60,43 @@ module Backup
|
|
|
58
60
|
# gets invoked once per object for a #transfer! and once for a remove! Backups run in the
|
|
59
61
|
# background anyway so even if it were a bit slower it shouldn't matter.
|
|
60
62
|
def connection
|
|
61
|
-
Net::SFTP.start(
|
|
63
|
+
Net::SFTP.start(
|
|
64
|
+
ip, username,
|
|
65
|
+
:password => password,
|
|
66
|
+
:port => port
|
|
67
|
+
) {|sftp| yield sftp }
|
|
62
68
|
end
|
|
63
69
|
|
|
64
70
|
##
|
|
65
71
|
# Transfers the archived file to the specified remote server
|
|
66
72
|
def transfer!
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
connection do |sftp|
|
|
74
|
+
create_remote_directories(sftp)
|
|
75
|
+
|
|
76
|
+
files_to_transfer do |local_file, remote_file|
|
|
77
|
+
Logger.message "#{storage_name} started transferring " +
|
|
78
|
+
"'#{ local_file }' to '#{ ip }'."
|
|
79
|
+
|
|
80
|
+
sftp.upload!(
|
|
81
|
+
File.join(local_path, local_file),
|
|
82
|
+
File.join(remote_path, remote_file)
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
73
86
|
end
|
|
74
87
|
|
|
75
88
|
##
|
|
76
89
|
# Removes the transferred archive file from the server
|
|
77
90
|
def remove!
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
91
|
+
connection do |sftp|
|
|
92
|
+
transferred_files do |local_file, remote_file|
|
|
93
|
+
Logger.message "#{storage_name} started removing " +
|
|
94
|
+
"'#{ local_file }' from '#{ ip }'."
|
|
95
|
+
|
|
96
|
+
sftp.remove!(File.join(remote_path, remote_file))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
sftp.rmdir!(remote_path)
|
|
84
100
|
end
|
|
85
101
|
end
|
|
86
102
|
|
|
@@ -90,13 +106,13 @@ module Backup
|
|
|
90
106
|
# paths to directories that don't yet exist when creating new directories.
|
|
91
107
|
# Instead, we split the parts up in to an array (for each '/') and loop through
|
|
92
108
|
# that to create the directories one by one. Net::SFTP raises an exception when
|
|
93
|
-
# the directory it's trying
|
|
94
|
-
def create_remote_directories
|
|
109
|
+
# the directory it's trying to create already exists, so we have rescue it
|
|
110
|
+
def create_remote_directories(sftp)
|
|
95
111
|
path_parts = Array.new
|
|
96
112
|
remote_path.split('/').each do |path_part|
|
|
97
113
|
path_parts << path_part
|
|
98
114
|
begin
|
|
99
|
-
|
|
115
|
+
sftp.mkdir!(path_parts.join('/'))
|
|
100
116
|
rescue Net::SFTP::StatusException; end
|
|
101
117
|
end
|
|
102
118
|
end
|
data/lib/backup/syncer/base.rb
CHANGED
data/lib/backup/syncer/rsync.rb
CHANGED
|
@@ -67,7 +67,7 @@ module Backup
|
|
|
67
67
|
def perform!
|
|
68
68
|
Logger.message("#{ self.class } started syncing #{ directories }.")
|
|
69
69
|
Logger.silent(
|
|
70
|
-
run("#{ utility(:rsync) }
|
|
70
|
+
run("#{ utility(:rsync) } #{ options } #{ directories } '#{ username }@#{ ip }:#{ path }'")
|
|
71
71
|
)
|
|
72
72
|
|
|
73
73
|
remove_password_file!
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require 'erb'
|
|
4
|
+
|
|
5
|
+
module Backup
|
|
6
|
+
class Template
|
|
7
|
+
|
|
8
|
+
# Holds a binding object. Nil if not provided.
|
|
9
|
+
attr_accessor :binding
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Creates a new instance of the Backup::Template class
|
|
13
|
+
# and optionally takes an argument that can be either a binding object, a Hash or nil
|
|
14
|
+
def initialize(object = nil)
|
|
15
|
+
if object.is_a?(Binding)
|
|
16
|
+
@binding = object
|
|
17
|
+
elsif object.is_a?(Hash)
|
|
18
|
+
@binding = Backup::Binder.new(object).get_binding
|
|
19
|
+
else
|
|
20
|
+
@binding = nil
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Renders the provided file (in the context of the binding if any) to the console
|
|
26
|
+
def render(file)
|
|
27
|
+
puts result(file)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Returns a String object containing the contents of the file (in the context of the binding if any)
|
|
32
|
+
def result(file)
|
|
33
|
+
ERB.new(file_contents(file), nil, '<>').result(binding)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Reads and returns the contents of the provided file path,
|
|
40
|
+
# relative from the Backup::TEMPLATE_PATH
|
|
41
|
+
def file_contents(file)
|
|
42
|
+
File.read(File.join(Backup::TEMPLATE_PATH, file))
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/backup/version.rb
CHANGED
data/spec/archive_spec.rb
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
-
require File.
|
|
3
|
+
require File.expand_path('../spec_helper.rb', __FILE__)
|
|
4
4
|
|
|
5
5
|
describe Backup::Archive do
|
|
6
6
|
|
|
7
7
|
let(:archive) do
|
|
8
8
|
Backup::Archive.new(:dummy_archive) do |a|
|
|
9
9
|
a.add '/home/rspecuser/somefile'
|
|
10
|
-
a.add '/home/rspecuser/logs
|
|
11
|
-
a.add '/home/rspecuser/dotfiles
|
|
10
|
+
a.add '/home/rspecuser/logs'
|
|
11
|
+
a.add '/home/rspecuser/dotfiles'
|
|
12
12
|
a.exclude '/home/rspecuser/badfile'
|
|
13
|
-
a.exclude '/home/rspecuser/wrongdir
|
|
13
|
+
a.exclude '/home/rspecuser/wrongdir'
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -39,7 +39,7 @@ describe Backup::Archive do
|
|
|
39
39
|
describe '#paths_to_package' do
|
|
40
40
|
it 'should return a tar -c friendly string' do
|
|
41
41
|
archive.send(:paths_to_package).should ==
|
|
42
|
-
"'/home/rspecuser/somefile' '/home/rspecuser/logs
|
|
42
|
+
"'/home/rspecuser/somefile' '/home/rspecuser/logs' '/home/rspecuser/dotfiles'"
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -51,7 +51,7 @@ describe Backup::Archive do
|
|
|
51
51
|
|
|
52
52
|
it 'should return a tar -c friendly string' do
|
|
53
53
|
archive.send(:paths_to_exclude).should ==
|
|
54
|
-
"--exclude='/home/rspecuser/badfile' --exclude='/home/rspecuser/wrongdir
|
|
54
|
+
"--exclude='/home/rspecuser/badfile' --exclude='/home/rspecuser/wrongdir'"
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -63,7 +63,10 @@ describe Backup::Archive do
|
|
|
63
63
|
context 'when both paths were added and paths that should be excluded were added' do
|
|
64
64
|
it 'should render both the syntax for the paths that be included as well as excluded' do
|
|
65
65
|
archive.expects(:mkdir).with(File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive'))
|
|
66
|
-
archive.expects(:run).with(
|
|
66
|
+
archive.expects(:run).with(
|
|
67
|
+
"tar -cf '#{File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive', "#{:dummy_archive}.tar")}' --exclude='/home/rspecuser/badfile' --exclude='/home/rspecuser/wrongdir' '/home/rspecuser/somefile' '/home/rspecuser/logs' '/home/rspecuser/dotfiles'",
|
|
68
|
+
:ignore_exit_codes => [1]
|
|
69
|
+
)
|
|
67
70
|
archive.expects(:utility).with(:tar).returns(:tar)
|
|
68
71
|
archive.perform!
|
|
69
72
|
end
|
|
@@ -76,13 +79,35 @@ describe Backup::Archive do
|
|
|
76
79
|
end
|
|
77
80
|
|
|
78
81
|
archive.stubs(:utility).returns(:tar)
|
|
79
|
-
archive.expects(:run).with(
|
|
82
|
+
archive.expects(:run).with(
|
|
83
|
+
"tar -cf '#{File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive', "#{:dummy_archive}.tar")}' '/path/to/archive'",
|
|
84
|
+
:ignore_exit_codes => [1]
|
|
85
|
+
)
|
|
80
86
|
archive.perform!
|
|
81
87
|
end
|
|
82
88
|
end
|
|
83
89
|
|
|
90
|
+
context 'when tar_options are given' do
|
|
91
|
+
it 'should add the options to the tar command' do
|
|
92
|
+
archive = Backup::Archive.new(:dummy_archive) do |a|
|
|
93
|
+
a.add '/path/to/archive'
|
|
94
|
+
a.tar_options '-h --xattrs'
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
archive.stubs(:utility).returns(:tar)
|
|
98
|
+
archive.expects(:run).with(
|
|
99
|
+
"tar -h --xattrs -cf '#{File.join(Backup::TMP_PATH, Backup::TRIGGER, 'archive', "#{:dummy_archive}.tar")}' '/path/to/archive'",
|
|
100
|
+
:ignore_exit_codes => [1]
|
|
101
|
+
)
|
|
102
|
+
archive.perform!
|
|
103
|
+
end
|
|
104
|
+
end
|
|
84
105
|
it 'should log the status' do
|
|
85
|
-
Backup::Logger.expects(:message).
|
|
106
|
+
Backup::Logger.expects(:message).
|
|
107
|
+
with("Backup::Archive started packaging and archiving:\n" +
|
|
108
|
+
" /home/rspecuser/somefile\n" +
|
|
109
|
+
" /home/rspecuser/logs\n" +
|
|
110
|
+
" /home/rspecuser/dotfiles")
|
|
86
111
|
archive.perform!
|
|
87
112
|
end
|
|
88
113
|
end
|