backup 3.0.20 → 3.0.21
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/Gemfile +1 -5
- data/Gemfile.lock +46 -50
- data/README.md +54 -27
- data/lib/backup.rb +16 -39
- data/lib/backup/archive.rb +42 -18
- data/lib/backup/cleaner.rb +110 -25
- data/lib/backup/cli/helpers.rb +17 -32
- data/lib/backup/cli/utility.rb +46 -107
- data/lib/backup/compressor/base.rb +14 -2
- data/lib/backup/compressor/bzip2.rb +10 -24
- data/lib/backup/compressor/gzip.rb +10 -24
- data/lib/backup/compressor/lzma.rb +10 -23
- data/lib/backup/compressor/pbzip2.rb +12 -32
- data/lib/backup/config.rb +171 -0
- data/lib/backup/configuration/compressor/base.rb +1 -2
- data/lib/backup/configuration/compressor/pbzip2.rb +4 -4
- data/lib/backup/configuration/database/base.rb +2 -1
- data/lib/backup/configuration/database/mongodb.rb +8 -0
- data/lib/backup/configuration/database/mysql.rb +4 -0
- data/lib/backup/configuration/database/postgresql.rb +4 -0
- data/lib/backup/configuration/database/redis.rb +4 -0
- data/lib/backup/configuration/database/riak.rb +5 -1
- data/lib/backup/configuration/encryptor/base.rb +1 -2
- data/lib/backup/configuration/encryptor/open_ssl.rb +1 -1
- data/lib/backup/configuration/helpers.rb +7 -2
- data/lib/backup/configuration/notifier/base.rb +4 -28
- data/lib/backup/configuration/storage/base.rb +1 -1
- data/lib/backup/configuration/storage/dropbox.rb +14 -4
- data/lib/backup/configuration/syncer/base.rb +10 -0
- data/lib/backup/configuration/syncer/rsync/base.rb +28 -0
- data/lib/backup/configuration/syncer/rsync/local.rb +11 -0
- data/lib/backup/configuration/syncer/rsync/pull.rb +11 -0
- data/lib/backup/configuration/syncer/rsync/push.rb +31 -0
- data/lib/backup/configuration/syncer/s3.rb +0 -4
- data/lib/backup/database/base.rb +25 -7
- data/lib/backup/database/mongodb.rb +112 -75
- data/lib/backup/database/mysql.rb +54 -29
- data/lib/backup/database/postgresql.rb +60 -42
- data/lib/backup/database/redis.rb +61 -39
- data/lib/backup/database/riak.rb +35 -11
- data/lib/backup/dependency.rb +4 -5
- data/lib/backup/encryptor/base.rb +13 -1
- data/lib/backup/encryptor/gpg.rb +39 -39
- data/lib/backup/encryptor/open_ssl.rb +28 -38
- data/lib/backup/logger.rb +20 -11
- data/lib/backup/model.rb +206 -163
- data/lib/backup/notifier/base.rb +27 -25
- data/lib/backup/notifier/campfire.rb +7 -13
- data/lib/backup/notifier/hipchat.rb +28 -28
- data/lib/backup/notifier/mail.rb +24 -26
- data/lib/backup/notifier/presently.rb +10 -18
- data/lib/backup/notifier/prowl.rb +9 -17
- data/lib/backup/notifier/twitter.rb +11 -18
- data/lib/backup/package.rb +47 -0
- data/lib/backup/packager.rb +81 -16
- data/lib/backup/splitter.rb +48 -35
- data/lib/backup/storage/base.rb +44 -172
- data/lib/backup/storage/cloudfiles.rb +31 -46
- data/lib/backup/storage/cycler.rb +117 -0
- data/lib/backup/storage/dropbox.rb +92 -76
- data/lib/backup/storage/ftp.rb +30 -40
- data/lib/backup/storage/local.rb +44 -45
- data/lib/backup/storage/ninefold.rb +55 -49
- data/lib/backup/storage/rsync.rb +49 -56
- data/lib/backup/storage/s3.rb +33 -44
- data/lib/backup/storage/scp.rb +21 -48
- data/lib/backup/storage/sftp.rb +26 -40
- data/lib/backup/syncer/base.rb +7 -0
- data/lib/backup/syncer/rsync/base.rb +78 -0
- data/lib/backup/syncer/rsync/local.rb +53 -0
- data/lib/backup/syncer/rsync/pull.rb +38 -0
- data/lib/backup/syncer/rsync/push.rb +113 -0
- data/lib/backup/syncer/s3.rb +42 -32
- data/lib/backup/version.rb +1 -1
- data/spec/archive_spec.rb +235 -69
- data/spec/cleaner_spec.rb +304 -0
- data/spec/cli/helpers_spec.rb +142 -1
- data/spec/cli/utility_spec.rb +338 -13
- data/spec/compressor/base_spec.rb +31 -0
- data/spec/compressor/bzip2_spec.rb +60 -35
- data/spec/compressor/gzip_spec.rb +60 -35
- data/spec/compressor/lzma_spec.rb +60 -35
- data/spec/compressor/pbzip2_spec.rb +98 -37
- data/spec/config_spec.rb +321 -0
- data/spec/configuration/base_spec.rb +4 -4
- data/spec/configuration/compressor/bzip2_spec.rb +1 -0
- data/spec/configuration/compressor/gzip_spec.rb +1 -0
- data/spec/configuration/compressor/lzma_spec.rb +1 -0
- data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
- data/spec/configuration/database/base_spec.rb +2 -1
- data/spec/configuration/database/mongodb_spec.rb +26 -16
- data/spec/configuration/database/mysql_spec.rb +4 -0
- data/spec/configuration/database/postgresql_spec.rb +4 -0
- data/spec/configuration/database/redis_spec.rb +4 -0
- data/spec/configuration/database/riak_spec.rb +4 -0
- data/spec/configuration/encryptor/gpg_spec.rb +1 -0
- data/spec/configuration/encryptor/open_ssl_spec.rb +1 -0
- data/spec/configuration/notifier/base_spec.rb +32 -0
- data/spec/configuration/notifier/campfire_spec.rb +1 -0
- data/spec/configuration/notifier/hipchat_spec.rb +1 -0
- data/spec/configuration/notifier/mail_spec.rb +1 -0
- data/spec/configuration/notifier/presently_spec.rb +1 -0
- data/spec/configuration/notifier/prowl_spec.rb +1 -0
- data/spec/configuration/notifier/twitter_spec.rb +1 -0
- data/spec/configuration/storage/cloudfiles_spec.rb +1 -0
- data/spec/configuration/storage/dropbox_spec.rb +4 -3
- data/spec/configuration/storage/ftp_spec.rb +1 -0
- data/spec/configuration/storage/local_spec.rb +1 -0
- data/spec/configuration/storage/ninefold_spec.rb +1 -0
- data/spec/configuration/storage/rsync_spec.rb +3 -1
- data/spec/configuration/storage/s3_spec.rb +1 -0
- data/spec/configuration/storage/scp_spec.rb +1 -0
- data/spec/configuration/storage/sftp_spec.rb +1 -0
- data/spec/configuration/syncer/rsync/base_spec.rb +33 -0
- data/spec/configuration/syncer/rsync/local_spec.rb +10 -0
- data/spec/configuration/syncer/rsync/pull_spec.rb +10 -0
- data/spec/configuration/syncer/{rsync_spec.rb → rsync/push_spec.rb} +12 -15
- data/spec/configuration/syncer/s3_spec.rb +2 -3
- data/spec/database/base_spec.rb +35 -20
- data/spec/database/mongodb_spec.rb +298 -119
- data/spec/database/mysql_spec.rb +147 -72
- data/spec/database/postgresql_spec.rb +155 -100
- data/spec/database/redis_spec.rb +200 -97
- data/spec/database/riak_spec.rb +82 -24
- data/spec/dependency_spec.rb +49 -0
- data/spec/encryptor/base_spec.rb +30 -0
- data/spec/encryptor/gpg_spec.rb +105 -28
- data/spec/encryptor/open_ssl_spec.rb +85 -114
- data/spec/logger_spec.rb +74 -8
- data/spec/model_spec.rb +528 -220
- data/spec/notifier/base_spec.rb +89 -0
- data/spec/notifier/campfire_spec.rb +147 -119
- data/spec/notifier/hipchat_spec.rb +140 -145
- data/spec/notifier/mail_spec.rb +190 -248
- data/spec/notifier/presently_spec.rb +147 -282
- data/spec/notifier/prowl_spec.rb +79 -111
- data/spec/notifier/twitter_spec.rb +87 -106
- data/spec/package_spec.rb +61 -0
- data/spec/packager_spec.rb +154 -0
- data/spec/spec_helper.rb +36 -13
- data/spec/splitter_spec.rb +90 -41
- data/spec/storage/base_spec.rb +95 -239
- data/spec/storage/cloudfiles_spec.rb +185 -75
- data/spec/storage/cycler_spec.rb +239 -0
- data/spec/storage/dropbox_spec.rb +318 -87
- data/spec/storage/ftp_spec.rb +165 -152
- data/spec/storage/local_spec.rb +206 -54
- data/spec/storage/ninefold_spec.rb +264 -128
- data/spec/storage/rsync_spec.rb +244 -163
- data/spec/storage/s3_spec.rb +175 -64
- data/spec/storage/scp_spec.rb +156 -150
- data/spec/storage/sftp_spec.rb +153 -135
- data/spec/syncer/base_spec.rb +22 -0
- data/spec/syncer/rsync/base_spec.rb +118 -0
- data/spec/syncer/rsync/local_spec.rb +121 -0
- data/spec/syncer/rsync/pull_spec.rb +90 -0
- data/spec/syncer/rsync/push_spec.rb +327 -0
- data/spec/syncer/s3_spec.rb +180 -91
- data/templates/cli/utility/config +1 -1
- data/templates/cli/utility/database/mongodb +4 -0
- data/templates/cli/utility/database/mysql +3 -0
- data/templates/cli/utility/database/postgresql +3 -0
- data/templates/cli/utility/database/redis +3 -0
- data/templates/cli/utility/database/riak +3 -0
- data/templates/cli/utility/storage/dropbox +4 -1
- data/templates/cli/utility/syncer/rsync_local +12 -0
- data/templates/cli/utility/syncer/{rsync → rsync_pull} +2 -2
- data/templates/cli/utility/syncer/rsync_push +17 -0
- data/templates/storage/dropbox/authorization_url.erb +1 -1
- metadata +42 -17
- data/lib/backup/configuration/syncer/rsync.rb +0 -45
- data/lib/backup/finder.rb +0 -87
- data/lib/backup/storage/object.rb +0 -47
- data/lib/backup/syncer/rsync.rb +0 -152
- data/spec/backup_spec.rb +0 -11
- data/spec/finder_spec.rb +0 -91
- data/spec/storage/object_spec.rb +0 -74
- data/spec/syncer/rsync_spec.rb +0 -195
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
class Package
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# The time when the backup initiated (in format: 2011.02.20.03.29.59)
|
|
8
|
+
attr_reader :time
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# The trigger which initiated the backup process
|
|
12
|
+
attr_reader :trigger
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Extension for the final archive file(s)
|
|
16
|
+
attr_accessor :extension
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Set by the Splitter if the final archive was "chunked"
|
|
20
|
+
attr_accessor :chunk_suffixes
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# The version of Backup used to create the package
|
|
24
|
+
attr_reader :version
|
|
25
|
+
|
|
26
|
+
def initialize(model)
|
|
27
|
+
@time = model.time
|
|
28
|
+
@trigger = model.trigger
|
|
29
|
+
@extension = 'tar'
|
|
30
|
+
@chunk_suffixes = Array.new
|
|
31
|
+
@version = Backup::Version.current
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def filenames
|
|
35
|
+
if chunk_suffixes.empty?
|
|
36
|
+
[basename]
|
|
37
|
+
else
|
|
38
|
+
chunk_suffixes.map {|suffix| "#{ basename }-#{ suffix }" }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def basename
|
|
43
|
+
"#{ time }.#{ trigger }.#{ extension }"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/backup/packager.rb
CHANGED
|
@@ -1,25 +1,90 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
3
|
module Backup
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module Packager
|
|
5
|
+
class << self
|
|
6
|
+
include Backup::CLI::Helpers
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
##
|
|
9
|
+
# Build the final package for the backup model.
|
|
10
|
+
def package!(model)
|
|
11
|
+
@package = model.package
|
|
12
|
+
@encryptor = model.encryptor
|
|
13
|
+
@splitter = model.splitter
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
end
|
|
15
|
+
Logger.message "Packaging the backup files..."
|
|
16
|
+
procedure.call
|
|
17
|
+
Logger.message "Packaging Complete!"
|
|
18
|
+
end
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Builds a chain of nested Procs which assemble and execute
|
|
24
|
+
# the final command to package the backup.
|
|
25
|
+
# This is done so that the Encryptor and Splitter have the ability
|
|
26
|
+
# to perform actions before and after the final command is executed.
|
|
27
|
+
# No Encryptors currently utilize this, however the Splitter does.
|
|
28
|
+
def procedure
|
|
29
|
+
stack = []
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Initial `tar` command to package the temporary backup folder.
|
|
33
|
+
# The command's output will then be either piped to the Encryptor
|
|
34
|
+
# or the Splitter (if no Encryptor), or redirected into the final
|
|
35
|
+
# output file if neither are configured.
|
|
36
|
+
@package_command = "#{ utility(:tar) } -cf - " +
|
|
37
|
+
"-C '#{ Config.tmp_path }' '#{ @package.trigger }'"
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# If an Encryptor was configured, it will be called first
|
|
41
|
+
# to amend the command to be piped through the encryption utility.
|
|
42
|
+
# It's output will then be either piped into a Splitter, or sent
|
|
43
|
+
# directly to the final output file.
|
|
44
|
+
if @encryptor
|
|
45
|
+
stack << lambda do
|
|
46
|
+
@encryptor.encrypt_with do |command, ext|
|
|
47
|
+
@package_command << " | #{command}"
|
|
48
|
+
@package.extension << ext
|
|
49
|
+
stack.shift.call
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
23
53
|
|
|
54
|
+
##
|
|
55
|
+
# If a Splitter was configured, the command will be piped through
|
|
56
|
+
# the `split` command. Once the Proc executing the final command
|
|
57
|
+
# has completed and returns back to the Splitter, it will check the
|
|
58
|
+
# final output files to determine if the backup was indeed split.
|
|
59
|
+
# If so, it will set the package's chunk_suffixes. If not, it will
|
|
60
|
+
# remove the '-aa' suffix from the only file created by `split`.
|
|
61
|
+
#
|
|
62
|
+
# If no Splitter was configured, the command output will be
|
|
63
|
+
# redirected directly into the final output file.
|
|
64
|
+
if @splitter
|
|
65
|
+
stack << lambda do
|
|
66
|
+
@splitter.split_with do |command|
|
|
67
|
+
@package_command << " | #{command}"
|
|
68
|
+
stack.shift.call
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
else
|
|
72
|
+
stack << lambda do
|
|
73
|
+
outfile = File.join(Config.tmp_path, @package.basename)
|
|
74
|
+
@package_command << " > #{ outfile }"
|
|
75
|
+
stack.shift.call
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Last Proc to be called runs the command the procedure built.
|
|
81
|
+
# Once complete, the call stack will unwind back through the
|
|
82
|
+
# preceeding Procs in the stack (if any)
|
|
83
|
+
stack << lambda { run(@package_command) }
|
|
84
|
+
|
|
85
|
+
stack.shift
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
24
89
|
end
|
|
25
90
|
end
|
data/lib/backup/splitter.rb
CHANGED
|
@@ -4,58 +4,71 @@ module Backup
|
|
|
4
4
|
class Splitter
|
|
5
5
|
include Backup::CLI::Helpers
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
def initialize(model, chunk_size)
|
|
8
|
+
@model = model
|
|
9
|
+
@chunk_size = chunk_size
|
|
10
|
+
end
|
|
10
11
|
|
|
11
12
|
##
|
|
12
|
-
#
|
|
13
|
-
|
|
13
|
+
# This is called as part of the procedure used to build the final
|
|
14
|
+
# backup package file(s). It yields it's portion of the command line
|
|
15
|
+
# for this procedure, which will split the data being piped into it
|
|
16
|
+
# into multiple files, based on the @chunk_size.
|
|
17
|
+
# Once the packaging procedure is complete, it will return and
|
|
18
|
+
# @package.chunk_suffixes will be set based on the resulting files.
|
|
19
|
+
def split_with
|
|
20
|
+
before_packaging
|
|
21
|
+
yield @split_command
|
|
22
|
+
after_packaging
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
14
26
|
|
|
15
27
|
##
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
# The `split` command reads from $stdin and will store it's output in
|
|
29
|
+
# multiple files, based on the @chunk_size. The files will be
|
|
30
|
+
# written using the given `prefix`, which is the full path to the
|
|
31
|
+
# final @package.basename, plus a '-' separator. This `prefix` will then
|
|
32
|
+
# be suffixed using 'aa', 'ab', and so on... for each file.
|
|
33
|
+
def before_packaging
|
|
34
|
+
@package = @model.package
|
|
35
|
+
Logger.message "Splitter configured with a chunk size of " +
|
|
36
|
+
"#{ @chunk_size }MB."
|
|
37
|
+
|
|
38
|
+
@split_command = "#{ utility(:split) } -b #{ @chunk_size }m - " +
|
|
39
|
+
"'#{ File.join(Config.tmp_path, @package.basename + '-') }'"
|
|
22
40
|
end
|
|
23
41
|
|
|
24
42
|
##
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
# Finds the resulting files from the packaging procedure
|
|
44
|
+
# and stores an Array of suffixes used in @package.chunk_suffixes.
|
|
45
|
+
# If the @chunk_size was never reached and only one file
|
|
46
|
+
# was written, that file will be suffixed with '-aa'.
|
|
47
|
+
# In which case, it will simply remove the suffix from the filename.
|
|
48
|
+
def after_packaging
|
|
49
|
+
suffixes = chunk_suffixes
|
|
50
|
+
if suffixes == ['aa']
|
|
51
|
+
FileUtils.mv(
|
|
52
|
+
File.join(Config.tmp_path, @package.basename + '-aa'),
|
|
53
|
+
File.join(Config.tmp_path, @package.basename)
|
|
54
|
+
)
|
|
55
|
+
else
|
|
56
|
+
@package.chunk_suffixes = suffixes
|
|
34
57
|
end
|
|
35
58
|
end
|
|
36
59
|
|
|
37
|
-
private
|
|
38
|
-
|
|
39
60
|
##
|
|
40
|
-
# Returns an array of suffixes for each chunk.
|
|
41
|
-
# For example: [aa, ab, ac, ad, ae]
|
|
61
|
+
# Returns an array of suffixes for each chunk, in alphabetical order.
|
|
62
|
+
# For example: [aa, ab, ac, ad, ae]
|
|
42
63
|
def chunk_suffixes
|
|
43
|
-
chunks.map
|
|
44
|
-
File.extname(chunk).split("-").last
|
|
45
|
-
end.sort
|
|
64
|
+
chunks.map {|chunk| File.extname(chunk).split('-').last }.sort
|
|
46
65
|
end
|
|
47
66
|
|
|
48
67
|
##
|
|
49
68
|
# Returns an array of full paths to the backup chunks.
|
|
50
|
-
# Chunks
|
|
69
|
+
# Chunks are sorted in alphabetical order.
|
|
51
70
|
def chunks
|
|
52
|
-
Dir[
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
##
|
|
56
|
-
# Converts the provided megabytes to a bytes representation
|
|
57
|
-
def bytes_representation_of(megabytes)
|
|
58
|
-
megabytes * 1024 * 1024
|
|
71
|
+
Dir[File.join(Config.tmp_path, @package.basename + '-*')].sort
|
|
59
72
|
end
|
|
60
73
|
|
|
61
74
|
end
|
data/lib/backup/storage/base.rb
CHANGED
|
@@ -5,107 +5,36 @@ module Backup
|
|
|
5
5
|
class Base
|
|
6
6
|
include Backup::Configuration::Helpers
|
|
7
7
|
|
|
8
|
-
##
|
|
9
|
-
# The time when the backup initiated (in format: 2011.02.20.03.29.59)
|
|
10
|
-
attr_accessor :time
|
|
11
|
-
|
|
12
8
|
##
|
|
13
9
|
# Sets the limit to how many backups to keep in the remote location.
|
|
14
10
|
# If exceeded, the oldest will be removed to make room for the newest
|
|
15
11
|
attr_accessor :keep
|
|
16
12
|
|
|
17
|
-
# Temporarily holds the configuration block used to instantiate the
|
|
18
|
-
# storage object. Used for updating storage objects loaded from YAML
|
|
19
|
-
# during backup rotation in #cycle!
|
|
20
|
-
attr_accessor :configure_block
|
|
21
|
-
|
|
22
|
-
##
|
|
23
|
-
# Contains an array of chunk suffixes (if any)
|
|
24
|
-
# If none are set, this will be an empty array, in which case Backup assumes
|
|
25
|
-
# we haven't been splitting the backup in to multiple chunks. The storage object
|
|
26
|
-
# will only attempt to transfer/remove chunks if this array contains chunk suffixes.
|
|
27
|
-
attr_accessor :chunk_suffixes
|
|
28
|
-
|
|
29
|
-
##
|
|
30
|
-
# Super method for the child classes' perform! method. "super" should
|
|
31
|
-
# always be invoked from the child classes' perform! method to ensure that the
|
|
32
|
-
# @chunk_suffixes array gets set to the storage object, which will be used to transfer all the
|
|
33
|
-
# chunks to the remote location, rather than the single backup file. Also, this will be persisted
|
|
34
|
-
# and loaded back in during the cycling process, so it gets properly deleted from the remote location.
|
|
35
|
-
|
|
36
13
|
##
|
|
37
14
|
# (Optional)
|
|
38
|
-
# User-defined string used to uniquely identify multiple storages of the
|
|
39
|
-
# This will be appended to the YAML storage file used for
|
|
15
|
+
# User-defined string used to uniquely identify multiple storages of the
|
|
16
|
+
# same type. This will be appended to the YAML storage file used for
|
|
17
|
+
# cycling backups.
|
|
40
18
|
attr_accessor :storage_id
|
|
41
19
|
|
|
42
|
-
##
|
|
43
|
-
# Set to Backup::Version.current just before the object is stored
|
|
44
|
-
# in the YAML file for cycling. This way, we know when the object
|
|
45
|
-
# is loaded from the YAML file, which version of Backup stored it.
|
|
46
|
-
attr_reader :version
|
|
47
|
-
|
|
48
|
-
def perform!
|
|
49
|
-
@chunk_suffixes ||= Backup::Model.chunk_suffixes
|
|
50
|
-
end
|
|
51
|
-
|
|
52
20
|
##
|
|
53
21
|
# Creates a new instance of the storage object
|
|
54
|
-
|
|
55
|
-
|
|
22
|
+
# * Called with super(model, storage_id) from each subclass
|
|
23
|
+
def initialize(model, storage_id = nil)
|
|
24
|
+
load_defaults!
|
|
25
|
+
@model = model
|
|
56
26
|
@storage_id = storage_id
|
|
57
|
-
configure!
|
|
58
27
|
end
|
|
59
28
|
|
|
60
29
|
##
|
|
61
|
-
#
|
|
62
|
-
def
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
##
|
|
68
|
-
# Returns the full filename of the processed backup file
|
|
69
|
-
def filename
|
|
70
|
-
@filename ||= File.basename(Backup::Model.file)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
##
|
|
74
|
-
# Returns the local path
|
|
75
|
-
def local_path
|
|
76
|
-
TMP_PATH
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
##
|
|
80
|
-
# Returns an array of backup chunks
|
|
81
|
-
def chunks
|
|
82
|
-
chunk_suffixes.map do |chunk_suffix|
|
|
83
|
-
"#{ filename }-#{ chunk_suffix }"
|
|
84
|
-
end.sort
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
##
|
|
88
|
-
# Returns a block with two arguments: "local_file, remote_file"
|
|
89
|
-
# The local_file is the full file name: "2011.08.30.11.00.02.backup.tar.gz.enc"
|
|
90
|
-
# The remote_file is the full file name, minus the timestamp: "backup.tar.gz.enc"
|
|
91
|
-
def files_to_transfer
|
|
92
|
-
if chunks?
|
|
93
|
-
chunks.each do |chunk|
|
|
94
|
-
yield chunk, chunk[20..-1]
|
|
95
|
-
end
|
|
96
|
-
else
|
|
97
|
-
yield filename, filename[20..-1]
|
|
98
|
-
end
|
|
30
|
+
# Performs the backup transfer
|
|
31
|
+
def perform!
|
|
32
|
+
@package = @model.package
|
|
33
|
+
transfer!
|
|
34
|
+
cycle!
|
|
99
35
|
end
|
|
100
36
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
##
|
|
104
|
-
# Returns true if we're working with chunks
|
|
105
|
-
# that were splitted by Backup
|
|
106
|
-
def chunks?
|
|
107
|
-
chunk_suffixes.is_a?(Array) and chunk_suffixes.count > 0
|
|
108
|
-
end
|
|
37
|
+
private
|
|
109
38
|
|
|
110
39
|
##
|
|
111
40
|
# Provider defaults to false. Overridden when using a service-based
|
|
@@ -114,112 +43,55 @@ module Backup
|
|
|
114
43
|
false
|
|
115
44
|
end
|
|
116
45
|
|
|
117
|
-
private
|
|
118
|
-
|
|
119
|
-
##
|
|
120
|
-
# Configure the storage object, using optional configuration block
|
|
121
|
-
# Uses #pre_configure to set defaults (if any exist) and then evaluates
|
|
122
|
-
# the optional configuration block which may overwrite these defaults.
|
|
123
|
-
# Then uses #post_configure to adjust the configuration as needed.
|
|
124
|
-
#
|
|
125
|
-
# This method is also used to update storage objects loaded from the
|
|
126
|
-
# YAML data storage file used for backup rotation in #cycle!
|
|
127
|
-
def configure!
|
|
128
|
-
pre_configure
|
|
129
|
-
instance_eval(&@configure_block) if @configure_block
|
|
130
|
-
post_configure
|
|
131
|
-
self
|
|
132
|
-
end
|
|
133
|
-
|
|
134
46
|
##
|
|
135
|
-
#
|
|
136
|
-
|
|
137
|
-
def pre_configure
|
|
138
|
-
load_defaults!
|
|
139
|
-
end
|
|
47
|
+
# Each subclass must define a +path+ where remote files will be stored
|
|
48
|
+
def path; end
|
|
140
49
|
|
|
141
50
|
##
|
|
142
|
-
#
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
51
|
+
# Return the storage name, with optional storage_id
|
|
52
|
+
def storage_name
|
|
53
|
+
self.class.to_s.sub('Backup::', '') +
|
|
54
|
+
(storage_id ? " (#{storage_id})" : '')
|
|
146
55
|
end
|
|
147
56
|
|
|
148
57
|
##
|
|
149
|
-
#
|
|
150
|
-
# This is
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
# configuration from the current backup job.
|
|
154
|
-
def update!(configure_block)
|
|
155
|
-
upgrade_if_needed!
|
|
156
|
-
instance_exec(configure_block) do |block|
|
|
157
|
-
@configure_block = block; configure!
|
|
158
|
-
end
|
|
58
|
+
# Returns the local path
|
|
59
|
+
# This is where any Package to be transferred is located.
|
|
60
|
+
def local_path
|
|
61
|
+
Config.tmp_path
|
|
159
62
|
end
|
|
160
63
|
|
|
161
64
|
##
|
|
162
|
-
#
|
|
163
|
-
#
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return if version == Backup::Version.current
|
|
167
|
-
case
|
|
168
|
-
when version.nil? # <= 3.0.19
|
|
169
|
-
@filename = @remote_file
|
|
170
|
-
@chunk_suffixes = []
|
|
171
|
-
clean!
|
|
172
|
-
else; # upgrade not required
|
|
173
|
-
end
|
|
65
|
+
# Returns the remote path for the given Package
|
|
66
|
+
# This is where the Package will be stored, or was previously stored.
|
|
67
|
+
def remote_path_for(package)
|
|
68
|
+
File.join(path, package.trigger, package.time)
|
|
174
69
|
end
|
|
175
70
|
|
|
176
71
|
##
|
|
177
|
-
#
|
|
178
|
-
#
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
72
|
+
# Yields two arguments to the given block: "local_file, remote_file"
|
|
73
|
+
# The local_file is the full file name:
|
|
74
|
+
# e.g. "2011.08.30.11.00.02.backup.tar.enc"
|
|
75
|
+
# The remote_file is the full file name, minus the timestamp:
|
|
76
|
+
# e.g. "backup.tar.enc"
|
|
77
|
+
def files_to_transfer_for(package)
|
|
78
|
+
package.filenames.each do |filename|
|
|
79
|
+
yield filename, filename[20..-1]
|
|
183
80
|
end
|
|
184
|
-
@version = Backup::Version.current
|
|
185
81
|
end
|
|
82
|
+
alias :transferred_files_for :files_to_transfer_for
|
|
186
83
|
|
|
187
84
|
##
|
|
188
|
-
#
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
# array of objects that still remain after the removal of the older
|
|
194
|
-
# objects and files (that exceeded the @keep range). And finally these
|
|
195
|
-
# remaining objects will be converted to YAML format and are written back
|
|
196
|
-
# to the YAML file.
|
|
197
|
-
# Each remaining storage object's attributes will be updated using the
|
|
198
|
-
# defaults and configuration block defined for the current backup job
|
|
199
|
-
# in case the storage location is changed or credentials are updated.
|
|
85
|
+
# Adds the current package being stored to the YAML cycle data file
|
|
86
|
+
# and will remove any old Package file(s) when the storage limit
|
|
87
|
+
# set by #keep is exceeded. Any errors raised while attempting to
|
|
88
|
+
# remove older packages will be rescued and a warning will be logged
|
|
89
|
+
# containing the original error message.
|
|
200
90
|
def cycle!
|
|
201
91
|
return unless keep.to_i > 0
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
objects.each {|object| object.send(:update!, @configure_block) }
|
|
206
|
-
objects.unshift(self)
|
|
207
|
-
if objects.count > keep
|
|
208
|
-
objects_to_remove = objects[keep..-1]
|
|
209
|
-
objects_to_remove.each do |object|
|
|
210
|
-
Logger.message "#{storage_name} started removing (cycling) " +
|
|
211
|
-
"'#{ object.filename }'."
|
|
212
|
-
begin
|
|
213
|
-
object.send(:remove!)
|
|
214
|
-
rescue => err
|
|
215
|
-
Logger.warn Errors::Storage::CycleError.wrap(err,
|
|
216
|
-
"#{storage_name} failed to remove '#{object.filename}'")
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
objects = objects - objects_to_remove
|
|
220
|
-
end
|
|
221
|
-
objects.each {|object| object.send(:clean!) }
|
|
222
|
-
storage_object.write(objects)
|
|
92
|
+
Logger.message "#{ storage_name }: Cycling Started..."
|
|
93
|
+
Cycler.cycle!(self, @package)
|
|
94
|
+
Logger.message "#{ storage_name }: Cycling Complete!"
|
|
223
95
|
end
|
|
224
96
|
|
|
225
97
|
end
|