do_snapshot 0.2.2 → 0.3.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.
@@ -2,99 +2,82 @@
2
2
  require 'date'
3
3
  require 'pony'
4
4
  require_relative 'core_ext/hash'
5
- require_relative 'log'
5
+ require_relative 'helpers'
6
6
 
7
7
  module DoSnapshot
8
8
  # Shared mailer.
9
9
  #
10
- module Mail
11
- def mailer
12
- UniversalMailer
13
- end
10
+ class Mail
11
+ include DoSnapshot::Helpers
14
12
 
15
- # UniversalMailer is module to deal with singleton methods.
16
- # Used to give classes access only for selected methods
17
- #
18
- module UniversalMailer
19
- module_function
13
+ attr_writer :mailer, :opts_default, :smtp_default
20
14
 
21
- def notify
22
- Mail.notify
23
- end
15
+ def initialize(options = {})
16
+ options.each { |key, option| send("#{key}=", option) }
24
17
  end
25
18
 
26
- class << self
27
- include DoSnapshot::Log
28
-
29
- attr_writer :mailer, :opts_default, :smtp_default
30
-
31
- def load_options(options = {})
32
- options.each { |key, option| send("#{key}=", option) }
33
- end
34
-
35
- def reset_options
36
- @opts = opts_default
37
- @smtp = smtp_default
38
- end
19
+ def reset_options
20
+ @opts = opts_default
21
+ @smtp = smtp_default
22
+ end
39
23
 
40
- def mailer
41
- @mailer ||= Pony.method(:mail)
42
- end
24
+ def mailer
25
+ @mailer ||= Pony.method(:mail)
26
+ end
43
27
 
44
- def smtp
45
- @smtp ||= smtp_default.dup
46
- end
28
+ def smtp
29
+ @smtp ||= smtp_default.dup
30
+ end
47
31
 
48
- def opts
49
- @opts ||= opts_default.dup
50
- end
32
+ def opts
33
+ @opts ||= opts_default.dup
34
+ end
51
35
 
52
- def smtp=(options)
53
- options.each_pair do |key, value|
54
- smtp[key.to_sym] = value
55
- end if options
56
- end
36
+ def smtp=(options)
37
+ options.each_pair do |key, value|
38
+ smtp[key.to_sym] = value
39
+ end if options
40
+ end
57
41
 
58
- def opts=(options)
59
- options.each_pair do |key, value|
60
- opts[key.to_sym] = value
61
- end if options
62
- end
42
+ def opts=(options)
43
+ options.each_pair do |key, value|
44
+ opts[key.to_sym] = value
45
+ end if options
46
+ end
63
47
 
64
- # Sending message via Hash params.
65
- #
66
- # Options:: --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
67
- #
68
- def notify
69
- setup_notify
70
- log.debug 'Sending e-mail notification.'
71
- # Look into your inbox :)
72
- mailer.call(opts)
73
- end
48
+ # Sending message via Hash params.
49
+ #
50
+ # Options:: --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
51
+ #
52
+ def notify
53
+ setup_notify
54
+ logger.debug 'Sending e-mail notification.'
55
+ # Look into your inbox :)
56
+ mailer.call(opts)
57
+ end
74
58
 
75
- protected
59
+ protected
76
60
 
77
- def opts_default
78
- @opts_default ||= {
79
- subject: 'Digital Ocean: maximum snapshots is reached.',
80
- body: "Please cleanup your Digital Ocean account.\nSnapshot maximum is reached.",
81
- from: 'noreply@someonelse.com',
82
- to: 'to@someonelse.com',
83
- via: :smtp
84
- }
85
- end
61
+ def opts_default
62
+ @opts_default ||= {
63
+ subject: 'Digital Ocean: maximum snapshots is reached.',
64
+ body: "Please cleanup your Digital Ocean account.\nSnapshot maximum is reached.",
65
+ from: 'noreply@someonelse.com',
66
+ to: 'to@someonelse.com',
67
+ via: :smtp
68
+ }
69
+ end
86
70
 
87
- def smtp_default
88
- @smtp_default ||= {
89
- domain: 'localhost.localdomain',
90
- port: '25'
91
- }
92
- end
71
+ def smtp_default
72
+ @smtp_default ||= {
73
+ domain: 'localhost.localdomain',
74
+ port: '25'
75
+ }
76
+ end
93
77
 
94
- def setup_notify
95
- opts[:body] = "#{opts[:body]}\n\nTrace: #{DateTime.now}\n#{Log.buffer.join("\n")}"
96
- opts[:via_options] = smtp
97
- end
78
+ def setup_notify
79
+ opts[:body] = "#{opts[:body]}\n\nTrace: #{DateTime.now}\n#{DoSnapshot.logger.buffer.join("\n")}"
80
+ opts[:via_options] = smtp
98
81
  end
99
82
  end
100
83
  end
@@ -0,0 +1,59 @@
1
+ require 'do_snapshot/cli'
2
+
3
+ module DoSnapshot
4
+ # CLI Runner
5
+ #
6
+ class Runner
7
+ def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
8
+ @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
9
+ end
10
+
11
+ def execute! # rubocop:disable Metrics/MethodLength
12
+ exit_code = begin
13
+ run_cli
14
+ rescue DoSnapshot::NoTokenError, DoSnapshot::NoKeysError => _
15
+ do_nothing_on_shown_error
16
+ rescue StandardError => e
17
+ display_backtrace_otherwise(e)
18
+ rescue SystemExit => e
19
+ e.status
20
+ ensure
21
+ clean_before_exit
22
+ end
23
+
24
+ @kernel.exit(exit_code)
25
+ end
26
+
27
+ private
28
+
29
+ def run_cli
30
+ $stderr = @stderr
31
+ $stdin = @stdin
32
+ $stdout = @stdout
33
+
34
+ DoSnapshot::CLI.start(@argv)
35
+
36
+ 0
37
+ end
38
+
39
+ def do_nothing_on_shown_error
40
+ clean_before_exit
41
+ 1
42
+ end
43
+
44
+ def display_backtrace_otherwise(e)
45
+ b = e.backtrace
46
+ @stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
47
+ @stderr.puts(b.map { |s| "\tfrom #{s}" }.join("\n"))
48
+ 1
49
+ end
50
+
51
+ def clean_before_exit
52
+ DoSnapshot.cleanup
53
+
54
+ $stderr = STDERR
55
+ $stdin = STDIN
56
+ $stdout = STDOUT
57
+ end
58
+ end
59
+ end
@@ -2,5 +2,5 @@
2
2
  # Current version
3
3
  #
4
4
  module DoSnapshot
5
- VERSION = '0.2.2'
5
+ VERSION = '0.3.0'
6
6
  end
data/lib/do_snapshot.rb CHANGED
@@ -1,13 +1,46 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  require_relative 'do_snapshot/version'
3
+ require_relative 'do_snapshot/configuration'
3
4
 
4
5
  # Used primary for creating snapshot's as backups for DigitalOcean
5
6
  #
6
7
  module DoSnapshot
8
+ class << self
9
+ attr_accessor :logger, :mailer
10
+
11
+ def configure
12
+ yield(config)
13
+ end
14
+
15
+ def reconfigure
16
+ @config = Configuration.new
17
+ yield(config)
18
+ end
19
+
20
+ def config
21
+ @config ||= Configuration.new
22
+ end
23
+
24
+ def cleanup
25
+ logger.close if logger
26
+ @logger = nil
27
+ @mailer = nil
28
+ @config = nil
29
+ end
30
+ end
31
+
7
32
  # Standard Request Exception. When we don't need droplet instance id.
8
33
  #
9
34
  class RequestError < StandardError; end
10
35
 
36
+ # Every call must have keys in environment or via params.
37
+ #
38
+ class NoKeysError < StandardError; end
39
+
40
+ # Every call must have token in environment or via params.
41
+ #
42
+ class NoTokenError < StandardError; end
43
+
11
44
  # Base Exception for cases when we need id for log and/or something actions.
12
45
  #
13
46
  class RequestActionError < RequestError
@@ -22,7 +55,7 @@ module DoSnapshot
22
55
  #
23
56
  class DropletShutdownError < RequestActionError
24
57
  def initialize(*args)
25
- Log.log :error, "Droplet id: #{args[0]} is Failed to Power Off."
58
+ DoSnapshot.logger.error "Droplet id: #{args[0]} is Failed to Power Off."
26
59
  super
27
60
  end
28
61
  end
@@ -32,7 +65,7 @@ module DoSnapshot
32
65
  #
33
66
  class SnapshotCreateError < RequestActionError
34
67
  def initialize(*args)
35
- Log.log :error, "Droplet id: #{args[0]} is Failed to Snapshot."
68
+ DoSnapshot.logger.error "Droplet id: #{args[0]} is Failed to Snapshot."
36
69
  super
37
70
  end
38
71
  end
@@ -42,7 +75,7 @@ module DoSnapshot
42
75
  #
43
76
  class DropletFindError < RequestError
44
77
  def initialize(*args)
45
- Log.log :error, 'Droplet Not Found'
78
+ DoSnapshot.logger.error 'Droplet Not Found'
46
79
  super
47
80
  end
48
81
  end
@@ -52,7 +85,7 @@ module DoSnapshot
52
85
  #
53
86
  class DropletListError < RequestError
54
87
  def initialize(*args)
55
- Log.log :error, 'Droplet Listing is failed to retrieve'
88
+ DoSnapshot.logger.error 'Droplet Listing is failed to retrieve'
56
89
  super
57
90
  end
58
91
  end
@@ -5,7 +5,6 @@ describe DoSnapshot::Adapter::Abstract do
5
5
  include_context 'spec'
6
6
 
7
7
  subject(:api) { described_class }
8
- subject(:log) { DoSnapshot::Log }
9
8
 
10
9
  describe '.initialize' do
11
10
  describe '#delay' do
@@ -20,10 +19,4 @@ describe DoSnapshot::Adapter::Abstract do
20
19
  it('with custom timeout') { expect(instance.timeout).to eq timeout }
21
20
  end
22
21
  end
23
-
24
- before(:each) do
25
- log.buffer = %w()
26
- log.verbose = false
27
- log.quiet = true
28
- end
29
22
  end
@@ -41,7 +41,7 @@ describe DoSnapshot::Adapter::Digitalocean do
41
41
 
42
42
  expect { instance.droplet(droplet_id) }
43
43
  .to raise_error
44
- expect(log.buffer)
44
+ expect(DoSnapshot.logger.buffer)
45
45
  .to include 'Droplet Not Found'
46
46
 
47
47
  expect(a_request(:get, droplet_url))
@@ -63,7 +63,7 @@ describe DoSnapshot::Adapter::Digitalocean do
63
63
  stub_droplets_fail
64
64
 
65
65
  expect { instance.droplets }.to raise_error
66
- expect(log.buffer)
66
+ expect(DoSnapshot.logger.buffer)
67
67
  .to include 'Droplet Listing is failed to retrieve'
68
68
 
69
69
  expect(a_request(:get, droplets_uri))
@@ -77,7 +77,7 @@ describe DoSnapshot::Adapter::Digitalocean do
77
77
  stub_droplet_start(droplet_id)
78
78
 
79
79
  instance.start_droplet(droplet_id)
80
- expect(log.buffer).to include 'Power On has been requested.'
80
+ expect(DoSnapshot.logger.buffer).to include 'Power On has been requested.'
81
81
 
82
82
  expect(a_request(:get, droplet_start_url))
83
83
  .to have_been_made
@@ -90,7 +90,7 @@ describe DoSnapshot::Adapter::Digitalocean do
90
90
 
91
91
  expect { instance.start_droplet(droplet_id) }
92
92
  .not_to raise_error
93
- expect(log.buffer)
93
+ expect(DoSnapshot.logger.buffer)
94
94
  .to include 'Droplet is still running.'
95
95
 
96
96
  expect(a_request(:get, droplet_url))
@@ -126,7 +126,7 @@ describe DoSnapshot::Adapter::Digitalocean do
126
126
 
127
127
  expect { instance.stop_droplet(droplet_id) }
128
128
  .to raise_error
129
- expect(log.buffer)
129
+ expect(DoSnapshot.logger.buffer)
130
130
  .to include 'Droplet id: 100823 is Failed to Power Off.'
131
131
 
132
132
  expect(a_request(:get, droplet_stop_url))
@@ -181,7 +181,7 @@ describe DoSnapshot::Adapter::Digitalocean do
181
181
  droplet = instance.droplet(droplet_id)
182
182
  expect { instance.cleanup_snapshots(droplet, 1) }
183
183
  .not_to raise_error
184
- expect(log.buffer)
184
+ expect(DoSnapshot.logger.buffer)
185
185
  .to include 'Snapshot name: mrcr.ru_2014_07_19 delete requested.'
186
186
 
187
187
  expect(a_request(:get, droplet_url))
@@ -200,7 +200,7 @@ describe DoSnapshot::Adapter::Digitalocean do
200
200
  droplet = instance.droplet(droplet_id)
201
201
  expect { instance.cleanup_snapshots(droplet, 1) }
202
202
  .not_to raise_error
203
- expect(log.buffer)
203
+ expect(DoSnapshot.logger.buffer)
204
204
  .to include 'Some Message'
205
205
 
206
206
  expect(a_request(:get, droplet_url))
@@ -212,10 +212,4 @@ describe DoSnapshot::Adapter::Digitalocean do
212
212
  end
213
213
  end
214
214
  end
215
-
216
- before(:each) do
217
- log.buffer = %w()
218
- log.verbose = false
219
- log.quiet = true
220
- end
221
215
  end
@@ -43,7 +43,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
43
43
 
44
44
  expect { instance.droplet(droplet_id) }
45
45
  .to raise_error
46
- expect(log.buffer)
46
+ expect(DoSnapshot.logger.buffer)
47
47
  .to include 'Droplet Not Found'
48
48
 
49
49
  expect(a_request(:get, droplet_url))
@@ -65,7 +65,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
65
65
  stub_droplets_fail
66
66
 
67
67
  expect { instance.droplets }.to raise_error
68
- expect(log.buffer)
68
+ expect(DoSnapshot.logger.buffer)
69
69
  .to include 'Droplet Listing is failed to retrieve'
70
70
 
71
71
  expect(a_request(:get, droplets_uri))
@@ -79,7 +79,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
79
79
  stub_droplet_start(droplet_id)
80
80
 
81
81
  instance.start_droplet(droplet_id)
82
- expect(log.buffer).to include 'Power On has been requested.'
82
+ expect(DoSnapshot.logger.buffer).to include 'Power On has been requested.'
83
83
 
84
84
  expect(a_request(:post, droplet_start_url))
85
85
  .to have_been_made
@@ -92,7 +92,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
92
92
 
93
93
  expect { instance.start_droplet(droplet_id) }
94
94
  .not_to raise_error
95
- expect(log.buffer)
95
+ expect(DoSnapshot.logger.buffer)
96
96
  .to include 'Droplet is still running.'
97
97
 
98
98
  expect(a_request(:get, droplet_url))
@@ -128,7 +128,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
128
128
 
129
129
  expect { instance.stop_droplet(droplet_id) }
130
130
  .to raise_error
131
- expect(log.buffer)
131
+ expect(DoSnapshot.logger.buffer)
132
132
  .to include 'Droplet id: 100823 is Failed to Power Off.'
133
133
 
134
134
  expect(a_request(:post, droplet_stop_url))
@@ -183,7 +183,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
183
183
  droplet = instance.droplet(droplet_id)
184
184
  expect { instance.cleanup_snapshots(droplet, 1) }
185
185
  .not_to raise_error
186
- expect(log.buffer)
186
+ expect(DoSnapshot.logger.buffer)
187
187
  .to include 'Snapshot: 5019770 delete requested.'
188
188
 
189
189
  expect(a_request(:get, droplet_url))
@@ -202,7 +202,7 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
202
202
  droplet = instance.droplet(droplet_id)
203
203
  expect { instance.cleanup_snapshots(droplet, 1) }
204
204
  .not_to raise_error
205
- expect(log.buffer)
205
+ expect(DoSnapshot.logger.buffer)
206
206
  .to include 'Destroy of snapshot 5019903 for droplet id: 100823 name: example.com is failed.'
207
207
 
208
208
  expect(a_request(:get, droplet_url))
@@ -214,10 +214,4 @@ describe DoSnapshot::Adapter::DigitaloceanV2 do
214
214
  end
215
215
  end
216
216
  end
217
-
218
- before(:each) do
219
- log.buffer = %w()
220
- log.verbose = false
221
- log.quiet = true
222
- end
223
217
  end
@@ -14,7 +14,7 @@ describe DoSnapshot::Command do
14
14
  it 'sends message' do
15
15
  expect { snap_runner }
16
16
  .not_to raise_error
17
- expect(log.buffer)
17
+ expect(DoSnapshot.logger.buffer)
18
18
  .to include 'All operations has been finished.'
19
19
  end
20
20
  end
@@ -108,7 +108,7 @@ describe DoSnapshot::Command do
108
108
 
109
109
  expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
110
110
  .not_to raise_error
111
- expect(log.buffer)
111
+ expect(DoSnapshot.logger.buffer)
112
112
  .to include 'Power On has been requested.'
113
113
  end
114
114
 
@@ -117,9 +117,9 @@ describe DoSnapshot::Command do
117
117
 
118
118
  expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
119
119
  .to raise_error
120
- expect(log.buffer)
120
+ expect(DoSnapshot.logger.buffer)
121
121
  .to include 'Droplet id: 100823 is Failed to Power Off.'
122
- expect(log.buffer)
122
+ expect(DoSnapshot.logger.buffer)
123
123
  .to include 'Droplet Not Found'
124
124
  end
125
125
 
@@ -130,16 +130,16 @@ describe DoSnapshot::Command do
130
130
 
131
131
  expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
132
132
  .not_to raise_error
133
- expect(log.buffer)
133
+ expect(DoSnapshot.logger.buffer)
134
134
  .to include 'Power On failed to request.'
135
135
  end
136
136
  end
137
137
 
138
138
  before(:each) do
139
139
  stub_all_api(nil, true)
140
- log.buffer = %w()
141
- log.verbose = false
142
- log.quiet = true
140
+ DoSnapshot.logger.buffer = %w()
141
+ DoSnapshot.logger.verbose = false
142
+ DoSnapshot.logger.quiet = true
143
143
  end
144
144
 
145
145
  def load_options(options = nil)
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe DoSnapshot::Configuration do
4
+ subject(:cli) { described_class }
5
+
6
+ it { expect(cli.new).to respond_to(:logger) }
7
+ it { expect(cli.new).to respond_to(:logger_level) }
8
+ it { expect(cli.new).to respond_to(:verbose) }
9
+ it { expect(cli.new).to respond_to(:quiet) }
10
+ it { expect(cli.new).to respond_to(:mailer) }
11
+ end
@@ -0,0 +1,88 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe DoSnapshot::Log do
5
+ include_context 'spec'
6
+
7
+ subject(:log) { described_class }
8
+
9
+ describe 'will have message' do
10
+ it '#info' do
11
+ expect(DoSnapshot.logger).to respond_to(:info)
12
+ DoSnapshot.logger.info('fff')
13
+ expect(DoSnapshot.logger.buffer).to include('fff')
14
+ end
15
+
16
+ it '#debug' do
17
+ expect(DoSnapshot.logger).to respond_to(:debug)
18
+ DoSnapshot.logger.info('fff')
19
+ expect(DoSnapshot.logger.buffer).to include('fff')
20
+ end
21
+
22
+ it '#warn' do
23
+ expect(DoSnapshot.logger).to respond_to(:warn)
24
+ DoSnapshot.logger.info('fff')
25
+ expect(DoSnapshot.logger.buffer).to include('fff')
26
+ end
27
+
28
+ it '#fatal' do
29
+ expect(DoSnapshot.logger).to respond_to(:fatal)
30
+ DoSnapshot.logger.info('fff')
31
+ expect(DoSnapshot.logger.buffer).to include('fff')
32
+ end
33
+
34
+ it '#error' do
35
+ expect(DoSnapshot.logger).to respond_to(:error)
36
+ DoSnapshot.logger.info('fff')
37
+ expect(DoSnapshot.logger.buffer).to include('fff')
38
+ end
39
+
40
+ it '#blablabla' do
41
+ expect(DoSnapshot.logger).not_to respond_to(:blablabla)
42
+ end
43
+
44
+ before :each do
45
+ DoSnapshot.configure do |config|
46
+ config.logger = Logger.new(log_path)
47
+ config.verbose = true
48
+ config.quiet = true
49
+ end
50
+ DoSnapshot.logger = DoSnapshot::Log.new
51
+ end
52
+ end
53
+
54
+ describe 'will work with files' do
55
+ it 'with file' do
56
+ FileUtils.remove_file(log_path, true)
57
+
58
+ DoSnapshot.configure do |config|
59
+ config.logger = Logger.new(log_path)
60
+ config.verbose = true
61
+ config.quiet = true
62
+ end
63
+ DoSnapshot.logger = DoSnapshot::Log.new
64
+
65
+ expect(File.exist?(log_path)).to be_truthy
66
+ end
67
+
68
+ it 'with no file' do
69
+ FileUtils.remove_file(log_path, true)
70
+
71
+ DoSnapshot.logger = DoSnapshot::Log.new
72
+
73
+ expect(File.exist?(log_path)).to be_falsey
74
+ end
75
+
76
+ it 'with no file but logging' do
77
+ FileUtils.remove_file(log_path, true)
78
+
79
+ DoSnapshot.logger = DoSnapshot::Log.new
80
+
81
+ expect(File.exist?(log_path)).to be_falsey
82
+
83
+ expect(DoSnapshot.logger).to respond_to(:info)
84
+ DoSnapshot.logger.info('fff')
85
+ expect(DoSnapshot.logger.buffer).to include('fff')
86
+ end
87
+ end
88
+ end
@@ -4,12 +4,26 @@ require 'spec_helper'
4
4
  describe DoSnapshot::Mail do
5
5
  include_context 'spec'
6
6
 
7
+ subject(:mail) { described_class }
8
+
7
9
  describe 'will send mail with options' do
8
10
  it '#notify' do
9
- DoSnapshot::Mail.reset_options
10
- DoSnapshot::Mail.load_options(opts: mail_options, smtp: smtp_options)
11
- expect { DoSnapshot::Mail.notify }.not_to raise_error
12
- expect(DoSnapshot::Mail.smtp[:address]).to eq(smtp_options[:address])
11
+ mail = DoSnapshot.mailer.notify
12
+ expect(mail).not_to be_falsey
13
+ expect(mail.delivery_method.settings[:address]).to eq(smtp_options[:address])
14
+ expect(mail.delivery_method.settings[:port]).to eq(smtp_options[:port])
15
+ expect(mail.delivery_method.settings[:user_name]).to eq(smtp_options[:user_name])
16
+ expect(mail.delivery_method.settings[:password]).to eq(smtp_options[:password])
17
+ expect(mail.header.fields).to include(::Mail::Field.new('From', mail_options[:from], 'UTF-8'))
18
+ expect(mail.header.fields).to include(::Mail::Field.new('To', mail_options[:to], 'UTF-8'))
19
+ end
20
+
21
+ before :each do
22
+ DoSnapshot.configure do |config|
23
+ config.mailer = mail.new(opts: mail_options, smtp: smtp_options)
24
+ end
25
+ DoSnapshot.mailer = DoSnapshot.config.mailer
26
+ DoSnapshot.logger = DoSnapshot::Log.new
13
27
  end
14
28
  end
15
29
  end