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,88 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
Backup::Dependency.load('httparty')
|
|
4
|
+
|
|
5
|
+
module Backup
|
|
6
|
+
module Notifier
|
|
7
|
+
class Presently < Base
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# Presently subdomain
|
|
11
|
+
attr_accessor :subdomain
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Presently credentials
|
|
15
|
+
attr_accessor :user_name, :password
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Group id
|
|
19
|
+
attr_accessor :group_id
|
|
20
|
+
|
|
21
|
+
def initialize(model, &block)
|
|
22
|
+
super(model)
|
|
23
|
+
|
|
24
|
+
instance_eval(&block) if block_given?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Notify the user of the backup operation results.
|
|
31
|
+
# `status` indicates one of the following:
|
|
32
|
+
#
|
|
33
|
+
# `:success`
|
|
34
|
+
# : The backup completed successfully.
|
|
35
|
+
# : Notification will be sent if `on_success` was set to `true`
|
|
36
|
+
#
|
|
37
|
+
# `:warning`
|
|
38
|
+
# : The backup completed successfully, but warnings were logged
|
|
39
|
+
# : Notification will be sent, including a copy of the current
|
|
40
|
+
# : backup log, if `on_warning` was set to `true`
|
|
41
|
+
#
|
|
42
|
+
# `:failure`
|
|
43
|
+
# : The backup operation failed.
|
|
44
|
+
# : Notification will be sent, including the Exception which caused
|
|
45
|
+
# : the failure, the Exception's backtrace, a copy of the current
|
|
46
|
+
# : backup log and other information if `on_failure` was set to `true`
|
|
47
|
+
#
|
|
48
|
+
def notify!(status)
|
|
49
|
+
name = case status
|
|
50
|
+
when :success then 'Success'
|
|
51
|
+
when :warning then 'Warning'
|
|
52
|
+
when :failure then 'Failure'
|
|
53
|
+
end
|
|
54
|
+
message = "[Backup::%s] #{@model.label} (#{@model.trigger})" % name
|
|
55
|
+
send_message(message)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def send_message(message)
|
|
59
|
+
client = Client.new(subdomain, user_name, password, group_id)
|
|
60
|
+
client.update(message)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
class Client
|
|
64
|
+
include HTTParty
|
|
65
|
+
|
|
66
|
+
attr_accessor :subdomain, :user_name, :password, :group_id
|
|
67
|
+
|
|
68
|
+
def initialize(subdomain, user_name, password, group_id)
|
|
69
|
+
@subdomain = subdomain
|
|
70
|
+
@user_name = user_name
|
|
71
|
+
@password = password
|
|
72
|
+
@group_id = group_id
|
|
73
|
+
|
|
74
|
+
self.class.base_uri "https://#{subdomain}.presently.com"
|
|
75
|
+
self.class.basic_auth user_name, password
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def update(message)
|
|
79
|
+
message = "d @#{group_id} #{message}" if group_id
|
|
80
|
+
self.class.post "/api/twitter/statuses/update.json", :body => {
|
|
81
|
+
:status => message,
|
|
82
|
+
:source => "Backup Notifier"
|
|
83
|
+
}
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Prowler gem when using Prowler notifications
|
|
5
|
+
Backup::Dependency.load('prowler')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Notifier
|
|
9
|
+
class Prowl < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Application name
|
|
13
|
+
# Tell something like your server name. Example: "Server1 Backup"
|
|
14
|
+
attr_accessor :application
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# API-Key
|
|
18
|
+
# Create a Prowl account and request an API key on prowlapp.com.
|
|
19
|
+
attr_accessor :api_key
|
|
20
|
+
|
|
21
|
+
def initialize(model, &block)
|
|
22
|
+
super(model)
|
|
23
|
+
|
|
24
|
+
instance_eval(&block) if block_given?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Notify the user of the backup operation results.
|
|
31
|
+
# `status` indicates one of the following:
|
|
32
|
+
#
|
|
33
|
+
# `:success`
|
|
34
|
+
# : The backup completed successfully.
|
|
35
|
+
# : Notification will be sent if `on_success` was set to `true`
|
|
36
|
+
#
|
|
37
|
+
# `:warning`
|
|
38
|
+
# : The backup completed successfully, but warnings were logged
|
|
39
|
+
# : Notification will be sent, including a copy of the current
|
|
40
|
+
# : backup log, if `on_warning` was set to `true`
|
|
41
|
+
#
|
|
42
|
+
# `:failure`
|
|
43
|
+
# : The backup operation failed.
|
|
44
|
+
# : Notification will be sent, including the Exception which caused
|
|
45
|
+
# : the failure, the Exception's backtrace, a copy of the current
|
|
46
|
+
# : backup log and other information if `on_failure` was set to `true`
|
|
47
|
+
#
|
|
48
|
+
def notify!(status)
|
|
49
|
+
name = case status
|
|
50
|
+
when :success then 'Success'
|
|
51
|
+
when :warning then 'Warning'
|
|
52
|
+
when :failure then 'Failure'
|
|
53
|
+
end
|
|
54
|
+
message = '[Backup::%s]' % name
|
|
55
|
+
send_message(message)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def send_message(message)
|
|
59
|
+
client = Prowler.new(:application => application, :api_key => api_key)
|
|
60
|
+
client.notify(message, "#{@model.label} (#{@model.trigger})")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# Only load the Twitter gem when using Twitter notifications
|
|
5
|
+
Backup::Dependency.load('twitter')
|
|
6
|
+
|
|
7
|
+
module Backup
|
|
8
|
+
module Notifier
|
|
9
|
+
class Twitter < Base
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Twitter consumer key credentials
|
|
13
|
+
attr_accessor :consumer_key, :consumer_secret
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# OAuth credentials
|
|
17
|
+
attr_accessor :oauth_token, :oauth_token_secret
|
|
18
|
+
|
|
19
|
+
def initialize(model, &block)
|
|
20
|
+
super(model)
|
|
21
|
+
|
|
22
|
+
instance_eval(&block) if block_given?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Notify the user of the backup operation results.
|
|
29
|
+
# `status` indicates one of the following:
|
|
30
|
+
#
|
|
31
|
+
# `:success`
|
|
32
|
+
# : The backup completed successfully.
|
|
33
|
+
# : Notification will be sent if `on_success` was set to `true`
|
|
34
|
+
#
|
|
35
|
+
# `:warning`
|
|
36
|
+
# : The backup completed successfully, but warnings were logged
|
|
37
|
+
# : Notification will be sent, including a copy of the current
|
|
38
|
+
# : backup log, if `on_warning` was set to `true`
|
|
39
|
+
#
|
|
40
|
+
# `:failure`
|
|
41
|
+
# : The backup operation failed.
|
|
42
|
+
# : Notification will be sent, including the Exception which caused
|
|
43
|
+
# : the failure, the Exception's backtrace, a copy of the current
|
|
44
|
+
# : backup log and other information if `on_failure` was set to `true`
|
|
45
|
+
#
|
|
46
|
+
def notify!(status)
|
|
47
|
+
name = case status
|
|
48
|
+
when :success then 'Success'
|
|
49
|
+
when :warning then 'Warning'
|
|
50
|
+
when :failure then 'Failure'
|
|
51
|
+
end
|
|
52
|
+
message = "[Backup::%s] #{@model.label} (#{@model.trigger}) (@ #{@model.time})" % name
|
|
53
|
+
send_message(message)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def send_message(message)
|
|
57
|
+
::Twitter.configure do |config|
|
|
58
|
+
config.consumer_key = @consumer_key
|
|
59
|
+
config.consumer_secret = @consumer_secret
|
|
60
|
+
config.oauth_token = @oauth_token
|
|
61
|
+
config.oauth_token_secret = @oauth_token_secret
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
client = ::Twitter::Client.new
|
|
65
|
+
client.update(message)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
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 checksum_name
|
|
35
|
+
basename+".sum"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def filenames
|
|
39
|
+
if chunk_suffixes.empty?
|
|
40
|
+
[basename]
|
|
41
|
+
else
|
|
42
|
+
chunk_suffixes.map {|suffix| "#{ basename }-#{ suffix }" }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def basename
|
|
47
|
+
"#{ time }.#{ trigger }.#{ extension }"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
module Packager
|
|
5
|
+
class << self
|
|
6
|
+
include Backup::CLI::Helpers
|
|
7
|
+
|
|
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
|
|
14
|
+
@checksum_creator = model.checksum_creator
|
|
15
|
+
@pipeline = Pipeline.new
|
|
16
|
+
|
|
17
|
+
Logger.message "Packaging the backup files..."
|
|
18
|
+
procedure.call
|
|
19
|
+
|
|
20
|
+
if @pipeline.success?
|
|
21
|
+
Logger.message "Packaging Complete!"
|
|
22
|
+
else
|
|
23
|
+
raise Errors::Packager::PipelineError,
|
|
24
|
+
"Failed to Create Backup Package\n" +
|
|
25
|
+
@pipeline.error_messages
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# Builds a chain of nested Procs which adds each command to a Pipeline
|
|
33
|
+
# needed to package the final command to package the backup.
|
|
34
|
+
# This is done so that the Encryptor and Splitter have the ability
|
|
35
|
+
# to perform actions before and after the final command is executed.
|
|
36
|
+
# No Encryptors currently utilize this, however the Splitter does.
|
|
37
|
+
def procedure
|
|
38
|
+
stack = []
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Initial `tar` command to package the temporary backup folder.
|
|
42
|
+
# The command's output will then be either piped to the Encryptor
|
|
43
|
+
# or the Splitter (if no Encryptor), or through `cat` into the final
|
|
44
|
+
# output file if neither are configured.
|
|
45
|
+
@pipeline << "#{ utility(:tar) } -cf - " +
|
|
46
|
+
"-C '#{ Config.tmp_path }' '#{ @package.trigger }'"
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# If an Encryptor was configured, it will be called first
|
|
50
|
+
# to add the encryption utility command to be piped through,
|
|
51
|
+
# and amend the final package extension.
|
|
52
|
+
# It's output will then be either piped into a Splitter,
|
|
53
|
+
# or through `cat` into the final output file.
|
|
54
|
+
if @encryptor
|
|
55
|
+
stack << lambda do
|
|
56
|
+
@encryptor.encrypt_with do |command, ext|
|
|
57
|
+
@pipeline << command
|
|
58
|
+
@package.extension << ext
|
|
59
|
+
stack.shift.call
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# If a Splitter was configured, the `split` utility command will be
|
|
66
|
+
# added to the Pipeline to split the final output into multiple files.
|
|
67
|
+
# Once the Proc executing the Pipeline has completed and returns back
|
|
68
|
+
# to the Splitter, it will check the final output files to determine
|
|
69
|
+
# if the backup was indeed split.
|
|
70
|
+
# If so, it will set the package's chunk_suffixes. If not, it will
|
|
71
|
+
# remove the '-aa' suffix from the only file created by `split`.
|
|
72
|
+
#
|
|
73
|
+
# If no Splitter was configured, the final file output will be
|
|
74
|
+
# piped through `cat` into the final output file.
|
|
75
|
+
if @splitter
|
|
76
|
+
stack << lambda do
|
|
77
|
+
@splitter.split_with do |command|
|
|
78
|
+
@pipeline << command
|
|
79
|
+
stack.shift.call
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
else
|
|
83
|
+
stack << lambda do
|
|
84
|
+
outfile = File.join(Config.tmp_path, @package.basename)
|
|
85
|
+
@pipeline << "cat > #{ outfile }"
|
|
86
|
+
|
|
87
|
+
if @checksum_creator
|
|
88
|
+
@checksum_creator.checksum_with outfile do |cmd|
|
|
89
|
+
@pipeline << cmd
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
stack.shift.call
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
##
|
|
98
|
+
# Last Proc to be called runs the Pipeline the procedure built.
|
|
99
|
+
# Once complete, the call stack will unwind back through the
|
|
100
|
+
# preceeding Procs in the stack (if any)
|
|
101
|
+
stack << lambda { @pipeline.run }
|
|
102
|
+
|
|
103
|
+
stack.shift
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
module Backup
|
|
4
|
+
class Pipeline
|
|
5
|
+
include Backup::CLI::Helpers
|
|
6
|
+
|
|
7
|
+
attr_reader :stderr, :errors
|
|
8
|
+
|
|
9
|
+
def initialize
|
|
10
|
+
@commands = []
|
|
11
|
+
@errors = []
|
|
12
|
+
@stderr = ''
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Adds a command to be executed in the pipeline.
|
|
17
|
+
# Each command will be run in the order in which it was added,
|
|
18
|
+
# with it's output being piped to the next command.
|
|
19
|
+
def <<(command)
|
|
20
|
+
@commands << command
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Runs the command line from `#pipeline` and collects STDOUT/STDERR.
|
|
25
|
+
# STDOUT is then parsed to determine the exit status of each command.
|
|
26
|
+
# For each command with a non-zero exit status, a SystemCallError is
|
|
27
|
+
# created and added to @errors. All STDERR output is set in @stderr.
|
|
28
|
+
#
|
|
29
|
+
# Note that there is no accumulated STDOUT from the commands,
|
|
30
|
+
# and the last command added to the pipeline should *not* attempt to
|
|
31
|
+
# write to STDOUT, as this will raise an Exception.
|
|
32
|
+
#
|
|
33
|
+
# Use `#success?` to determine if all commands in the pipeline succeeded.
|
|
34
|
+
# If `#success?` returns `false`, use `#error_messages` to get an error report.
|
|
35
|
+
def run
|
|
36
|
+
Open4.popen4(pipeline) do |pid, stdin, stdout, stderr|
|
|
37
|
+
pipestatus = stdout.read.gsub("\n", '').split(':').sort
|
|
38
|
+
pipestatus.each do |status|
|
|
39
|
+
index, exitstatus = status.split('|').map(&:to_i)
|
|
40
|
+
if exitstatus > 0
|
|
41
|
+
command = command_name(@commands[index])
|
|
42
|
+
@errors << SystemCallError.new(
|
|
43
|
+
"'#{ command }' returned exit code: #{ exitstatus }", exitstatus
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
@stderr = stderr.read.strip
|
|
48
|
+
end
|
|
49
|
+
Logger.warn(stderr_messages) if success? && stderr_messages
|
|
50
|
+
rescue Exception => e
|
|
51
|
+
raise Errors::Pipeline::ExecutionError.wrap(e)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def success?
|
|
55
|
+
@errors.empty?
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
##
|
|
59
|
+
# Returns a multi-line String, reporting all STDERR messages received
|
|
60
|
+
# from the commands in the pipeline (if any), along with the SystemCallError
|
|
61
|
+
# (Errno) message for each command which had a non-zero exit status.
|
|
62
|
+
#
|
|
63
|
+
# Each error is wrapped by Backup::Errors to provide formatting.
|
|
64
|
+
def error_messages
|
|
65
|
+
@error_messages ||= (stderr_messages || '') +
|
|
66
|
+
"The following system errors were returned:\n" +
|
|
67
|
+
@errors.map {|err| Errors::Error.wrap(err).message }.join("\n")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Each command is added as part of the pipeline, grouped with an `echo`
|
|
74
|
+
# command to pass along the command's index in @commands and it's exit status.
|
|
75
|
+
# The command's STDERR is redirected to FD#4, and the `echo` command to
|
|
76
|
+
# report the "index|exit status" it redirected to FD#3.
|
|
77
|
+
# Each command's STDOUT will be connected to the STDIN of the next subshell.
|
|
78
|
+
# The entire pipeline is run within a container group, which redirects
|
|
79
|
+
# FD#3 to STDOUT and FD#4 to STDERR so these can be collected.
|
|
80
|
+
# FD#1 is closed so any attempt by the last command in the pipeline to
|
|
81
|
+
# write to STDOUT will raise an error, as we don't want this to interfere
|
|
82
|
+
# with collecting the exit statuses.
|
|
83
|
+
#
|
|
84
|
+
# There is no guarantee as to the order of this output, which is why the
|
|
85
|
+
# command's index in @commands is passed along with it's exit status.
|
|
86
|
+
# And, if multiple commands output messages on STDERR, those messages
|
|
87
|
+
# may be interleaved. Interleaving of the "index|exit status" outputs
|
|
88
|
+
# should not be an issue, given the small byte size of the data being written.
|
|
89
|
+
def pipeline
|
|
90
|
+
parts = []
|
|
91
|
+
@commands.each_with_index do |command, index|
|
|
92
|
+
parts << %Q[( #{ command } 2>&4; echo "#{ index }|$?:" >&3 )]
|
|
93
|
+
end
|
|
94
|
+
"( #{ parts.join(' | ') } ) 3>&1- 4>&2"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def stderr_messages
|
|
98
|
+
@stderr_messages ||= @stderr.empty? ? false : <<-EOS.gsub(/^ +/, ' ')
|
|
99
|
+
Pipeline STDERR Messages:
|
|
100
|
+
(Note: may be interleaved if multiple commands returned error messages)
|
|
101
|
+
|
|
102
|
+
#{ @stderr }
|
|
103
|
+
EOS
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
end
|
|
107
|
+
end
|