backup_checksum 3.0.23
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 +7 -0
- data/.travis.yml +10 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +130 -0
- data/Guardfile +21 -0
- data/LICENSE.md +24 -0
- data/README.md +476 -0
- data/backup_checksum.gemspec +32 -0
- data/bin/backup +11 -0
- data/lib/backup.rb +217 -0
- data/lib/backup/archive.rb +117 -0
- data/lib/backup/binder.rb +22 -0
- data/lib/backup/checksum/base.rb +44 -0
- data/lib/backup/checksum/shasum.rb +16 -0
- data/lib/backup/cleaner.rb +121 -0
- data/lib/backup/cli/helpers.rb +88 -0
- data/lib/backup/cli/utility.rb +247 -0
- data/lib/backup/compressor/base.rb +29 -0
- data/lib/backup/compressor/bzip2.rb +50 -0
- data/lib/backup/compressor/gzip.rb +47 -0
- data/lib/backup/compressor/lzma.rb +50 -0
- data/lib/backup/compressor/pbzip2.rb +56 -0
- data/lib/backup/config.rb +173 -0
- data/lib/backup/configuration/base.rb +15 -0
- data/lib/backup/configuration/checksum/base.rb +9 -0
- data/lib/backup/configuration/checksum/shasum.rb +9 -0
- data/lib/backup/configuration/compressor/base.rb +9 -0
- data/lib/backup/configuration/compressor/bzip2.rb +23 -0
- data/lib/backup/configuration/compressor/gzip.rb +23 -0
- data/lib/backup/configuration/compressor/lzma.rb +23 -0
- data/lib/backup/configuration/compressor/pbzip2.rb +28 -0
- data/lib/backup/configuration/database/base.rb +19 -0
- data/lib/backup/configuration/database/mongodb.rb +49 -0
- data/lib/backup/configuration/database/mysql.rb +42 -0
- data/lib/backup/configuration/database/postgresql.rb +41 -0
- data/lib/backup/configuration/database/redis.rb +39 -0
- data/lib/backup/configuration/database/riak.rb +29 -0
- data/lib/backup/configuration/encryptor/base.rb +9 -0
- data/lib/backup/configuration/encryptor/gpg.rb +17 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +32 -0
- data/lib/backup/configuration/helpers.rb +52 -0
- data/lib/backup/configuration/notifier/base.rb +28 -0
- data/lib/backup/configuration/notifier/campfire.rb +25 -0
- data/lib/backup/configuration/notifier/hipchat.rb +41 -0
- data/lib/backup/configuration/notifier/mail.rb +112 -0
- data/lib/backup/configuration/notifier/presently.rb +25 -0
- data/lib/backup/configuration/notifier/prowl.rb +23 -0
- data/lib/backup/configuration/notifier/twitter.rb +21 -0
- data/lib/backup/configuration/storage/base.rb +18 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +25 -0
- data/lib/backup/configuration/storage/dropbox.rb +58 -0
- data/lib/backup/configuration/storage/ftp.rb +29 -0
- data/lib/backup/configuration/storage/local.rb +17 -0
- data/lib/backup/configuration/storage/ninefold.rb +20 -0
- data/lib/backup/configuration/storage/rsync.rb +29 -0
- data/lib/backup/configuration/storage/s3.rb +25 -0
- data/lib/backup/configuration/storage/scp.rb +25 -0
- data/lib/backup/configuration/storage/sftp.rb +25 -0
- data/lib/backup/configuration/syncer/base.rb +10 -0
- data/lib/backup/configuration/syncer/cloud.rb +23 -0
- data/lib/backup/configuration/syncer/cloud_files.rb +30 -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 +23 -0
- data/lib/backup/database/base.rb +59 -0
- data/lib/backup/database/mongodb.rb +232 -0
- data/lib/backup/database/mysql.rb +163 -0
- data/lib/backup/database/postgresql.rb +146 -0
- data/lib/backup/database/redis.rb +139 -0
- data/lib/backup/database/riak.rb +69 -0
- data/lib/backup/dependency.rb +114 -0
- data/lib/backup/encryptor/base.rb +29 -0
- data/lib/backup/encryptor/gpg.rb +80 -0
- data/lib/backup/encryptor/open_ssl.rb +72 -0
- data/lib/backup/errors.rb +124 -0
- data/lib/backup/logger.rb +152 -0
- data/lib/backup/model.rb +386 -0
- data/lib/backup/notifier/base.rb +81 -0
- data/lib/backup/notifier/campfire.rb +168 -0
- data/lib/backup/notifier/hipchat.rb +99 -0
- data/lib/backup/notifier/mail.rb +206 -0
- data/lib/backup/notifier/presently.rb +88 -0
- data/lib/backup/notifier/prowl.rb +65 -0
- data/lib/backup/notifier/twitter.rb +70 -0
- data/lib/backup/package.rb +51 -0
- data/lib/backup/packager.rb +108 -0
- data/lib/backup/pipeline.rb +107 -0
- data/lib/backup/splitter.rb +75 -0
- data/lib/backup/storage/base.rb +119 -0
- data/lib/backup/storage/cloudfiles.rb +87 -0
- data/lib/backup/storage/cycler.rb +117 -0
- data/lib/backup/storage/dropbox.rb +181 -0
- data/lib/backup/storage/ftp.rb +119 -0
- data/lib/backup/storage/local.rb +82 -0
- data/lib/backup/storage/ninefold.rb +116 -0
- data/lib/backup/storage/rsync.rb +149 -0
- data/lib/backup/storage/s3.rb +94 -0
- data/lib/backup/storage/scp.rb +99 -0
- data/lib/backup/storage/sftp.rb +108 -0
- data/lib/backup/syncer/base.rb +42 -0
- data/lib/backup/syncer/cloud.rb +190 -0
- data/lib/backup/syncer/cloud_files.rb +56 -0
- data/lib/backup/syncer/rsync/base.rb +52 -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 +47 -0
- data/lib/backup/template.rb +46 -0
- data/lib/backup/version.rb +43 -0
- data/spec/archive_spec.rb +335 -0
- data/spec/cleaner_spec.rb +304 -0
- data/spec/cli/helpers_spec.rb +176 -0
- data/spec/cli/utility_spec.rb +363 -0
- data/spec/compressor/base_spec.rb +31 -0
- data/spec/compressor/bzip2_spec.rb +83 -0
- data/spec/compressor/gzip_spec.rb +83 -0
- data/spec/compressor/lzma_spec.rb +83 -0
- data/spec/compressor/pbzip2_spec.rb +124 -0
- data/spec/config_spec.rb +321 -0
- data/spec/configuration/base_spec.rb +35 -0
- data/spec/configuration/compressor/bzip2_spec.rb +29 -0
- data/spec/configuration/compressor/gzip_spec.rb +29 -0
- data/spec/configuration/compressor/lzma_spec.rb +29 -0
- data/spec/configuration/compressor/pbzip2_spec.rb +32 -0
- data/spec/configuration/database/base_spec.rb +17 -0
- data/spec/configuration/database/mongodb_spec.rb +56 -0
- data/spec/configuration/database/mysql_spec.rb +53 -0
- data/spec/configuration/database/postgresql_spec.rb +53 -0
- data/spec/configuration/database/redis_spec.rb +50 -0
- data/spec/configuration/database/riak_spec.rb +35 -0
- data/spec/configuration/encryptor/gpg_spec.rb +26 -0
- data/spec/configuration/encryptor/open_ssl_spec.rb +35 -0
- data/spec/configuration/notifier/base_spec.rb +32 -0
- data/spec/configuration/notifier/campfire_spec.rb +32 -0
- data/spec/configuration/notifier/hipchat_spec.rb +44 -0
- data/spec/configuration/notifier/mail_spec.rb +71 -0
- data/spec/configuration/notifier/presently_spec.rb +35 -0
- data/spec/configuration/notifier/prowl_spec.rb +29 -0
- data/spec/configuration/notifier/twitter_spec.rb +35 -0
- data/spec/configuration/storage/cloudfiles_spec.rb +41 -0
- data/spec/configuration/storage/dropbox_spec.rb +38 -0
- data/spec/configuration/storage/ftp_spec.rb +44 -0
- data/spec/configuration/storage/local_spec.rb +29 -0
- data/spec/configuration/storage/ninefold_spec.rb +32 -0
- data/spec/configuration/storage/rsync_spec.rb +41 -0
- data/spec/configuration/storage/s3_spec.rb +38 -0
- data/spec/configuration/storage/scp_spec.rb +41 -0
- data/spec/configuration/storage/sftp_spec.rb +41 -0
- data/spec/configuration/syncer/cloud_files_spec.rb +44 -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/push_spec.rb +43 -0
- data/spec/configuration/syncer/s3_spec.rb +38 -0
- data/spec/database/base_spec.rb +54 -0
- data/spec/database/mongodb_spec.rb +428 -0
- data/spec/database/mysql_spec.rb +335 -0
- data/spec/database/postgresql_spec.rb +278 -0
- data/spec/database/redis_spec.rb +260 -0
- data/spec/database/riak_spec.rb +108 -0
- data/spec/dependency_spec.rb +49 -0
- data/spec/encryptor/base_spec.rb +30 -0
- data/spec/encryptor/gpg_spec.rb +134 -0
- data/spec/encryptor/open_ssl_spec.rb +129 -0
- data/spec/errors_spec.rb +306 -0
- data/spec/logger_spec.rb +363 -0
- data/spec/model_spec.rb +649 -0
- data/spec/notifier/base_spec.rb +89 -0
- data/spec/notifier/campfire_spec.rb +199 -0
- data/spec/notifier/hipchat_spec.rb +188 -0
- data/spec/notifier/mail_spec.rb +280 -0
- data/spec/notifier/presently_spec.rb +181 -0
- data/spec/notifier/prowl_spec.rb +117 -0
- data/spec/notifier/twitter_spec.rb +132 -0
- data/spec/package_spec.rb +61 -0
- data/spec/packager_spec.rb +225 -0
- data/spec/pipeline_spec.rb +257 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/splitter_spec.rb +120 -0
- data/spec/storage/base_spec.rb +160 -0
- data/spec/storage/cloudfiles_spec.rb +230 -0
- data/spec/storage/cycler_spec.rb +239 -0
- data/spec/storage/dropbox_spec.rb +370 -0
- data/spec/storage/ftp_spec.rb +247 -0
- data/spec/storage/local_spec.rb +235 -0
- data/spec/storage/ninefold_spec.rb +319 -0
- data/spec/storage/rsync_spec.rb +345 -0
- data/spec/storage/s3_spec.rb +221 -0
- data/spec/storage/scp_spec.rb +209 -0
- data/spec/storage/sftp_spec.rb +220 -0
- data/spec/syncer/base_spec.rb +22 -0
- data/spec/syncer/cloud_files_spec.rb +192 -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 +192 -0
- data/spec/version_spec.rb +21 -0
- data/templates/cli/utility/archive +25 -0
- data/templates/cli/utility/compressor/bzip2 +7 -0
- data/templates/cli/utility/compressor/gzip +7 -0
- data/templates/cli/utility/compressor/lzma +7 -0
- data/templates/cli/utility/compressor/pbzip2 +7 -0
- data/templates/cli/utility/config +31 -0
- data/templates/cli/utility/database/mongodb +18 -0
- data/templates/cli/utility/database/mysql +21 -0
- data/templates/cli/utility/database/postgresql +17 -0
- data/templates/cli/utility/database/redis +16 -0
- data/templates/cli/utility/database/riak +11 -0
- data/templates/cli/utility/encryptor/gpg +12 -0
- data/templates/cli/utility/encryptor/openssl +9 -0
- data/templates/cli/utility/model.erb +23 -0
- data/templates/cli/utility/notifier/campfire +12 -0
- data/templates/cli/utility/notifier/hipchat +15 -0
- data/templates/cli/utility/notifier/mail +22 -0
- data/templates/cli/utility/notifier/presently +13 -0
- data/templates/cli/utility/notifier/prowl +11 -0
- data/templates/cli/utility/notifier/twitter +13 -0
- data/templates/cli/utility/splitter +7 -0
- data/templates/cli/utility/storage/cloud_files +22 -0
- data/templates/cli/utility/storage/dropbox +20 -0
- data/templates/cli/utility/storage/ftp +12 -0
- data/templates/cli/utility/storage/local +7 -0
- data/templates/cli/utility/storage/ninefold +9 -0
- data/templates/cli/utility/storage/rsync +11 -0
- data/templates/cli/utility/storage/s3 +19 -0
- data/templates/cli/utility/storage/scp +11 -0
- data/templates/cli/utility/storage/sftp +11 -0
- data/templates/cli/utility/syncer/cloud_files +48 -0
- data/templates/cli/utility/syncer/rsync_local +12 -0
- data/templates/cli/utility/syncer/rsync_pull +17 -0
- data/templates/cli/utility/syncer/rsync_push +17 -0
- data/templates/cli/utility/syncer/s3 +45 -0
- 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 +311 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Cleaner
|
|
5
|
+
class << self
|
|
6
|
+
|
|
7
|
+
##
|
|
8
|
+
# Logs warnings if any temporary files still exist
|
|
9
|
+
# from the last time this model/trigger was run,
|
|
10
|
+
# then removes the files.
|
|
11
|
+
def prepare(model)
|
|
12
|
+
@model = model
|
|
13
|
+
|
|
14
|
+
messages = []
|
|
15
|
+
if packaging_folder_dirty?
|
|
16
|
+
messages << <<-EOS
|
|
17
|
+
The temporary backup folder still contains files!
|
|
18
|
+
'#{ File.join(Config.tmp_path, @model.trigger) }'
|
|
19
|
+
These files will now be removed.
|
|
20
|
+
EOS
|
|
21
|
+
FileUtils.rm_rf(File.join(Config.tmp_path, @model.trigger))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
package_files = tmp_path_package_files
|
|
25
|
+
unless package_files.empty?
|
|
26
|
+
# the chances that tmp_path would be dirty
|
|
27
|
+
# AND package files exist are practically nil
|
|
28
|
+
messages << ('-' * 74) unless messages.empty?
|
|
29
|
+
|
|
30
|
+
messages << <<-EOS
|
|
31
|
+
The temporary backup folder '#{ Config.tmp_path }'
|
|
32
|
+
appears to contain the package files from the previous backup!
|
|
33
|
+
#{ package_files.join("\n") }
|
|
34
|
+
These files will now be removed.
|
|
35
|
+
EOS
|
|
36
|
+
package_files.each {|file| FileUtils.rm_f(file) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
unless messages.empty?
|
|
40
|
+
Logger.warn Errors::CleanerError.new(<<-EOS)
|
|
41
|
+
Cleanup Warning
|
|
42
|
+
#{ messages.join("\n") }
|
|
43
|
+
Please check the log for messages and/or your notifications
|
|
44
|
+
concerning this backup: '#{ @model.label } (#{ @model.trigger })'
|
|
45
|
+
The temporary files which had to be removed should not have existed.
|
|
46
|
+
EOS
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Remove the temporary folder used during packaging
|
|
52
|
+
def remove_packaging(model)
|
|
53
|
+
Logger.message "Cleaning up the temporary files..."
|
|
54
|
+
FileUtils.rm_rf(File.join(Config.tmp_path, model.trigger))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
# Remove the final package files from tmp_path
|
|
59
|
+
# Note: 'force' is used, since a Local Storage may *move* these files.
|
|
60
|
+
def remove_package(package)
|
|
61
|
+
Logger.message "Cleaning up the package files..."
|
|
62
|
+
package.filenames.each do |file|
|
|
63
|
+
FileUtils.rm_f(File.join(Config.tmp_path, file))
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
##
|
|
68
|
+
# Logs warnings if any temporary files still exist
|
|
69
|
+
# when errors occur during the backup
|
|
70
|
+
def warnings(model)
|
|
71
|
+
@model = model
|
|
72
|
+
|
|
73
|
+
messages = []
|
|
74
|
+
if packaging_folder_dirty?
|
|
75
|
+
messages << <<-EOS
|
|
76
|
+
The temporary backup folder still contains files!
|
|
77
|
+
'#{ File.join(Config.tmp_path, @model.trigger) }'
|
|
78
|
+
This folder may contain completed Archives and/or Database backups.
|
|
79
|
+
EOS
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
package_files = tmp_path_package_files
|
|
83
|
+
unless package_files.empty?
|
|
84
|
+
# the chances that tmp_path would be dirty
|
|
85
|
+
# AND package files exist are practically nil
|
|
86
|
+
messages << ('-' * 74) unless messages.empty?
|
|
87
|
+
|
|
88
|
+
messages << <<-EOS
|
|
89
|
+
The temporary backup folder '#{ Config.tmp_path }'
|
|
90
|
+
appears to contain the backup files which were to be stored:
|
|
91
|
+
#{ package_files.join("\n") }
|
|
92
|
+
EOS
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
unless messages.empty?
|
|
96
|
+
Logger.warn Errors::CleanerError.new(<<-EOS)
|
|
97
|
+
Cleanup Warning
|
|
98
|
+
#{ messages.join("\n") }
|
|
99
|
+
Make sure you check these files before the next scheduled backup for
|
|
100
|
+
'#{ @model.label } (#{ @model.trigger })'
|
|
101
|
+
These files will be removed at that time!
|
|
102
|
+
EOS
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
private
|
|
107
|
+
|
|
108
|
+
def packaging_folder_dirty?
|
|
109
|
+
!Dir[File.join(Config.tmp_path, @model.trigger, '*')].empty?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def tmp_path_package_files
|
|
113
|
+
Dir[File.join(
|
|
114
|
+
Config.tmp_path,
|
|
115
|
+
"????.??.??.??.??.??.#{ @model.trigger }.tar{,[.-]*}"
|
|
116
|
+
)]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module CLI
|
|
5
|
+
module Helpers
|
|
6
|
+
UTILITY = {}
|
|
7
|
+
|
|
8
|
+
##
|
|
9
|
+
# Runs a given command in an isolated (sub) process using POpen4.
|
|
10
|
+
# The STDOUT, STDERR and the returned exit code of the utility will be stored in the process_data Hash.
|
|
11
|
+
#
|
|
12
|
+
# If a command returns an exit code other than 0, an exception will raise and the backup process will abort.
|
|
13
|
+
# Some utilities return exit codes other than 0 which aren't an issue in Backup's context. If this is the case,
|
|
14
|
+
# you can pass in an array of exit codes to ignore (whitelist), for example:
|
|
15
|
+
#
|
|
16
|
+
# run("tar -cf /output.tar /some/folder", :ignore_exit_codes => [1])
|
|
17
|
+
#
|
|
18
|
+
# So if the `tar` utility returns in this case 1, Backup will consider it an acceptable return code.
|
|
19
|
+
#
|
|
20
|
+
# Note: Exit code 0 is always automatically added to the :ignore_exit_codes array, regardless of whether you specify an
|
|
21
|
+
# array to ignore or not.
|
|
22
|
+
def run(command, options = {})
|
|
23
|
+
command.gsub!(/^\s+/, "")
|
|
24
|
+
|
|
25
|
+
process_data = Hash.new
|
|
26
|
+
pid, stdin, stdout, stderr = Open4::popen4(command)
|
|
27
|
+
ignored, process_data[:status] = Process::waitpid2(pid)
|
|
28
|
+
process_data[:stdout] = stdout.read
|
|
29
|
+
process_data[:stderr] = stderr.read
|
|
30
|
+
process_data[:ignore_exit_codes] = ((options[:ignore_exit_codes] || Array.new) << 0).uniq
|
|
31
|
+
|
|
32
|
+
raise_if_command_failed!(command_name(command), process_data)
|
|
33
|
+
process_data[:stdout]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Returns the full path to the specified utility.
|
|
38
|
+
# Raises an error if utility can not be found in the system's $PATH
|
|
39
|
+
def utility(name)
|
|
40
|
+
path = UTILITY[name] || %x[which #{name} 2>/dev/null].chomp
|
|
41
|
+
if path.empty?
|
|
42
|
+
raise Errors::CLI::UtilityNotFoundError, <<-EOS
|
|
43
|
+
Path to '#{ name }' could not be found.
|
|
44
|
+
Make sure the specified utility is installed
|
|
45
|
+
and available in your system's $PATH.
|
|
46
|
+
If this is a database utility, you may need to specify the full path
|
|
47
|
+
using the Database's '<utility_name>_utility' configuration setting.
|
|
48
|
+
EOS
|
|
49
|
+
end
|
|
50
|
+
UTILITY[name] = path
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Returns the name of the command name from the given command line
|
|
55
|
+
def command_name(command)
|
|
56
|
+
i = command =~ /\s/
|
|
57
|
+
command = command.slice(0, i) if i
|
|
58
|
+
command.split('/')[-1]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
##
|
|
62
|
+
# Inspects the exit code returned from the POpen4 child process. If the exit code isn't listed
|
|
63
|
+
# in the process_data[:ignore_exit_codes] array, an exception will be raised, aborting the backup process.
|
|
64
|
+
#
|
|
65
|
+
# Information regarding the error ( EXIT CODE and STDERR ) will be returned to the shell so the user can
|
|
66
|
+
# investigate the issue.
|
|
67
|
+
#
|
|
68
|
+
# raises Backup::Errors::CLI::SystemCallError
|
|
69
|
+
def raise_if_command_failed!(utility, process_data)
|
|
70
|
+
unless process_data[:ignore_exit_codes].include?(process_data[:status].to_i)
|
|
71
|
+
|
|
72
|
+
stderr = process_data[:stderr].empty? ?
|
|
73
|
+
nil : "STDERR:\n#{process_data[:stderr]}\n"
|
|
74
|
+
stdout = process_data[:stdout].empty? ?
|
|
75
|
+
nil : "STDOUT:\n#{process_data[:stdout]}\n"
|
|
76
|
+
|
|
77
|
+
raise Errors::CLI::SystemCallError, <<-EOS
|
|
78
|
+
Failed to run #{utility} on #{RUBY_PLATFORM}
|
|
79
|
+
The following information should help to determine the problem:
|
|
80
|
+
Exit Code: #{process_data[:status]}
|
|
81
|
+
#{stderr}#{stdout}
|
|
82
|
+
EOS
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Build the Backup Command Line Interface using Thor
|
|
5
|
+
module Backup
|
|
6
|
+
module CLI
|
|
7
|
+
class Utility < Thor
|
|
8
|
+
include Thor::Actions
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# [Perform]
|
|
12
|
+
# Performs the backup process. The only required option is the --trigger [-t].
|
|
13
|
+
# If the other options (--config-file, --data-path, --cache--path, --tmp-path) aren't specified
|
|
14
|
+
# they will fallback to the (good) defaults
|
|
15
|
+
#
|
|
16
|
+
# If --root-path is given, it will be used as the base path for our defaults,
|
|
17
|
+
# as well as the base path for any option specified as a relative path.
|
|
18
|
+
# Any option given as an absolute path will be used "as-is".
|
|
19
|
+
method_option :trigger, :type => :string, :required => true, :aliases => ['-t', '--triggers']
|
|
20
|
+
method_option :config_file, :type => :string, :default => '', :aliases => '-c'
|
|
21
|
+
method_option :root_path, :type => :string, :default => '', :aliases => '-r'
|
|
22
|
+
method_option :data_path, :type => :string, :default => '', :aliases => '-d'
|
|
23
|
+
method_option :log_path, :type => :string, :default => '', :aliases => '-l'
|
|
24
|
+
method_option :cache_path, :type => :string, :default => ''
|
|
25
|
+
method_option :tmp_path, :type => :string, :default => ''
|
|
26
|
+
method_option :quiet, :type => :boolean, :default => false, :aliases => '-q'
|
|
27
|
+
desc 'perform', "Performs the backup for the specified trigger.\n" +
|
|
28
|
+
"You may perform multiple backups by providing multiple triggers, separated by commas.\n\n" +
|
|
29
|
+
"Example:\n\s\s$ backup perform --triggers backup1,backup2,backup3,backup4\n\n" +
|
|
30
|
+
"This will invoke 4 backups, and they will run in the order specified (not asynchronous)."
|
|
31
|
+
def perform
|
|
32
|
+
##
|
|
33
|
+
# Silence Backup::Logger from printing to STDOUT, if --quiet was specified
|
|
34
|
+
Logger.quiet = options[:quiet]
|
|
35
|
+
|
|
36
|
+
##
|
|
37
|
+
# Update Config variables based on the given options
|
|
38
|
+
Config.update(options)
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Load the configuration file
|
|
42
|
+
Config.load_config!
|
|
43
|
+
|
|
44
|
+
##
|
|
45
|
+
# Ensure the :log_path, :cache_path and :tmp_path are created
|
|
46
|
+
# if they do not yet exist
|
|
47
|
+
[Config.log_path, Config.cache_path, Config.tmp_path].each do |path|
|
|
48
|
+
FileUtils.mkdir_p(path)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
##
|
|
52
|
+
# Truncate log file if needed
|
|
53
|
+
Logger.truncate!
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Prepare all trigger names by splitting them by ','
|
|
57
|
+
# and finding trigger names matching wildcard
|
|
58
|
+
triggers = options[:trigger].split(",")
|
|
59
|
+
triggers.map!(&:strip).map! {|t|
|
|
60
|
+
t.include?('*') ? Model.find_matching(t) : t
|
|
61
|
+
}.flatten!
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
# Process each trigger
|
|
65
|
+
triggers.each do |trigger|
|
|
66
|
+
##
|
|
67
|
+
# Find the model for this trigger
|
|
68
|
+
# Will raise an error if not found
|
|
69
|
+
model = Model.find(trigger)
|
|
70
|
+
|
|
71
|
+
##
|
|
72
|
+
# Prepare and Perform the backup
|
|
73
|
+
model.prepare!
|
|
74
|
+
model.perform!
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Clear the Log Messages for the next potential run
|
|
78
|
+
Logger.clear!
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
rescue => err
|
|
82
|
+
Logger.error Errors::CLIError.wrap(err)
|
|
83
|
+
exit(1)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
##
|
|
87
|
+
# [Generate:Model]
|
|
88
|
+
# Generates a model configuration file based on the arguments passed in.
|
|
89
|
+
# For example:
|
|
90
|
+
# $ backup generate:model --trigger my_backup --databases='mongodb'
|
|
91
|
+
# will generate a pre-populated model with a base MongoDB setup
|
|
92
|
+
desc 'generate:model', "Generates a Backup model file\n\n" +
|
|
93
|
+
"Note:\n" +
|
|
94
|
+
"\s\s'--config-path' is the path to the directory where 'config.rb' is located.\n" +
|
|
95
|
+
"\s\sThe model file will be created as '<config_path>/models/<trigger>.rb'\n" +
|
|
96
|
+
"\s\sDefault: #{Config.root_path}\n"
|
|
97
|
+
|
|
98
|
+
method_option :trigger, :type => :string, :required => true
|
|
99
|
+
method_option :config_path, :type => :string,
|
|
100
|
+
:desc => 'Path to your Backup configuration directory'
|
|
101
|
+
|
|
102
|
+
# options with their available values
|
|
103
|
+
%w{ databases storages syncers
|
|
104
|
+
encryptors compressors notifiers }.map(&:to_sym).each do |name|
|
|
105
|
+
path = File.join(Backup::TEMPLATE_PATH, 'cli', 'utility', name.to_s[0..-2])
|
|
106
|
+
method_option name, :type => :string, :desc =>
|
|
107
|
+
"(#{Dir[path + '/*'].sort.map {|p| File.basename(p) }.join(', ')})"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
method_option :archives, :type => :boolean
|
|
111
|
+
method_option :splitter, :type => :boolean, :default => true,
|
|
112
|
+
:desc => "use `--no-splitter` to disable"
|
|
113
|
+
|
|
114
|
+
define_method "generate:model" do
|
|
115
|
+
opts = options.merge(
|
|
116
|
+
:trigger => options[:trigger].gsub(/[\W\s]/, '_'),
|
|
117
|
+
:config_path => options[:config_path] ?
|
|
118
|
+
File.expand_path(options[:config_path]) : nil
|
|
119
|
+
)
|
|
120
|
+
config_path = opts[:config_path] || Config.root_path
|
|
121
|
+
models_path = File.join(config_path, "models")
|
|
122
|
+
config = File.join(config_path, "config.rb")
|
|
123
|
+
model = File.join(models_path, "#{opts[:trigger]}.rb")
|
|
124
|
+
|
|
125
|
+
FileUtils.mkdir_p(models_path)
|
|
126
|
+
if overwrite?(model)
|
|
127
|
+
File.open(model, 'w') do |file|
|
|
128
|
+
file.write(Backup::Template.new({:options => opts}).
|
|
129
|
+
result("cli/utility/model.erb"))
|
|
130
|
+
end
|
|
131
|
+
puts "Generated model file: '#{ model }'."
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
if not File.exist?(config)
|
|
135
|
+
File.open(config, "w") do |file|
|
|
136
|
+
file.write(Backup::Template.new.result("cli/utility/config"))
|
|
137
|
+
end
|
|
138
|
+
puts "Generated configuration file: '#{ config }'."
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
##
|
|
143
|
+
# [Generate:Config]
|
|
144
|
+
# Generates the main configuration file
|
|
145
|
+
desc 'generate:config', 'Generates the main Backup bootstrap/configuration file'
|
|
146
|
+
method_option :config_path, :type => :string,
|
|
147
|
+
:desc => 'Path to your Backup configuration directory'
|
|
148
|
+
define_method 'generate:config' do
|
|
149
|
+
config_path = options[:config_path] ?
|
|
150
|
+
File.expand_path(options[:config_path]) : Config.root_path
|
|
151
|
+
config = File.join(config_path, "config.rb")
|
|
152
|
+
|
|
153
|
+
FileUtils.mkdir_p(config_path)
|
|
154
|
+
if overwrite?(config)
|
|
155
|
+
File.open(config, "w") do |file|
|
|
156
|
+
file.write(Backup::Template.new.result("cli/utility/config"))
|
|
157
|
+
end
|
|
158
|
+
puts "Generated configuration file: '#{ config }'."
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
##
|
|
163
|
+
# [Decrypt]
|
|
164
|
+
# Shorthand for decrypting encrypted files
|
|
165
|
+
desc 'decrypt', 'Decrypts encrypted files'
|
|
166
|
+
method_option :encryptor, :type => :string, :required => true
|
|
167
|
+
method_option :in, :type => :string, :required => true
|
|
168
|
+
method_option :out, :type => :string, :required => true
|
|
169
|
+
method_option :base64, :type => :boolean, :default => false
|
|
170
|
+
method_option :password_file, :type => :string, :default => ''
|
|
171
|
+
method_option :salt, :type => :boolean, :default => false
|
|
172
|
+
def decrypt
|
|
173
|
+
case options[:encryptor].downcase
|
|
174
|
+
when 'openssl'
|
|
175
|
+
base64 = options[:base64] ? '-base64' : ''
|
|
176
|
+
password = options[:password_file] ? "-pass file:#{options[:password_file]}" : ''
|
|
177
|
+
salt = options[:salt] ? '-salt' : ''
|
|
178
|
+
%x[openssl aes-256-cbc -d #{base64} #{password} #{salt} -in '#{options[:in]}' -out '#{options[:out]}']
|
|
179
|
+
when 'gpg'
|
|
180
|
+
%x[gpg -o '#{options[:out]}' -d '#{options[:in]}']
|
|
181
|
+
else
|
|
182
|
+
puts "Unknown encryptor: #{options[:encryptor]}"
|
|
183
|
+
puts "Use either 'openssl' or 'gpg'."
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
##
|
|
188
|
+
# [Dependencies]
|
|
189
|
+
# Returns a list of Backup's dependencies
|
|
190
|
+
desc 'dependencies', 'Display the list of dependencies for Backup, or install them through Backup.'
|
|
191
|
+
method_option :install, :type => :string
|
|
192
|
+
method_option :list, :type => :boolean
|
|
193
|
+
def dependencies
|
|
194
|
+
unless options.any?
|
|
195
|
+
puts
|
|
196
|
+
puts "To display a list of available dependencies, run:\n\n"
|
|
197
|
+
puts " backup dependencies --list"
|
|
198
|
+
puts
|
|
199
|
+
puts "To install one of these dependencies (with the correct version), run:\n\n"
|
|
200
|
+
puts " backup dependencies --install <name>"
|
|
201
|
+
exit
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
if options[:list]
|
|
205
|
+
Backup::Dependency.all.each do |name, gemspec|
|
|
206
|
+
puts
|
|
207
|
+
puts name
|
|
208
|
+
puts "--------------------------------------------------"
|
|
209
|
+
puts "version: #{gemspec[:version]}"
|
|
210
|
+
puts "lib required: #{gemspec[:require]}"
|
|
211
|
+
puts "used for: #{gemspec[:for]}"
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
if options[:install]
|
|
216
|
+
puts
|
|
217
|
+
puts "Installing \"#{options[:install]}\" version \"#{Backup::Dependency.all[options[:install]][:version]}\".."
|
|
218
|
+
puts "If this doesn't work, please issue the following command yourself:\n\n"
|
|
219
|
+
puts " gem install #{options[:install]} -v '#{Backup::Dependency.all[options[:install]][:version]}'\n\n"
|
|
220
|
+
puts "Please wait..\n\n"
|
|
221
|
+
puts %x[gem install #{options[:install]} -v '#{Backup::Dependency.all[options[:install]][:version]}']
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
##
|
|
226
|
+
# [Version]
|
|
227
|
+
# Returns the current version of the Backup gem
|
|
228
|
+
map '-v' => :version
|
|
229
|
+
desc 'version', 'Display installed Backup version'
|
|
230
|
+
def version
|
|
231
|
+
puts "Backup #{Backup::Version.current}"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
private
|
|
235
|
+
|
|
236
|
+
##
|
|
237
|
+
# Helper method for asking the user if he/she wants to overwrite the file
|
|
238
|
+
def overwrite?(path)
|
|
239
|
+
if File.exist?(path)
|
|
240
|
+
return yes? "A file already exists at '#{ path }'. Do you want to overwrite? [y/n]"
|
|
241
|
+
end
|
|
242
|
+
true
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|