backup 3.5.1 → 3.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dc2e8837fa998e2998728d7068b7b6bd40944aad
4
- data.tar.gz: 6d1f80d16e3de75e4e5ac424d261a4945b276114
3
+ metadata.gz: d68dc83802f92387efeb5d0bfd6e89c7d5d32e49
4
+ data.tar.gz: a9c414e7eb6a1c329b49329d3c4fc5391ab78f84
5
5
  SHA512:
6
- metadata.gz: 8a01458dadc536160bb9cbcb5b91cae1d0b4e3711b259c5a6d0af7a250e146cb7aeaa60549a66d986f4eeb3da4ce32e43d241740cabba831e2b1045eccec517e
7
- data.tar.gz: d4f84b2d26e477ade4d163be027ce3025ce3078eaa868d84a25c10c70a4b513afb8f12968077b1c272f514a872f1cd976b66638774a0ab3dcd1fdddc903034fd
6
+ metadata.gz: 1f801689681baae58593843de6828116bc688ece381912e47d6b74e8354f61bd437a13e0b36bf106331124de108788c626dd0fa1d16e09f9c04fff4834c9a747
7
+ data.tar.gz: ed9473697e3a81910ada2857f7c3533b341bc8ff0a9a6863db58d16cc408a2e29042ab4284bf0e44979dea0fa7dfebe68e48de10cc8b6a41a7c13ed62a321c1d
data/lib/backup/cli.rb CHANGED
@@ -156,15 +156,38 @@ module Backup
156
156
  exit(3)
157
157
  end
158
158
 
159
- # Model#perform! handles all exceptions from this point,
160
- # as each model may fail and return here to allow others to run.
161
- warnings = errors = false
162
- models.each do |model|
159
+ until models.empty?
160
+ model = models.shift
163
161
  model.perform!
164
- warnings ||= Logger.has_warnings?
165
- errors ||= Logger.has_errors?
162
+
163
+ case model.exit_status
164
+ when 1
165
+ warnings = true
166
+ when 2
167
+ errors = true
168
+ unless models.empty?
169
+ Logger.info Errors::ModelError.new(<<-EOS)
170
+ Backup will now continue...
171
+ The following triggers will now be processed:
172
+ (#{ models.map {|m| m.trigger }.join(', ') })
173
+ EOS
174
+ end
175
+ when 3
176
+ fatal = true
177
+ unless models.empty?
178
+ Logger.error Errors::ModelFatalError.new(<<-EOS)
179
+ Backup will now exit.
180
+ The following triggers will not be processed:
181
+ (#{ models.map {|m| m.trigger }.join(', ') })
182
+ EOS
183
+ end
184
+ end
185
+
186
+ model.notifiers.each(&:perform!)
187
+ exit(3) if fatal
166
188
  Logger.clear!
167
189
  end
190
+
168
191
  exit(errors ? 2 : 1) if errors || warnings
169
192
  end
170
193
 
data/lib/backup/errors.rb CHANGED
@@ -5,13 +5,21 @@ module Backup
5
5
  # - automatically defines module namespaces referenced under Backup::Errors
6
6
  # - any constant name referenced that ends with 'Error' will be created
7
7
  # as a subclass of Backup::Errors::Error
8
+ # - any constant name referenced that ends with 'FatalError' will be created
9
+ # as a subclass of Backup::Errors::FatalError
10
+ #
8
11
  # e.g.
9
12
  # err = Backup::Errors::Foo::Bar::FooError.new('error message')
10
13
  # err.message => "Foo::Bar::FooError: error message"
11
14
  #
15
+ # err = Backup::Errors::Foo::Bar::FooFatalError.new('error message')
16
+ # err.message => "Foo::Bar::FooFatalError: error message"
17
+ #
12
18
  module ErrorsHelper
13
19
  def const_missing(const)
14
- if const.to_s.end_with?('Error')
20
+ if const.to_s.end_with?('FatalError')
21
+ module_eval("class #{const} < Backup::Errors::FatalError; end")
22
+ elsif const.to_s.end_with?('Error')
15
23
  module_eval("class #{const} < Backup::Errors::Error; end")
16
24
  else
17
25
  module_eval("module #{const}; extend Backup::ErrorsHelper; end")
@@ -20,104 +28,61 @@ module Backup
20
28
  end
21
29
  end
22
30
 
23
- ##
24
- # provides cascading errors with formatted messages
25
- # see the specs for details
26
- #
27
- # e.g.
28
- # module Backup
29
- # begin
30
- # begin
31
- # begin
32
- # raise Errors::ZoneAError, 'an error occurred in Zone A'
33
- # rescue => err
34
- # raise Errors::ZoneBError.wrap(err, <<-EOS)
35
- # an error occurred in Zone B
36
- #
37
- # the following error should give a reason
38
- # EOS
39
- # end
40
- # rescue => err
41
- # raise Errors::ZoneCError.wrap(err)
42
- # end
43
- # rescue => err
44
- # puts Errors::ZoneDError.wrap(err, 'an error occurred in Zone D')
45
- # end
46
- # end
47
- #
48
- # Outputs:
49
- # ZoneDError: an error occurred in Zone D
50
- # Reason: ZoneCError
51
- # ZoneBError: an error occurred in Zone B
52
- #
53
- # the following error should give a reason
54
- # Reason: ZoneAError
55
- # an error occurred in Zone A
56
- #
57
31
  module Errors
58
32
  extend ErrorsHelper
59
33
 
60
- class Error < StandardError
61
-
62
- def self.wrap(orig_err, msg = nil)
63
- new(msg, orig_err)
64
- end
34
+ # Provides cascading errors with formatted messages.
35
+ # See the specs for details.
36
+ module NestedExceptions
65
37
 
66
- def initialize(msg = nil, orig_err = nil)
67
- super(msg)
68
- set_backtrace(orig_err.backtrace) if @orig_err = orig_err
38
+ def self.included(klass)
39
+ klass.extend Module.new {
40
+ def wrap(wrapped_exception, msg = nil)
41
+ new(msg, wrapped_exception)
42
+ end
43
+ }
69
44
  end
70
45
 
71
- def to_s
72
- return @to_s if @to_s
73
- orig_to_s = super()
74
-
75
- if orig_to_s == self.class.to_s
76
- msg = orig_err_msg ?
77
- "#{orig_err_class}: #{orig_err_msg}" : orig_err_class
78
- else
79
- msg = format_msg(orig_to_s)
80
- msg << "\n Reason: #{orig_err_class}" + (orig_err_msg ?
81
- "\n #{orig_err_msg}" : ' (no message given)') if @orig_err
46
+ def initialize(obj = nil, wrapped_exception = nil)
47
+ @wrapped_exception = wrapped_exception
48
+ msg = (obj.respond_to?(:to_str) ? obj.to_str : obj.to_s).
49
+ gsub(/^ */, ' ').strip
50
+ msg = clean_name(self.class.name) + (msg.empty? ? '' : ": #{ msg }")
51
+
52
+ if wrapped_exception
53
+ msg << "\n--- Wrapped Exception ---\n"
54
+ class_name = clean_name(wrapped_exception.class.name)
55
+ msg << class_name + ': ' unless
56
+ wrapped_exception.message.start_with? class_name
57
+ msg << wrapped_exception.message
82
58
  end
83
59
 
84
- @to_s = msg ? msg_prefix + msg : class_name
85
- end
86
-
87
- private
88
-
89
- def msg_prefix
90
- @msg_prefix ||= class_name + ': '
60
+ super(msg)
61
+ set_backtrace(wrapped_exception.backtrace) if wrapped_exception
91
62
  end
92
63
 
93
- def orig_msg
94
- @orig_msg ||= to_s.sub(msg_prefix, '')
95
- end
64
+ def exception(obj = nil)
65
+ return self if obj.nil? || equal?(obj)
96
66
 
97
- def class_name
98
- @class_name ||= self.class.to_s.sub('Backup::Errors::', '')
67
+ ex = self.class.new(obj, @wrapped_exception)
68
+ ex.set_backtrace(backtrace) unless ex.backtrace
69
+ ex
99
70
  end
100
71
 
101
- def orig_err_class
102
- return unless @orig_err
72
+ private
103
73
 
104
- @orig_err_class ||= @orig_err.is_a?(Errors::Error) ?
105
- @orig_err.send(:class_name) : @orig_err.class.to_s
74
+ def clean_name(name)
75
+ name.sub(/^Backup::Errors::/, '')
106
76
  end
107
77
 
108
- def orig_err_msg
109
- return unless @orig_err
110
- return @orig_err_msg unless @orig_err_msg.nil?
78
+ end
111
79
 
112
- msg = @orig_err.is_a?(Errors::Error) ?
113
- @orig_err.send(:orig_msg) : @orig_err.to_s
114
- @orig_err_msg = (msg == orig_err_class) ?
115
- false : format_msg(msg)
116
- end
80
+ class Error < StandardError
81
+ include NestedExceptions
82
+ end
117
83
 
118
- def format_msg(msg)
119
- msg.gsub(/^ */, ' ').strip
120
- end
84
+ class FatalError < Exception
85
+ include NestedExceptions
121
86
  end
122
87
 
123
88
  end
data/lib/backup/model.rb CHANGED
@@ -34,35 +34,35 @@ module Backup
34
34
  attr_reader :label
35
35
 
36
36
  ##
37
- # The databases attribute holds an array of database objects
37
+ # Array of configured Database objects.
38
38
  attr_reader :databases
39
39
 
40
40
  ##
41
- # The archives attr_accessor holds an array of archive objects
41
+ # Array of configured Archive objects.
42
42
  attr_reader :archives
43
43
 
44
44
  ##
45
- # The notifiers attr_accessor holds an array of notifier objects
45
+ # Array of configured Notifier objects.
46
46
  attr_reader :notifiers
47
47
 
48
48
  ##
49
- # The storages attribute holds an array of storage objects
49
+ # Array of configured Storage objects.
50
50
  attr_reader :storages
51
51
 
52
52
  ##
53
- # The syncers attribute holds an array of syncer objects
53
+ # Array of configured Syncer objects.
54
54
  attr_reader :syncers
55
55
 
56
56
  ##
57
- # Holds the configured Compressor
57
+ # The configured Compressor, if any.
58
58
  attr_reader :compressor
59
59
 
60
60
  ##
61
- # Holds the configured Encryptor
61
+ # The configured Encryptor, if any.
62
62
  attr_reader :encryptor
63
63
 
64
64
  ##
65
- # Holds the configured Splitter
65
+ # The configured Splitter, if any.
66
66
  attr_reader :splitter
67
67
 
68
68
  ##
@@ -74,17 +74,31 @@ module Backup
74
74
  attr_reader :time
75
75
 
76
76
  ##
77
- # Takes a trigger, label and the configuration block.
78
- # After the instance has evaluated the configuration block
79
- # to configure the model, it will be appended to Model.all
77
+ # Result of this model's backup process.
78
+ #
79
+ # 0 = Job was successful
80
+ # 1 = Job was successful, but issued warnings
81
+ # 2 = Job failed, additional triggers may be performed
82
+ # 3 = Job failed, additional triggers will not be performed
83
+ attr_reader :exit_status
84
+
85
+ ##
86
+ # Exception raised by either a +before+ hook or one of the model's
87
+ # procedures that caused the model to fail. An exception raised by an
88
+ # +after+ hook would not be stored here. Therefore, it is possible for
89
+ # this to be +nil+ even if #exit_status is 2 or 3.
90
+ attr_reader :exception
91
+
80
92
  def initialize(trigger, label, &block)
81
93
  @trigger = trigger.to_s
82
94
  @label = label.to_s
83
95
  @package = Package.new(self)
84
96
 
85
- procedure_instance_variables.each do |variable|
86
- instance_variable_set(variable, Array.new)
87
- end
97
+ @databases = []
98
+ @archives = []
99
+ @storages = []
100
+ @notifiers = []
101
+ @syncers = []
88
102
 
89
103
  instance_eval(&block) if block_given?
90
104
 
@@ -96,31 +110,27 @@ module Backup
96
110
  end
97
111
 
98
112
  ##
99
- # Adds an archive to the array of archives
100
- # to store during the backup process
113
+ # Adds an Archive. Multiple Archives may be added to the model.
101
114
  def archive(name, &block)
102
115
  @archives << Archive.new(self, name, &block)
103
116
  end
104
117
 
105
118
  ##
106
- # Adds a database to the array of databases
107
- # to dump during the backup process
119
+ # Adds an Database. Multiple Databases may be added to the model.
108
120
  def database(name, database_id = nil, &block)
109
121
  @databases << get_class_from_scope(Database, name).
110
122
  new(self, database_id, &block)
111
123
  end
112
124
 
113
125
  ##
114
- # Adds a storage method to the array of storage
115
- # methods to use during the backup process
126
+ # Adds an Storage. Multiple Storages may be added to the model.
116
127
  def store_with(name, storage_id = nil, &block)
117
128
  @storages << get_class_from_scope(Storage, name).
118
129
  new(self, storage_id, &block)
119
130
  end
120
131
 
121
132
  ##
122
- # Adds a syncer method to the array of syncer
123
- # methods to use during the backup process
133
+ # Adds an Syncer. Multiple Syncers may be added to the model.
124
134
  def sync_with(name, syncer_id = nil, &block)
125
135
  ##
126
136
  # Warn user of DSL changes
@@ -147,29 +157,29 @@ module Backup
147
157
  end
148
158
 
149
159
  ##
150
- # Adds a notifier to the array of notifiers
151
- # to use during the backup process
160
+ # Adds an Notifier. Multiple Notifiers may be added to the model.
152
161
  def notify_by(name, &block)
153
162
  @notifiers << get_class_from_scope(Notifier, name).new(self, &block)
154
163
  end
155
164
 
156
165
  ##
157
- # Adds an encryptor to use during the backup process
166
+ # Adds an Encryptor. Only one Encryptor may be added to the model.
167
+ # This will be used to encrypt the final backup package.
158
168
  def encrypt_with(name, &block)
159
169
  @encryptor = get_class_from_scope(Encryptor, name).new(&block)
160
170
  end
161
171
 
162
172
  ##
163
- # Adds a compressor to use during the backup process
173
+ # Adds an Compressor. Only one Compressor may be added to the model.
174
+ # This will be used to compress each individual Archive and Database
175
+ # stored within the final backup package.
164
176
  def compress_with(name, &block)
165
177
  @compressor = get_class_from_scope(Compressor, name).new(&block)
166
178
  end
167
179
 
168
180
  ##
169
- # Adds a method that allows the user to configure this backup model
170
- # to use a Splitter, with the given +chunk_size+
171
- # The +chunk_size+ (in megabytes) will later determine
172
- # in how many chunks the backup needs to be split into
181
+ # Adds a Splitter with the given +chunk_size+ in MB.
182
+ # This will split the final backup package into multiple files.
173
183
  def split_into_chunks_of(chunk_size)
174
184
  if chunk_size.is_a?(Integer)
175
185
  @splitter = Splitter.new(self, chunk_size)
@@ -182,79 +192,97 @@ module Backup
182
192
  end
183
193
 
184
194
  ##
185
- # Performs the backup process
186
- ##
187
- # [Databases]
188
- # Runs all (if any) database objects to dump the databases
189
- ##
190
- # [Archives]
191
- # Runs all (if any) archive objects to package all their
192
- # paths in to a single tar file and places it in the backup folder
193
- ##
194
- # [Packaging]
195
- # After all the database dumps and archives are placed inside
196
- # the folder, it'll make a single .tar package (archive) out of it
197
- ##
198
- # [Encryption]
199
- # Optionally encrypts the packaged file with the configured encryptor
200
- ##
201
- # [Compression]
202
- # Optionally compresses the each Archive and Database dump with the configured compressor
203
- ##
204
- # [Splitting]
205
- # Optionally splits the backup file in to multiple smaller chunks before transferring them
206
- ##
207
- # [Storages]
208
- # Runs all (if any) storage objects to store the backups to remote locations
209
- # and (if configured) it'll cycle the files on the remote location to limit the
210
- # amount of backups stored on each individual location
211
- ##
212
- # [Syncers]
213
- # Runs all (if any) sync objects to store the backups to remote locations.
214
- # A Syncer does not go through the process of packaging, compressing, encrypting backups.
215
- # A Syncer directly transfers data from the filesystem to the remote location
195
+ # Defines a block of code to run before the model's procedures.
196
+ #
197
+ # Warnings logged within the before hook will elevate the model's
198
+ # exit_status to 1 and cause warning notifications to be sent.
199
+ #
200
+ # Raising an exception will abort the model and cause failure notifications
201
+ # to be sent. If the exception is a StandardError, exit_status will be 2.
202
+ # If the exception is not a StandardError, exit_status will be 3.
203
+ #
204
+ # If any exception is raised, any defined +after+ hook will be skipped.
205
+ def before(&block)
206
+ @before ||= block
207
+ end
208
+
216
209
  ##
217
- # [Notifiers]
218
- # Runs all (if any) notifier objects when a backup proces finished with or without
219
- # any errors.
210
+ # Defines a block of code to run after the model's procedures.
211
+ #
212
+ # This code is ensured to run, even if the model failed, **unless** a
213
+ # +before+ hook raised an exception and aborted the model.
214
+ #
215
+ # The code block will be passed the model's current exit_status:
216
+ #
217
+ # `0`: Success, no warnings.
218
+ # `1`: Success, but warnings were logged.
219
+ # `2`: Failure, but additional models/triggers will still be processed.
220
+ # `3`: Failure, no additional models/triggers will be processed.
221
+ #
222
+ # The model's exit_status may be elevated based on the after hook's
223
+ # actions, but will never be decreased.
224
+ #
225
+ # Warnings logged within the after hook may elevate the model's
226
+ # exit_status to 1 and cause warning notifications to be sent.
227
+ #
228
+ # Raising an exception may elevate the model's exit_status and cause
229
+ # failure notifications to be sent. If the exception is a StandardError,
230
+ # the exit_status will be elevated to 2. If the exception is not a
231
+ # StandardError, the exit_status will be elevated to 3.
232
+ def after(&block)
233
+ @after ||= block
234
+ end
235
+
220
236
  ##
221
- # [Cleaning]
222
- # Once the final Packaging is complete, the temporary folder used will be removed.
223
- # Then, once all Storages have run, the final packaged files will be removed.
224
- # If any errors occur during the backup process, all temporary files will be left in place.
225
- # If the error occurs before Packaging, then the temporary folder (tmp_path/trigger)
226
- # will remain and may contain all or some of the configured Archives and/or Database dumps.
227
- # If the error occurs after Packaging, but before the Storages complete, then the final
237
+ # Performs the backup process
238
+ #
239
+ # Once complete, #exit_status will indicate the result of this process.
240
+ #
241
+ # If any errors occur during the backup process, all temporary files will
242
+ # be left in place. If the error occurs before Packaging, then the
243
+ # temporary folder (tmp_path/trigger) will remain and may contain all or
244
+ # some of the configured Archives and/or Database dumps. If the error
245
+ # occurs after Packaging, but before the Storages complete, then the final
228
246
  # packaged files (located in the root of tmp_path) will remain.
229
- # *** Important *** If an error occurs and any of the above mentioned temporary files remain,
230
- # those files *** will be removed *** before the next scheduled backup for the same trigger.
231
247
  #
248
+ # *** Important ***
249
+ # If an error occurs and any of the above mentioned temporary files remain,
250
+ # those files *** will be removed *** before the next scheduled backup for
251
+ # the same trigger.
232
252
  def perform!
233
253
  @started_at = Time.now
234
254
  @time = package.time = @started_at.strftime("%Y.%m.%d.%H.%M.%S")
235
- log!(:started)
236
255
 
237
- prepare!
256
+ log!(:started)
257
+ before_hook
238
258
 
239
- if databases.any? or archives.any?
240
- procedures.each do |procedure|
241
- (procedure.call; next) if procedure.is_a?(Proc)
242
- procedure.each(&:perform!)
243
- end
259
+ procedures.each do |procedure|
260
+ procedure.is_a?(Proc) ? procedure.call : procedure.each(&:perform!)
244
261
  end
245
262
 
246
263
  syncers.each(&:perform!)
247
- notifiers.each(&:perform!)
248
- log!(:finished)
249
264
 
250
265
  rescue Exception => err
251
- log!(:failure, err)
252
- send_failure_notifications
253
- exit(3) unless err.is_a?(StandardError)
266
+ @exception = err
267
+
268
+ ensure
269
+ set_exit_status
270
+ log!(:finished)
271
+ after_hook
254
272
  end
255
273
 
256
274
  private
257
275
 
276
+ ##
277
+ # Returns an array of procedures that will be performed if any
278
+ # Archives or Databases are configured for the model.
279
+ def procedures
280
+ return [] unless databases.any? || archives.any?
281
+
282
+ [lambda { prepare! }, databases, archives,
283
+ lambda { package! }, storages, lambda { clean! }]
284
+ end
285
+
258
286
  ##
259
287
  # Clean any temporary files and/or package files left over
260
288
  # from the last time this model/trigger was performed.
@@ -280,18 +308,6 @@ module Backup
280
308
  Cleaner.remove_package(package)
281
309
  end
282
310
 
283
- ##
284
- # Returns an array of procedures
285
- def procedures
286
- [databases, archives, lambda { package! }, storages, lambda { clean! }]
287
- end
288
-
289
- ##
290
- # Returns an Array of the names (String) of the procedure instance variables
291
- def procedure_instance_variables
292
- [:@databases, :@archives, :@storages, :@notifiers, :@syncers]
293
- end
294
-
295
311
  ##
296
312
  # Returns the class/model specified by +name+ inside of +scope+.
297
313
  # +scope+ should be a Class/Module.
@@ -319,43 +335,84 @@ module Backup
319
335
  end
320
336
 
321
337
  ##
322
- # Logs messages when the backup starts, finishes or fails
323
- def log!(action, exception = nil)
338
+ # Sets or updates the model's #exit_status.
339
+ def set_exit_status
340
+ @exit_status = if exception
341
+ exception.is_a?(StandardError) ? 2 : 3
342
+ else
343
+ Logger.has_warnings? ? 1 : 0
344
+ end
345
+ end
346
+
347
+ ##
348
+ # Runs the +before+ hook.
349
+ # Any exception raised will be wrapped and re-raised, where it will be
350
+ # handled by #perform the same as an exception raised while performing
351
+ # the model's #procedures. Only difference is that an exception raised
352
+ # here will prevent any +after+ hook from being run.
353
+ def before_hook
354
+ return unless before
355
+
356
+ Logger.info 'Before Hook Starting...'
357
+ before.call
358
+ Logger.info 'Before Hook Finished.'
359
+
360
+ rescue Exception => err
361
+ @before_hook_failed = true
362
+ ex = err.is_a?(StandardError) ?
363
+ Errors::Model::HookError : Errors::Model::HookFatalError
364
+ raise ex.wrap(err, 'Before Hook Failed!')
365
+ end
366
+
367
+ ##
368
+ # Runs the +after+ hook.
369
+ # Any exception raised here will be logged only and the model's
370
+ # #exit_status will be elevated if neccessary.
371
+ def after_hook
372
+ return unless after && !@before_hook_failed
373
+
374
+ Logger.info 'After Hook Starting...'
375
+ after.call(exit_status)
376
+ Logger.info 'After Hook Finished.'
377
+
378
+ set_exit_status # in case hook logged warnings
379
+
380
+ rescue Exception => err
381
+ fatal = !err.is_a?(StandardError)
382
+ ex = fatal ? Errors::Model::HookFatalError : Errors::Model::HookError
383
+ Logger.error ex.wrap(err, 'After Hook Failed!')
384
+ # upgrade exit_status if needed
385
+ (@exit_status = fatal ? 3 : 2) unless exit_status == 3
386
+ end
387
+
388
+ ##
389
+ # Logs messages when the model starts and finishes.
390
+ #
391
+ # #exception will be set here if #exit_status is > 1,
392
+ # since log(:finished) is called before the +after+ hook.
393
+ def log!(action)
324
394
  case action
325
395
  when :started
326
- Logger.info "Performing Backup for '#{label} (#{trigger})'!\n" +
396
+ Logger.info "Performing Backup for '#{ label } (#{ trigger })'!\n" +
327
397
  "[ backup #{ VERSION } : #{ RUBY_DESCRIPTION } ]"
328
398
 
329
399
  when :finished
330
- msg = "Backup for '#{ label } (#{ trigger })' " +
331
- "Completed %s in #{ elapsed_time }"
332
- if Logger.has_warnings?
333
- Logger.warn msg % 'Successfully (with Warnings)'
334
- else
335
- Logger.info msg % 'Successfully'
336
- end
337
-
338
- when :failure
339
- err = Errors::ModelError.wrap(exception, <<-EOS)
340
- Backup for #{label} (#{trigger}) Failed!
341
- An Error occured which has caused this Backup to abort before completion.
342
- EOS
343
- Logger.error err
344
- Logger.error "\nBacktrace:\n\s\s" + err.backtrace.join("\n\s\s") + "\n\n"
400
+ if exit_status > 1
401
+ ex = exit_status == 2 ? Errors::ModelError : Errors::ModelFatalError
402
+ err = ex.wrap(exception, "Backup for #{ label } (#{ trigger }) Failed!")
403
+ Logger.error err
404
+ Logger.error "\nBacktrace:\n\s\s" + err.backtrace.join("\n\s\s") + "\n\n"
345
405
 
346
- Cleaner.warnings(self)
347
-
348
- if exception.is_a?(StandardError)
349
- Logger.info Errors::ModelError.new(<<-EOS)
350
- If you have other Backup jobs (triggers) configured to run,
351
- Backup will now attempt to continue...
352
- EOS
406
+ Cleaner.warnings(self)
353
407
  else
354
- Logger.error Errors::ModelError.new(<<-EOS)
355
- This Error was Fatal and Backup will now exit.
356
- If you have other Backup jobs (triggers) configured to run,
357
- they will not be processed.
358
- EOS
408
+ msg = "Backup for '#{ label } (#{ trigger })' "
409
+ if exit_status == 1
410
+ msg << "Completed Successfully (with Warnings) in #{ elapsed_time }"
411
+ Logger.warn msg
412
+ else
413
+ msg << "Completed Successfully in #{ elapsed_time }"
414
+ Logger.info msg
415
+ end
359
416
  end
360
417
  end
361
418
  end
@@ -371,21 +428,5 @@ module Backup
371
428
  '%02d:%02d:%02d' % [hours, minutes, seconds]
372
429
  end
373
430
 
374
- ##
375
- # Sends notifications when a backup fails.
376
- # Errors are logged and rescued, since the error that caused the
377
- # backup to fail could have been an error with a notifier.
378
- def send_failure_notifications
379
- notifiers.each do |n|
380
- begin
381
- n.perform!(true)
382
- rescue Exception => err
383
- Logger.error Errors::ModelError.wrap(err, <<-EOS)
384
- #{ n.class } Failed to send notification of backup failure.
385
- EOS
386
- end
387
- end
388
- end
389
-
390
431
  end
391
432
  end