backup-ssh 4.1.10 → 4.4.0

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -6
  3. data/lib/backup.rb +3 -0
  4. data/lib/backup/config/dsl.rb +2 -2
  5. data/lib/backup/database/mongodb.rb +2 -1
  6. data/lib/backup/database/mysql.rb +2 -2
  7. data/lib/backup/database/postgresql.rb +1 -1
  8. data/lib/backup/model.rb +26 -1
  9. data/lib/backup/notifier/base.rb +30 -0
  10. data/lib/backup/notifier/campfire.rb +1 -7
  11. data/lib/backup/notifier/command.rb +102 -0
  12. data/lib/backup/notifier/datadog.rb +11 -20
  13. data/lib/backup/notifier/flowdock.rb +6 -5
  14. data/lib/backup/notifier/hipchat.rb +33 -8
  15. data/lib/backup/notifier/http_post.rb +2 -7
  16. data/lib/backup/notifier/mail.rb +26 -15
  17. data/lib/backup/notifier/nagios.rb +3 -8
  18. data/lib/backup/notifier/prowl.rb +8 -9
  19. data/lib/backup/notifier/pushover.rb +1 -7
  20. data/lib/backup/notifier/ses.rb +19 -8
  21. data/lib/backup/notifier/slack.rb +4 -10
  22. data/lib/backup/notifier/twitter.rb +1 -7
  23. data/lib/backup/notifier/zabbix.rb +1 -6
  24. data/lib/backup/package.rb +4 -0
  25. data/lib/backup/packager.rb +8 -2
  26. data/lib/backup/storage/base.rb +15 -3
  27. data/lib/backup/storage/cycler.rb +24 -14
  28. data/lib/backup/storage/dropbox.rb +0 -24
  29. data/lib/backup/storage/ftp.rb +15 -1
  30. data/lib/backup/storage/qiniu.rb +65 -0
  31. data/lib/backup/storage/s3.rb +3 -2
  32. data/lib/backup/syncer/rsync/base.rb +7 -1
  33. data/lib/backup/version.rb +1 -1
  34. data/templates/cli/databases/mongodb +1 -1
  35. data/templates/cli/notifiers/command +32 -0
  36. data/templates/cli/notifiers/hipchat +1 -0
  37. data/templates/cli/notifiers/mail +3 -0
  38. data/templates/cli/storages/dropbox +1 -0
  39. data/templates/cli/storages/ftp +1 -0
  40. data/templates/cli/storages/local +1 -0
  41. data/templates/cli/storages/qiniu +12 -0
  42. data/templates/cli/storages/s3 +2 -0
  43. data/templates/cli/storages/scp +1 -0
  44. data/templates/cli/storages/sftp +1 -0
  45. metadata +79 -46
  46. data/LICENSE.md +0 -24
  47. data/lib/backup/storage/ninefold.rb +0 -74
  48. data/templates/cli/storages/ninefold +0 -9
@@ -95,18 +95,13 @@ module Backup
95
95
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
96
96
  #
97
97
  def notify!(status)
98
- tag = case status
99
- when :success then '[Backup::Success]'
100
- when :failure then '[Backup::Failure]'
101
- when :warning then '[Backup::Warning]'
102
- end
103
- message = "#{ tag } #{ model.label } (#{ model.trigger })"
98
+ msg = message.call(model, :status => status_data_for(status))
104
99
 
105
100
  opts = {
106
101
  :headers => { 'User-Agent' => "Backup/#{ VERSION }" }.
107
102
  merge(headers).reject {|k,v| v.nil? }.
108
103
  merge('Content-Type' => 'application/x-www-form-urlencoded'),
109
- :body => URI.encode_www_form({ 'message' => message }.
104
+ :body => URI.encode_www_form({ 'message' => msg }.
110
105
  merge(params).reject {|k,v| v.nil? }.
111
106
  merge('status' => status.to_s)),
112
107
  :expects => success_codes # raise error if unsuccessful
@@ -37,6 +37,18 @@ module Backup
37
37
  # Receiver Email Address
38
38
  attr_accessor :to
39
39
 
40
+ ##
41
+ # CC receiver Email Address
42
+ attr_accessor :cc
43
+
44
+ ##
45
+ # BCC receiver Email Address
46
+ attr_accessor :bcc
47
+
48
+ ##
49
+ # Set reply to email address
50
+ attr_accessor :reply_to
51
+
40
52
  ##
41
53
  # SMTP Server Address
42
54
  attr_accessor :address
@@ -148,14 +160,8 @@ module Backup
148
160
  # : backup log, if `on_failure` is `true`.
149
161
  #
150
162
  def notify!(status)
151
- tag = case status
152
- when :success then '[Backup::Success]'
153
- when :warning then '[Backup::Warning]'
154
- when :failure then '[Backup::Failure]'
155
- end
156
-
157
163
  email = new_email
158
- email.subject = "#{ tag } #{ model.label } (#{ model.trigger })"
164
+ email.subject = message.call(model, :status => status_data_for(status))
159
165
 
160
166
  send_log = send_log_on.include?(status)
161
167
  template = Backup::Template.new({ :model => model, :send_log => send_log })
@@ -182,9 +188,9 @@ module Backup
182
188
  options =
183
189
  case method
184
190
  when 'smtp'
185
- { :address => @address,
191
+ opts = {
192
+ :address => @address,
186
193
  :port => @port,
187
- :domain => @domain,
188
194
  :user_name => @user_name,
189
195
  :password => @password,
190
196
  :authentication => @authentication,
@@ -193,6 +199,11 @@ module Backup
193
199
  :ssl => @encryption == :ssl,
194
200
  :tls => @encryption == :tls
195
201
  }
202
+
203
+ # Don't override default domain setting if domain not applicable.
204
+ # ref https://github.com/mikel/mail/blob/2.6.3/lib/mail/network/delivery_methods/smtp.rb#L82
205
+ opts[:domain] = @domain if @domain
206
+ opts
196
207
  when 'sendmail'
197
208
  opts = {}
198
209
  opts.merge!(:location => utility(:sendmail))
@@ -209,13 +220,13 @@ module Backup
209
220
  when 'test' then {}
210
221
  end
211
222
 
212
- ::Mail.defaults do
213
- delivery_method method.to_sym, options
214
- end
215
-
216
223
  email = ::Mail.new
217
- email.to = @to
218
- email.from = @from
224
+ email.delivery_method method.to_sym, options
225
+ email.to = to
226
+ email.from = from
227
+ email.cc = cc
228
+ email.bcc = bcc
229
+ email.reply_to = reply_to
219
230
  email
220
231
  end
221
232
 
@@ -14,8 +14,8 @@ module Backup
14
14
 
15
15
  ##
16
16
  # Nagios nrpe configuration file.
17
- attr_accessor :send_nsca_cfg
18
-
17
+ attr_accessor :send_nsca_cfg
18
+
19
19
  ##
20
20
  # Name of the Nagios service for the backup check.
21
21
  attr_accessor :service_name
@@ -55,12 +55,7 @@ module Backup
55
55
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
56
56
  #
57
57
  def notify!(status)
58
- message = case status
59
- when :success then 'Completed Successfully'
60
- when :warning then 'Completed Successfully (with Warnings)'
61
- when :failure then 'Failed'
62
- end
63
- send_message("#{ message } in #{ model.duration }")
58
+ send_message(message.call(model, :status => status_data_for(status)))
64
59
  end
65
60
 
66
61
  def send_message(message)
@@ -16,6 +16,9 @@ module Backup
16
16
  attr_accessor :api_key
17
17
 
18
18
  def initialize(model, &block)
19
+ @message = lambda do |model, data|
20
+ "#{ model.label } (#{ model.trigger })"
21
+ end
19
22
  super
20
23
  instance_eval(&block) if block_given?
21
24
  end
@@ -40,21 +43,17 @@ module Backup
40
43
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
41
44
  #
42
45
  def notify!(status)
43
- tag = case status
44
- when :success then '[Backup::Success]'
45
- when :warning then '[Backup::Warning]'
46
- when :failure then '[Backup::Failure]'
47
- end
48
- send_message(tag)
46
+ send_message(status)
49
47
  end
50
48
 
51
- def send_message(message)
49
+ def send_message(status)
52
50
  uri = 'https://api.prowlapp.com/publicapi/add'
51
+ status_data = status_data_for(status)
53
52
  data = {
54
53
  :application => application,
55
54
  :apikey => api_key,
56
- :event => message,
57
- :description => "#{ model.label } (#{ model.trigger })"
55
+ :event => status_data[:message],
56
+ :description => message.call(model, :status => status_data)
58
57
  }
59
58
  options = {
60
59
  :headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
@@ -51,13 +51,7 @@ module Backup
51
51
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
52
52
  #
53
53
  def notify!(status)
54
- tag = case status
55
- when :success then '[Backup::Success]'
56
- when :failure then '[Backup::Failure]'
57
- when :warning then '[Backup::Warning]'
58
- end
59
- message = "#{ tag } #{ model.label } (#{ model.trigger })"
60
- send_message(message)
54
+ send_message(message.call(model, :status => status_data_for(status)))
61
55
  end
62
56
 
63
57
  def send_message(message)
@@ -21,6 +21,18 @@ module Backup
21
21
  # Receiver Email Address
22
22
  attr_accessor :to
23
23
 
24
+ ##
25
+ # CC receiver Email Address
26
+ attr_accessor :cc
27
+
28
+ ##
29
+ # BCC receiver Email Address
30
+ attr_accessor :bcc
31
+
32
+ ##
33
+ # Set reply to email address
34
+ attr_accessor :reply_to
35
+
24
36
  def initialize(model, &block)
25
37
  super
26
38
  instance_eval(&block) if block_given?
@@ -66,14 +78,13 @@ module Backup
66
78
  # : backup log, if `on_failure` is `true`.
67
79
  #
68
80
  def notify!(status)
69
- tag = case status
70
- when :success then '[Backup::Success]'
71
- when :warning then '[Backup::Warning]'
72
- when :failure then '[Backup::Failure]'
73
- end
74
-
75
- email = ::Mail.new(:to => to, :from => from)
76
- email.subject = "#{ tag } #{ model.label } (#{ model.trigger })"
81
+ email = ::Mail.new
82
+ email.to = to
83
+ email.from = from
84
+ email.cc = cc
85
+ email.bcc = bcc
86
+ email.reply_to = reply_to
87
+ email.subject = message.call(model, :status => status_data_for(status))
77
88
 
78
89
  send_log = send_log_on.include?(status)
79
90
  template = Backup::Template.new({ :model => model, :send_log => send_log })
@@ -61,21 +61,15 @@ module Backup
61
61
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
62
62
  #
63
63
  def notify!(status)
64
- tag = case status
65
- when :success then '[Backup::Success]'
66
- when :failure then '[Backup::Failure]'
67
- when :warning then '[Backup::Warning]'
68
- end
69
- message = "#{ tag } #{ model.label } (#{ model.trigger })"
70
-
71
- data = { :text => message }
64
+ data = {
65
+ :text => message.call(model, :status => status_data_for(status)),
66
+ :attachments => [attachment(status)]
67
+ }
72
68
  [:channel, :username, :icon_emoji].each do |param|
73
69
  val = send(param)
74
70
  data.merge!(param => val) if val
75
71
  end
76
72
 
77
- data.merge!(:attachments => [attachment(status)])
78
-
79
73
  options = {
80
74
  :headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
81
75
  :body => URI.encode_www_form(:payload => JSON.dump(data))
@@ -38,13 +38,7 @@ module Backup
38
38
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
39
39
  #
40
40
  def notify!(status)
41
- tag = case status
42
- when :success then '[Backup::Success]'
43
- when :warning then '[Backup::Warning]'
44
- when :failure then '[Backup::Failure]'
45
- end
46
- message = "#{ tag } #{ model.label } (#{ model.trigger }) (@ #{ model.time })"
47
- send_message(message)
41
+ send_message(message.call(model, :status => status_data_for(status)))
48
42
  end
49
43
 
50
44
  # Twitter::Client will raise an error if unsuccessful.
@@ -45,12 +45,7 @@ module Backup
45
45
  # : Notification will be sent if `on_warning` or `on_success` is `true`.
46
46
  #
47
47
  def notify!(status)
48
- message = case status
49
- when :success then 'Completed Successfully'
50
- when :warning then 'Completed Successfully (with Warnings)'
51
- when :failure then 'Failed'
52
- end
53
- send_message("#{ message } in #{ model.duration }")
48
+ send_message(message.call(model, :status => status_data_for(status)))
54
49
  end
55
50
 
56
51
  def send_message(message)
@@ -47,5 +47,9 @@ module Backup
47
47
  "#{ trigger }.#{ extension }"
48
48
  end
49
49
 
50
+ def time_as_object
51
+ Time.strptime(time, '%Y.%m.%d.%H.%M.%S')
52
+ end
53
+
50
54
  end
51
55
  end
@@ -42,8 +42,11 @@ module Backup
42
42
  # The command's output will then be either piped to the Encryptor
43
43
  # or the Splitter (if no Encryptor), or through `cat` into the final
44
44
  # output file if neither are configured.
45
- @pipeline << "#{ utility(:tar) } -cf - " +
46
- "-C '#{ Config.tmp_path }' '#{ @package.trigger }'"
45
+ @pipeline.add(
46
+ "#{ utility(:tar) } -cf - " +
47
+ "-C '#{ Config.tmp_path }' '#{ @package.trigger }'",
48
+ tar_success_codes
49
+ )
47
50
 
48
51
  ##
49
52
  # If an Encryptor was configured, it will be called first
@@ -96,6 +99,9 @@ module Backup
96
99
  stack.shift
97
100
  end
98
101
 
102
+ def tar_success_codes
103
+ gnu_tar? ? [0, 1] : [0]
104
+ end
99
105
  end
100
106
  end
101
107
  end
@@ -10,8 +10,18 @@ module Backup
10
10
  attr_accessor :path
11
11
 
12
12
  ##
13
- # Sets the limit to how many backups to keep in the remote location.
14
- # If exceeded, the oldest will be removed to make room for the newest
13
+ # Number of backups to keep or time until which to keep.
14
+ #
15
+ # If an Integer is given it sets the limit to how many backups to keep in
16
+ # the remote location. If exceeded, the oldest will be removed to make
17
+ # room for the newest.
18
+ #
19
+ # If a Time object is given it will remove backups _older_ than the given
20
+ # date.
21
+ #
22
+ # @!attribute [rw] keep
23
+ # @param [Integer|Time]
24
+ # @return [Integer|Time]
15
25
  attr_accessor :keep
16
26
 
17
27
  attr_reader :model, :package, :storage_id
@@ -33,7 +43,9 @@ module Backup
33
43
  def perform!
34
44
  Logger.info "#{ storage_name } Started..."
35
45
  transfer!
36
- cycle! if respond_to?(:cycle!, true) && keep.to_i > 0
46
+ if respond_to?(:cycle!, true) && (keep.to_i > 0 || keep.is_a?(Time))
47
+ cycle!
48
+ end
37
49
  Logger.info "#{ storage_name } Finished!"
38
50
  end
39
51
 
@@ -14,24 +14,34 @@ module Backup
14
14
  Logger.info 'Cycling Started...'
15
15
 
16
16
  packages = yaml_load.unshift(package)
17
- excess = packages.count - keep.to_i
17
+ cycled_packages = []
18
18
 
19
- if excess > 0
20
- packages.pop(excess).each do |pkg|
21
- begin
22
- remove!(pkg) unless pkg.no_cycle
23
- rescue => err
24
- Logger.warn Error.wrap(err, <<-EOS)
25
- There was a problem removing the following package:
26
- Trigger: #{pkg.trigger} :: Dated: #{pkg.time}
27
- Package included the following #{ pkg.filenames.count } file(s):
28
- #{ pkg.filenames.join("\n") }
29
- EOS
30
- end
19
+ if keep.is_a?(Date) || keep.is_a?(Time)
20
+ cycled_packages = packages.select do |p|
21
+ p.time_as_object < keep.to_time
31
22
  end
23
+ else
24
+ excess = packages.count - keep.to_i
25
+ cycled_packages = packages.last(excess) if excess > 0
32
26
  end
33
27
 
34
- yaml_save(packages)
28
+ saved_packages = packages - cycled_packages
29
+ cycled_packages.each { |package| delete_package package }
30
+
31
+ yaml_save(saved_packages)
32
+ end
33
+
34
+ def delete_package(package)
35
+ begin
36
+ remove!(package) unless package.no_cycle
37
+ rescue => err
38
+ Logger.warn Error.wrap(err, <<-EOS)
39
+ There was a problem removing the following package:
40
+ Trigger: #{package.trigger} :: Dated: #{package.time}
41
+ Package included the following #{ package.filenames.count } file(s):
42
+ #{ package.filenames.join("\n") }
43
+ EOS
44
+ end
35
45
  end
36
46
 
37
47
  # Returns path to the YAML data file.
@@ -210,27 +210,3 @@ module Backup
210
210
  end
211
211
  end
212
212
  end
213
-
214
- # Patch for dropbox-ruby-sdk-1.5.1
215
- class DropboxClient
216
- class ChunkedUploader
217
- def upload(chunk_size = 1024**2 * 4)
218
- while @offset < @total_size
219
- @file_obj.seek(@offset) unless @file_obj.pos == @offset
220
- data = @file_obj.read(chunk_size)
221
-
222
- begin
223
- resp = @client.parse_response(
224
- @client.partial_chunked_upload(data, @upload_id, @offset)
225
- )
226
- rescue DropboxError => err
227
- resp = JSON.parse(err.http_response.body) rescue {}
228
- raise err unless resp['offset']
229
- end
230
-
231
- @offset = resp['offset']
232
- @upload_id ||= resp['upload_id']
233
- end
234
- end
235
- end
236
- end
@@ -15,15 +15,25 @@ module Backup
15
15
  attr_accessor :ip, :port
16
16
 
17
17
  ##
18
- # use passive mode?
18
+ # Use passive mode?
19
19
  attr_accessor :passive_mode
20
20
 
21
+ ##
22
+ # Configure connection open and read timeouts.
23
+ # Net::FTP's open_timeout and read_timeout will both be configured using
24
+ # this setting.
25
+ # @!attribute [rw] timeout
26
+ # @param [Integer|Float]
27
+ # @return [Integer|Float]
28
+ attr_accessor :timeout
29
+
21
30
  def initialize(model, storage_id = nil)
22
31
  super
23
32
 
24
33
  @port ||= 21
25
34
  @path ||= 'backups'
26
35
  @passive_mode ||= false
36
+ @timeout ||= nil
27
37
  path.sub!(/^~\//, '')
28
38
  end
29
39
 
@@ -42,6 +52,10 @@ module Backup
42
52
  end; Net::FTP.send(:const_set, :FTP_PORT, port)
43
53
 
44
54
  Net::FTP.open(ip, username, password) do |ftp|
55
+ if timeout
56
+ ftp.open_timeout = timeout
57
+ ftp.read_timeout = timeout
58
+ end
45
59
  ftp.passive = true if passive_mode
46
60
  yield ftp
47
61
  end