backup-remote 0.0.2
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.
- checksums.yaml +7 -0
- data/README.md +112 -0
- data/bin/backup-remote +5 -0
- data/lib/backup.rb +155 -0
- data/lib/backup/archive.rb +170 -0
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/cleaner.rb +116 -0
- data/lib/backup/cli.rb +374 -0
- data/lib/backup/cloud_io/base.rb +41 -0
- data/lib/backup/cloud_io/cloud_files.rb +298 -0
- data/lib/backup/cloud_io/s3.rb +260 -0
- data/lib/backup/compressor/base.rb +35 -0
- data/lib/backup/compressor/bzip2.rb +39 -0
- data/lib/backup/compressor/custom.rb +53 -0
- data/lib/backup/compressor/gzip.rb +74 -0
- data/lib/backup/config.rb +121 -0
- data/lib/backup/config/dsl.rb +106 -0
- data/lib/backup/config/helpers.rb +143 -0
- data/lib/backup/database/base.rb +85 -0
- data/lib/backup/database/mongodb.rb +187 -0
- data/lib/backup/database/mysql.rb +192 -0
- data/lib/backup/database/openldap.rb +95 -0
- data/lib/backup/database/postgresql.rb +133 -0
- data/lib/backup/database/redis.rb +179 -0
- data/lib/backup/database/remote_mysql.rb +248 -0
- data/lib/backup/database/riak.rb +82 -0
- data/lib/backup/database/sqlite.rb +57 -0
- data/lib/backup/encryptor/base.rb +29 -0
- data/lib/backup/encryptor/gpg.rb +747 -0
- data/lib/backup/encryptor/open_ssl.rb +77 -0
- data/lib/backup/errors.rb +58 -0
- data/lib/backup/logger.rb +199 -0
- data/lib/backup/logger/console.rb +51 -0
- data/lib/backup/logger/fog_adapter.rb +29 -0
- data/lib/backup/logger/logfile.rb +133 -0
- data/lib/backup/logger/syslog.rb +116 -0
- data/lib/backup/model.rb +479 -0
- data/lib/backup/notifier/base.rb +128 -0
- data/lib/backup/notifier/campfire.rb +63 -0
- data/lib/backup/notifier/command.rb +102 -0
- data/lib/backup/notifier/datadog.rb +107 -0
- data/lib/backup/notifier/flowdock.rb +103 -0
- data/lib/backup/notifier/hipchat.rb +118 -0
- data/lib/backup/notifier/http_post.rb +117 -0
- data/lib/backup/notifier/mail.rb +249 -0
- data/lib/backup/notifier/nagios.rb +69 -0
- data/lib/backup/notifier/pagerduty.rb +81 -0
- data/lib/backup/notifier/prowl.rb +68 -0
- data/lib/backup/notifier/pushover.rb +74 -0
- data/lib/backup/notifier/ses.rb +105 -0
- data/lib/backup/notifier/slack.rb +148 -0
- data/lib/backup/notifier/twitter.rb +58 -0
- data/lib/backup/notifier/zabbix.rb +63 -0
- data/lib/backup/package.rb +55 -0
- data/lib/backup/packager.rb +107 -0
- data/lib/backup/pipeline.rb +128 -0
- data/lib/backup/remote/command.rb +82 -0
- data/lib/backup/splitter.rb +76 -0
- data/lib/backup/storage/base.rb +69 -0
- data/lib/backup/storage/cloud_files.rb +158 -0
- data/lib/backup/storage/cycler.rb +75 -0
- data/lib/backup/storage/dropbox.rb +212 -0
- data/lib/backup/storage/ftp.rb +112 -0
- data/lib/backup/storage/local.rb +64 -0
- data/lib/backup/storage/qiniu.rb +65 -0
- data/lib/backup/storage/rsync.rb +248 -0
- data/lib/backup/storage/s3.rb +156 -0
- data/lib/backup/storage/scp.rb +67 -0
- data/lib/backup/storage/sftp.rb +82 -0
- data/lib/backup/syncer/base.rb +70 -0
- data/lib/backup/syncer/cloud/base.rb +179 -0
- data/lib/backup/syncer/cloud/cloud_files.rb +83 -0
- data/lib/backup/syncer/cloud/local_file.rb +100 -0
- data/lib/backup/syncer/cloud/s3.rb +110 -0
- data/lib/backup/syncer/rsync/base.rb +54 -0
- data/lib/backup/syncer/rsync/local.rb +31 -0
- data/lib/backup/syncer/rsync/pull.rb +51 -0
- data/lib/backup/syncer/rsync/push.rb +205 -0
- data/lib/backup/template.rb +46 -0
- data/lib/backup/utilities.rb +224 -0
- data/lib/backup/version.rb +5 -0
- data/templates/cli/archive +28 -0
- data/templates/cli/compressor/bzip2 +4 -0
- data/templates/cli/compressor/custom +7 -0
- data/templates/cli/compressor/gzip +4 -0
- data/templates/cli/config +123 -0
- data/templates/cli/databases/mongodb +15 -0
- data/templates/cli/databases/mysql +18 -0
- data/templates/cli/databases/openldap +24 -0
- data/templates/cli/databases/postgresql +16 -0
- data/templates/cli/databases/redis +16 -0
- data/templates/cli/databases/riak +17 -0
- data/templates/cli/databases/sqlite +11 -0
- data/templates/cli/encryptor/gpg +27 -0
- data/templates/cli/encryptor/openssl +9 -0
- data/templates/cli/model +26 -0
- data/templates/cli/notifier/zabbix +15 -0
- data/templates/cli/notifiers/campfire +12 -0
- data/templates/cli/notifiers/command +32 -0
- data/templates/cli/notifiers/datadog +57 -0
- data/templates/cli/notifiers/flowdock +16 -0
- data/templates/cli/notifiers/hipchat +16 -0
- data/templates/cli/notifiers/http_post +32 -0
- data/templates/cli/notifiers/mail +24 -0
- data/templates/cli/notifiers/nagios +13 -0
- data/templates/cli/notifiers/pagerduty +12 -0
- data/templates/cli/notifiers/prowl +11 -0
- data/templates/cli/notifiers/pushover +11 -0
- data/templates/cli/notifiers/ses +15 -0
- data/templates/cli/notifiers/slack +22 -0
- data/templates/cli/notifiers/twitter +13 -0
- data/templates/cli/splitter +7 -0
- data/templates/cli/storages/cloud_files +11 -0
- data/templates/cli/storages/dropbox +20 -0
- data/templates/cli/storages/ftp +13 -0
- data/templates/cli/storages/local +8 -0
- data/templates/cli/storages/qiniu +12 -0
- data/templates/cli/storages/rsync +17 -0
- data/templates/cli/storages/s3 +16 -0
- data/templates/cli/storages/scp +15 -0
- data/templates/cli/storages/sftp +15 -0
- data/templates/cli/syncers/cloud_files +22 -0
- data/templates/cli/syncers/rsync_local +20 -0
- data/templates/cli/syncers/rsync_pull +28 -0
- data/templates/cli/syncers/rsync_push +28 -0
- data/templates/cli/syncers/s3 +27 -0
- data/templates/general/links +3 -0
- data/templates/general/version.erb +2 -0
- data/templates/notifier/mail/failure.erb +16 -0
- data/templates/notifier/mail/success.erb +16 -0
- data/templates/notifier/mail/warning.erb +16 -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 +1122 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Compressor
|
|
5
|
+
class Base
|
|
6
|
+
include Utilities::Helpers
|
|
7
|
+
include Config::Helpers
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Yields to the block the compressor command and filename extension.
|
|
11
|
+
def compress_with
|
|
12
|
+
log!
|
|
13
|
+
yield @cmd, @ext
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Return the compressor name, with Backup namespace removed
|
|
20
|
+
def compressor_name
|
|
21
|
+
self.class.to_s.sub('Backup::', '')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
##
|
|
25
|
+
# Logs a message to the console and log file to inform
|
|
26
|
+
# the client that Backup is using the compressor
|
|
27
|
+
def log!
|
|
28
|
+
Logger.info "Using #{ compressor_name } for compression.\n" +
|
|
29
|
+
" Command: '#{ @cmd }'\n" +
|
|
30
|
+
" Ext: '#{ @ext }'"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Compressor
|
|
5
|
+
class Bzip2 < Base
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Specify the level of compression to use.
|
|
9
|
+
#
|
|
10
|
+
# Values should be a single digit from 1 to 9.
|
|
11
|
+
# Note that setting the level to either extreme may or may not
|
|
12
|
+
# give the desired result. Be sure to check the documentation
|
|
13
|
+
# for the compressor being used.
|
|
14
|
+
#
|
|
15
|
+
# The default `level` is 9.
|
|
16
|
+
attr_accessor :level
|
|
17
|
+
|
|
18
|
+
##
|
|
19
|
+
# Creates a new instance of Backup::Compressor::Bzip2
|
|
20
|
+
def initialize(&block)
|
|
21
|
+
load_defaults!
|
|
22
|
+
|
|
23
|
+
@level ||= false
|
|
24
|
+
|
|
25
|
+
instance_eval(&block) if block_given?
|
|
26
|
+
|
|
27
|
+
@cmd = "#{ utility(:bzip2) }#{ options }"
|
|
28
|
+
@ext = '.bz2'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def options
|
|
34
|
+
" -#{ @level }" if @level
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Compressor
|
|
5
|
+
class Custom < Base
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Specify the system command to invoke a compressor,
|
|
9
|
+
# including any command-line arguments.
|
|
10
|
+
# e.g. @compressor.command = 'pbzip2 -p2 -4'
|
|
11
|
+
#
|
|
12
|
+
# The data to be compressed will be piped to the command's STDIN,
|
|
13
|
+
# and it should write the compressed data to STDOUT.
|
|
14
|
+
# i.e. `cat file.tar | %command% > file.tar.%extension%`
|
|
15
|
+
attr_accessor :command
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# File extension to append to the compressed file's filename.
|
|
19
|
+
# e.g. @compressor.extension = '.bz2'
|
|
20
|
+
attr_accessor :extension
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Initializes a new custom compressor.
|
|
24
|
+
def initialize(&block)
|
|
25
|
+
load_defaults!
|
|
26
|
+
|
|
27
|
+
instance_eval(&block) if block_given?
|
|
28
|
+
|
|
29
|
+
@cmd = set_cmd
|
|
30
|
+
@ext = set_ext
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# Return the command line using the full path.
|
|
37
|
+
# Ensures the command exists and is executable.
|
|
38
|
+
def set_cmd
|
|
39
|
+
parts = @command.to_s.split(' ')
|
|
40
|
+
parts[0] = utility(parts[0])
|
|
41
|
+
parts.join(' ')
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Return the extension given without whitespace.
|
|
46
|
+
# If extension was not set, return an empty string
|
|
47
|
+
def set_ext
|
|
48
|
+
@extension.to_s.strip
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Compressor
|
|
5
|
+
class Gzip < Base
|
|
6
|
+
class Error < Backup::Error; end
|
|
7
|
+
extend Utilities::Helpers
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Specify the level of compression to use.
|
|
11
|
+
#
|
|
12
|
+
# Values should be a single digit from 1 to 9.
|
|
13
|
+
# Note that setting the level to either extreme may or may not
|
|
14
|
+
# give the desired result. Be sure to check the documentation
|
|
15
|
+
# for the compressor being used.
|
|
16
|
+
#
|
|
17
|
+
# The default `level` is 6.
|
|
18
|
+
attr_accessor :level
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Use the `--rsyncable` option with `gzip`.
|
|
22
|
+
#
|
|
23
|
+
# This option directs `gzip` to compress data using an algorithm that
|
|
24
|
+
# allows `rsync` to efficiently detect changes. This is especially useful
|
|
25
|
+
# when used to compress `Archive` or `Database` backups that will be
|
|
26
|
+
# stored using Backup's `RSync` Storage option.
|
|
27
|
+
#
|
|
28
|
+
# The `--rsyncable` option is only available on patched versions of `gzip`.
|
|
29
|
+
# While most distributions apply this patch, this option may not be
|
|
30
|
+
# available on your system. If it's not available, Backup will log a
|
|
31
|
+
# warning and continue to use the compressor without this option.
|
|
32
|
+
attr_accessor :rsyncable
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Determine if +--rsyncable+ is supported and cache the result.
|
|
36
|
+
def self.has_rsyncable?
|
|
37
|
+
return @has_rsyncable unless @has_rsyncable.nil?
|
|
38
|
+
cmd = "#{ utility(:gzip) } --rsyncable --version >/dev/null 2>&1; echo $?"
|
|
39
|
+
@has_rsyncable = %x[#{ cmd }].chomp == '0'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# Creates a new instance of Backup::Compressor::Gzip
|
|
44
|
+
def initialize(&block)
|
|
45
|
+
load_defaults!
|
|
46
|
+
|
|
47
|
+
@level ||= false
|
|
48
|
+
@rsyncable ||= false
|
|
49
|
+
|
|
50
|
+
instance_eval(&block) if block_given?
|
|
51
|
+
|
|
52
|
+
@cmd = "#{ utility(:gzip) }#{ options }"
|
|
53
|
+
@ext = '.gz'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def options
|
|
59
|
+
opts = ''
|
|
60
|
+
opts << " -#{ @level }" if @level
|
|
61
|
+
if self.class.has_rsyncable?
|
|
62
|
+
opts << ' --rsyncable'
|
|
63
|
+
else
|
|
64
|
+
Logger.warn Error.new(<<-EOS)
|
|
65
|
+
'rsyncable' option ignored.
|
|
66
|
+
Your system's 'gzip' does not support the `--rsyncable` option.
|
|
67
|
+
EOS
|
|
68
|
+
end if @rsyncable
|
|
69
|
+
opts
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'backup/config/dsl'
|
|
3
|
+
require 'backup/config/helpers'
|
|
4
|
+
|
|
5
|
+
module Backup
|
|
6
|
+
module Config
|
|
7
|
+
class Error < Backup::Error; end
|
|
8
|
+
|
|
9
|
+
DEFAULTS = {
|
|
10
|
+
:config_file => 'config.rb',
|
|
11
|
+
:data_path => '.data',
|
|
12
|
+
:tmp_path => '.tmp'
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
include Utilities::Helpers
|
|
17
|
+
|
|
18
|
+
attr_reader :user, :root_path, :config_file, :data_path, :tmp_path
|
|
19
|
+
|
|
20
|
+
# Loads the user's +config.rb+ and all model files.
|
|
21
|
+
def load(options = {})
|
|
22
|
+
update(options) # from the command line
|
|
23
|
+
|
|
24
|
+
unless File.exist?(config_file)
|
|
25
|
+
raise Error, "Could not find configuration file: '#{config_file}'."
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
config = File.read(config_file)
|
|
29
|
+
version = Backup::VERSION.split('.').first
|
|
30
|
+
unless config =~ /^# Backup v#{ version }\.x Configuration$/
|
|
31
|
+
raise Error, <<-EOS
|
|
32
|
+
Invalid Configuration File
|
|
33
|
+
The configuration file at '#{ config_file }'
|
|
34
|
+
does not appear to be a Backup v#{ version }.x configuration file.
|
|
35
|
+
If you have upgraded to v#{ version }.x from a previous version,
|
|
36
|
+
you need to upgrade your configuration file.
|
|
37
|
+
Please see the instructions for upgrading in the Backup documentation.
|
|
38
|
+
EOS
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
dsl = DSL.new
|
|
42
|
+
|
|
43
|
+
dsl.instance_eval(config, config_file)
|
|
44
|
+
|
|
45
|
+
update(dsl._config_options) # from config.rb
|
|
46
|
+
update(options) # command line takes precedence
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Dir[File.join(File.dirname(config_file), 'models', '*.rb')].each do |model|
|
|
50
|
+
dsl.instance_eval(File.read(model), model)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def hostname
|
|
55
|
+
@hostname ||= run(utility(:hostname))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# If :root_path is set in the options, all paths will be updated.
|
|
61
|
+
# Otherwise, only the paths given will be updated.
|
|
62
|
+
def update(options = {})
|
|
63
|
+
root_path = options[:root_path].to_s.strip
|
|
64
|
+
new_root = root_path.empty? ? false : set_root_path(root_path)
|
|
65
|
+
|
|
66
|
+
DEFAULTS.each do |name, ending|
|
|
67
|
+
set_path_variable(name, options[name], ending, new_root)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Sets the @root_path to the given +path+ and returns it.
|
|
72
|
+
# Raises an error if the given +path+ does not exist.
|
|
73
|
+
def set_root_path(path)
|
|
74
|
+
# allows #reset! to set the default @root_path,
|
|
75
|
+
# then use #update to set all other paths,
|
|
76
|
+
# without requiring that @root_path exist.
|
|
77
|
+
return @root_path if path == @root_path
|
|
78
|
+
|
|
79
|
+
path = File.expand_path(path)
|
|
80
|
+
unless File.directory?(path)
|
|
81
|
+
raise Error, <<-EOS
|
|
82
|
+
Root Path Not Found
|
|
83
|
+
When specifying a --root-path, the path must exist.
|
|
84
|
+
Path was: #{ path }
|
|
85
|
+
EOS
|
|
86
|
+
end
|
|
87
|
+
@root_path = path
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def set_path_variable(name, path, ending, root_path)
|
|
91
|
+
# strip any trailing '/' in case the user supplied this as part of
|
|
92
|
+
# an absolute path, so we can match it against File.expand_path()
|
|
93
|
+
path = path.to_s.sub(/\/\s*$/, '').lstrip
|
|
94
|
+
new_path = false
|
|
95
|
+
# If no path is given, the variable will not be set/updated
|
|
96
|
+
# unless a root_path was given. In which case the value will
|
|
97
|
+
# be updated with our default ending.
|
|
98
|
+
if path.empty?
|
|
99
|
+
new_path = File.join(root_path, ending) if root_path
|
|
100
|
+
else
|
|
101
|
+
# When a path is given, the variable will be set/updated.
|
|
102
|
+
# If the path is relative, it will be joined with root_path (if given),
|
|
103
|
+
# or expanded relative to PWD.
|
|
104
|
+
new_path = File.expand_path(path)
|
|
105
|
+
unless path == new_path
|
|
106
|
+
new_path = File.join(root_path, path) if root_path
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
instance_variable_set(:"@#{name}", new_path) if new_path
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def reset!
|
|
113
|
+
@user = ENV['USER'] || Etc.getpwuid.name
|
|
114
|
+
@root_path = File.join(File.expand_path(ENV['HOME'] || ''), 'Backup')
|
|
115
|
+
update(:root_path => @root_path)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
reset! # set defaults on load
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Config
|
|
5
|
+
# Context for loading user config.rb and model files.
|
|
6
|
+
class DSL
|
|
7
|
+
class Error < Backup::Error; end
|
|
8
|
+
Model = Backup::Model
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
# List the available database, storage, syncer, compressor, encryptor
|
|
14
|
+
# and notifier constants. These are used to define constant names within
|
|
15
|
+
# Backup::Config::DSL so that users may use a constant instead of a string.
|
|
16
|
+
# Nested namespaces are represented using Hashs. Deep nesting supported.
|
|
17
|
+
#
|
|
18
|
+
# Example, instead of:
|
|
19
|
+
# database "MySQL" do |mysql|
|
|
20
|
+
# sync_with "RSync::Local" do |rsync|
|
|
21
|
+
#
|
|
22
|
+
# You can do:
|
|
23
|
+
# database MySQL do |mysql|
|
|
24
|
+
# sync_with RSync::Local do |rsync|
|
|
25
|
+
#
|
|
26
|
+
def add_dsl_constants
|
|
27
|
+
create_modules(
|
|
28
|
+
DSL,
|
|
29
|
+
[ # Databases
|
|
30
|
+
['MySQL', 'PostgreSQL', 'MongoDB', 'Redis', 'Riak', 'OpenLDAP', 'SQLite',
|
|
31
|
+
'RemoteMySQL'
|
|
32
|
+
],
|
|
33
|
+
|
|
34
|
+
# Storages
|
|
35
|
+
['S3', 'CloudFiles', 'Ninefold', 'Dropbox', 'FTP',
|
|
36
|
+
'SFTP', 'SCP', 'RSync', 'Local', 'Qiniu'],
|
|
37
|
+
# Compressors
|
|
38
|
+
['Gzip', 'Bzip2', 'Custom', 'Pbzip2', 'Lzma'],
|
|
39
|
+
# Encryptors
|
|
40
|
+
['OpenSSL', 'GPG'],
|
|
41
|
+
# Syncers
|
|
42
|
+
[
|
|
43
|
+
{ 'Cloud' => ['CloudFiles', 'S3'] },
|
|
44
|
+
{ 'RSync' => ['Push', 'Pull', 'Local'] }
|
|
45
|
+
],
|
|
46
|
+
# Notifiers
|
|
47
|
+
['Mail', 'Twitter', 'Campfire', 'Prowl',
|
|
48
|
+
'Hipchat', 'PagerDuty', 'Pushover', 'HttpPost', 'Nagios',
|
|
49
|
+
'Slack', 'FlowDock', 'Zabbix', 'Ses', 'DataDog', 'Command']
|
|
50
|
+
]
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def create_modules(scope, names)
|
|
55
|
+
names.flatten.each do |name|
|
|
56
|
+
if name.is_a?(Hash)
|
|
57
|
+
name.each do |key, val|
|
|
58
|
+
create_modules(get_or_create_empty_module(scope, key), [val])
|
|
59
|
+
end
|
|
60
|
+
else
|
|
61
|
+
get_or_create_empty_module(scope, name)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def get_or_create_empty_module(scope, const)
|
|
67
|
+
if scope.const_defined?(const)
|
|
68
|
+
scope.const_get(const)
|
|
69
|
+
else
|
|
70
|
+
scope.const_set(const, Module.new)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
add_dsl_constants # add constants on load
|
|
76
|
+
|
|
77
|
+
attr_reader :_config_options
|
|
78
|
+
|
|
79
|
+
def initialize
|
|
80
|
+
@_config_options = {}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Allow users to set command line path options in config.rb
|
|
84
|
+
[:root_path, :data_path, :tmp_path].each do |name|
|
|
85
|
+
define_method name, lambda {|path| _config_options[name] = path }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Allows users to create preconfigured models.
|
|
89
|
+
def preconfigure(name, &block)
|
|
90
|
+
unless name.is_a?(String) && name =~ /^[A-Z]/
|
|
91
|
+
raise Error, "Preconfigured model names must be given as a string " +
|
|
92
|
+
"and start with a capital letter."
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if DSL.const_defined?(name)
|
|
96
|
+
raise Error, "'#{ name }' is already in use " +
|
|
97
|
+
"and can not be used for a preconfigured model."
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
DSL.const_set(name, Class.new(Model))
|
|
101
|
+
DSL.const_get(name).preconfigure(&block)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require 'ostruct'
|
|
3
|
+
|
|
4
|
+
module Backup
|
|
5
|
+
module Config
|
|
6
|
+
module Helpers
|
|
7
|
+
|
|
8
|
+
def self.included(klass)
|
|
9
|
+
klass.extend ClassMethods
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
|
|
14
|
+
def defaults
|
|
15
|
+
@defaults ||= Config::Defaults.new
|
|
16
|
+
|
|
17
|
+
if block_given?
|
|
18
|
+
yield @defaults
|
|
19
|
+
else
|
|
20
|
+
@defaults
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Used only within the specs
|
|
25
|
+
def clear_defaults!
|
|
26
|
+
defaults.reset!
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def deprecations
|
|
30
|
+
@deprecations ||= {}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def log_deprecation_warning(name, deprecation)
|
|
34
|
+
msg = "#{ self }##{ name } has been deprecated as of " +
|
|
35
|
+
"backup v.#{ deprecation[:version] }"
|
|
36
|
+
msg << "\n#{ deprecation[:message] }" if deprecation[:message]
|
|
37
|
+
Logger.warn Config::Error.new(<<-EOS)
|
|
38
|
+
[DEPRECATION WARNING]
|
|
39
|
+
#{ msg }
|
|
40
|
+
EOS
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
protected
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Method to deprecate an attribute.
|
|
47
|
+
#
|
|
48
|
+
# :version
|
|
49
|
+
# Must be set to the backup version which will first
|
|
50
|
+
# introduce the deprecation.
|
|
51
|
+
#
|
|
52
|
+
# :action
|
|
53
|
+
# If set, this Proc will be called with a reference to the
|
|
54
|
+
# class instance and the value set on the deprecated accessor.
|
|
55
|
+
# e.g. deprecation[:action].call(klass, value)
|
|
56
|
+
# This should perform whatever action is neccessary, such as
|
|
57
|
+
# transferring the value to a new accessor.
|
|
58
|
+
#
|
|
59
|
+
# :message
|
|
60
|
+
# If set, this will be appended to #log_deprecation_warning
|
|
61
|
+
#
|
|
62
|
+
# Note that this replaces the `attr_accessor` method, or other
|
|
63
|
+
# method previously used to set the accessor being deprecated.
|
|
64
|
+
# #method_missing will handle any calls to `name=`.
|
|
65
|
+
#
|
|
66
|
+
def attr_deprecate(name, args = {})
|
|
67
|
+
deprecations[name] = {
|
|
68
|
+
:version => nil,
|
|
69
|
+
:message => nil,
|
|
70
|
+
:action => nil
|
|
71
|
+
}.merge(args)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end # ClassMethods
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
##
|
|
79
|
+
# Sets any pre-configured default values.
|
|
80
|
+
# If a default value was set for an invalid accessor,
|
|
81
|
+
# this will raise a NameError.
|
|
82
|
+
def load_defaults!
|
|
83
|
+
self.class.defaults._attributes.each do |name|
|
|
84
|
+
val = self.class.defaults.send(name)
|
|
85
|
+
val = val.dup rescue val
|
|
86
|
+
send(:"#{ name }=", val)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
##
|
|
91
|
+
# Check missing methods for deprecated attribute accessors.
|
|
92
|
+
#
|
|
93
|
+
# If a value is set on an accessor that has been deprecated
|
|
94
|
+
# using #attr_deprecate, a warning will be issued and any
|
|
95
|
+
# :action (Proc) specified will be called with a reference to
|
|
96
|
+
# the class instance and the value set on the deprecated accessor.
|
|
97
|
+
# See #attr_deprecate and #log_deprecation_warning
|
|
98
|
+
#
|
|
99
|
+
# Note that OpenStruct (used for setting defaults) does not allow
|
|
100
|
+
# multiple arguments when assigning values for members.
|
|
101
|
+
# So, we won't allow it here either, even though an attr_accessor
|
|
102
|
+
# will accept and convert them into an Array. Therefore, setting
|
|
103
|
+
# an option value using multiple values, whether as a default or
|
|
104
|
+
# directly on the class' accessor, should not be supported.
|
|
105
|
+
# i.e. if an option will accept being set as an Array, then it
|
|
106
|
+
# should be explicitly set as such. e.g. option = [val1, val2]
|
|
107
|
+
#
|
|
108
|
+
def method_missing(name, *args)
|
|
109
|
+
deprecation = nil
|
|
110
|
+
if method = name.to_s.chomp!('=')
|
|
111
|
+
if (len = args.count) != 1
|
|
112
|
+
raise ArgumentError,
|
|
113
|
+
"wrong number of arguments (#{ len } for 1)", caller(1)
|
|
114
|
+
end
|
|
115
|
+
deprecation = self.class.deprecations[method.to_sym]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if deprecation
|
|
119
|
+
self.class.log_deprecation_warning(method, deprecation)
|
|
120
|
+
deprecation[:action].call(self, args[0]) if deprecation[:action]
|
|
121
|
+
else
|
|
122
|
+
super
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end # Helpers
|
|
127
|
+
|
|
128
|
+
# Store for pre-configured defaults.
|
|
129
|
+
class Defaults < OpenStruct
|
|
130
|
+
# Returns an Array of all attribute method names
|
|
131
|
+
# that default values were set for.
|
|
132
|
+
def _attributes
|
|
133
|
+
@table.keys
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Used only within the specs
|
|
137
|
+
def reset!
|
|
138
|
+
@table.clear
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
143
|
+
end
|