do_snapshot 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  # Rails symbolize keys methods for Hash
2
3
  #
3
4
  class Hash
@@ -25,12 +26,12 @@ class Hash
25
26
  end
26
27
 
27
28
  def symbolize_keys
28
- transform_keys { |key| key.to_sym rescue key }
29
+ transform_keys { |key| key.to_sym rescue key } # rubocop:disable Style/RescueModifier
29
30
  end
30
31
 
31
32
  # Destructively convert all keys to symbols, as long as they respond
32
33
  # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
33
34
  def symbolize_keys!
34
- transform_keys! { |key| key.to_sym rescue key }
35
+ transform_keys! { |key| key.to_sym rescue key } # rubocop:disable Style/RescueModifier
35
36
  end
36
37
  end
@@ -0,0 +1,59 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'logger'
3
+
4
+ module DoSnapshot
5
+ # Shared logger
6
+ #
7
+ class Log
8
+ class << self
9
+ attr_accessor :logger, :shell, :quiet, :verbose
10
+ attr_writer :buffer
11
+
12
+ def buffer
13
+ @buffer ||= %w()
14
+ end
15
+
16
+ def info(message)
17
+ log :info, message
18
+ end
19
+
20
+ def warning(message)
21
+ log :warn, message
22
+ end
23
+
24
+ def error(message)
25
+ log :error, message
26
+ end
27
+
28
+ def debug(message)
29
+ log :debug, message
30
+ end
31
+
32
+ protected
33
+
34
+ def log(type, message)
35
+ buffer << message
36
+ logger.send(type, message) if logger
37
+
38
+ say message, color(type) unless type == :debug && !verbose
39
+ end
40
+
41
+ def say(message, color)
42
+ shell.say message, color if shell
43
+ end
44
+
45
+ def color(type)
46
+ case type
47
+ when :debug
48
+ :white
49
+ when :error
50
+ :red
51
+ when :warn
52
+ :yellow
53
+ else
54
+ :green
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,70 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'date'
3
+ require 'pony'
4
+ require 'do_snapshot/core_ext/hash'
5
+
6
+ module DoSnapshot
7
+ # Shared mailer.
8
+ #
9
+ class Mail
10
+ class << self
11
+ attr_accessor :opts
12
+ attr_writer :smtp, :opts_default, :smtp_default
13
+
14
+ def smtp
15
+ @smtp ||= {}
16
+ end
17
+
18
+ # Sending message via Hash params.
19
+ #
20
+ # Options:: --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
21
+ #
22
+ def notify
23
+ return unless opts
24
+
25
+ opts.symbolize_keys!
26
+ smtp.symbolize_keys!
27
+
28
+ opts_setup
29
+ smtp_setup
30
+
31
+ Log.debug 'Sending e-mail notification.'
32
+ # Look into your inbox :)
33
+ Pony.mail(opts)
34
+ end
35
+
36
+ protected
37
+
38
+ def opts_default
39
+ @opts_default ||= {
40
+ subject: 'Digital Ocean: maximum snapshots is reached.',
41
+ body: "Please cleanup your Digital Ocean account.\nSnapshot maximum is reached.",
42
+ from: 'noreply@someonelse.com',
43
+ to: 'to@someonelse.com',
44
+ via: :smtp
45
+ }
46
+ end
47
+
48
+ def smtp_default
49
+ @smtp_default ||= {
50
+ domain: 'localhost.localdomain',
51
+ port: '25'
52
+ }
53
+ end
54
+
55
+ def opts_setup
56
+ opts_default.each_pair do |key, value|
57
+ opts[key] = value unless opts.include? key
58
+ end
59
+ opts[:body] = "#{opts[:body]}\n\nTrace: #{DateTime.now}\n#{Log.buffer.join("\n")}"
60
+ end
61
+
62
+ def smtp_setup
63
+ smtp_default.each_pair do |key, value|
64
+ smtp[key] = value unless smtp.include? key
65
+ end
66
+ opts[:via_options] = smtp
67
+ end
68
+ end
69
+ end
70
+ end
@@ -1,5 +1,6 @@
1
+ # -*- encoding : utf-8 -*-
1
2
  # Current version
2
3
  #
3
4
  module DoSnapshot
4
- VERSION = '0.0.6'
5
+ VERSION = '0.0.7'
5
6
  end
data/{test → log}/.keep RENAMED
File without changes
data/spec/.keep ADDED
File without changes
@@ -0,0 +1,218 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe DoSnapshot::API do
5
+ include_context 'spec'
6
+
7
+ subject(:api) { described_class }
8
+ subject(:log) { DoSnapshot::Log }
9
+
10
+ describe '.initialize' do
11
+ describe '#delay' do
12
+ let(:delay) { 5 }
13
+ let(:instance) { api.new(delay: delay) }
14
+ it('with custom delay') { expect(instance.delay).to eq delay }
15
+ end
16
+
17
+ describe '#timeout' do
18
+ let(:timeout) { 5 }
19
+ let(:instance) { api.new(timeout: timeout) }
20
+ it('with custom timeout') { expect(instance.timeout).to eq timeout }
21
+ end
22
+ end
23
+
24
+ describe 'droplets' do
25
+ let(:instance) { api.new(delay: delay, timeout: timeout) }
26
+ include_context 'uri_helpers'
27
+
28
+ describe '.droplet' do
29
+ it 'with droplet' do
30
+ stub_droplet(droplet_id)
31
+
32
+ instance.droplet(droplet_id)
33
+
34
+ expect(a_request(:get, droplet_url))
35
+ .to have_been_made
36
+ end
37
+
38
+ it 'with error' do
39
+ stub_droplet_fail(droplet_id)
40
+
41
+ expect { instance.droplet(droplet_id) }
42
+ .to raise_error
43
+ expect(log.buffer)
44
+ .to include 'Droplet Not Found'
45
+
46
+ expect(a_request(:get, droplet_url))
47
+ .to have_been_made
48
+ end
49
+ end
50
+
51
+ describe '.droplets' do
52
+ it 'with droplets' do
53
+ stub_droplets
54
+
55
+ instance.droplets
56
+
57
+ expect(a_request(:get, droplets_uri))
58
+ .to have_been_made
59
+ end
60
+
61
+ it 'with error' do
62
+ stub_droplets_fail
63
+
64
+ expect { instance.droplets }.to raise_error
65
+ expect(log.buffer)
66
+ .to include 'Droplet Listing is failed to retrieve'
67
+
68
+ expect(a_request(:get, droplets_uri))
69
+ .to have_been_made
70
+ end
71
+ end
72
+
73
+ describe '.start_droplet' do
74
+ it 'with event' do
75
+ stub_droplet_inactive(droplet_id)
76
+ stub_droplet_start(droplet_id)
77
+
78
+ instance.start_droplet(droplet_id)
79
+ expect(log.buffer).to include 'Power On has been requested.'
80
+
81
+ expect(a_request(:get, droplet_start_url))
82
+ .to have_been_made
83
+ expect(a_request(:get, droplet_url))
84
+ .to have_been_made
85
+ end
86
+
87
+ it 'with warning message' do
88
+ stub_droplet(droplet_id)
89
+
90
+ expect { instance.start_droplet(droplet_id) }
91
+ .not_to raise_error
92
+ expect(log.buffer)
93
+ .to include 'Droplet is still running.'
94
+
95
+ expect(a_request(:get, droplet_url))
96
+ .to have_been_made
97
+ end
98
+
99
+ it 'with error' do
100
+ stub_droplet_fail(droplet_id)
101
+
102
+ expect { instance.start_droplet(droplet_id) }
103
+ .to raise_error
104
+
105
+ expect(a_request(:get, droplet_url))
106
+ .to have_been_made
107
+ end
108
+ end
109
+
110
+ describe '.stop_droplet' do
111
+ it 'with event' do
112
+ stub_event_done(event_id)
113
+ stub_droplet_stop(droplet_id)
114
+
115
+ instance.stop_droplet(droplet_id)
116
+
117
+ expect(a_request(:get, droplet_stop_url))
118
+ .to have_been_made
119
+ expect(a_request(:get, event_find_url))
120
+ .to have_been_made
121
+ end
122
+
123
+ it 'with error' do
124
+ stub_droplet_stop_fail(droplet_id)
125
+
126
+ expect { instance.stop_droplet(droplet_id) }
127
+ .to raise_error
128
+ expect(log.buffer)
129
+ .to include 'Droplet id: 100823 is Failed to Power Off.'
130
+
131
+ expect(a_request(:get, droplet_stop_url))
132
+ .to have_been_made
133
+ end
134
+ end
135
+
136
+ describe '.create_snapshot' do
137
+ it 'with success' do
138
+ stub_event_done(event_id)
139
+ stub_droplet_snapshot(droplet_id, snapshot_name)
140
+
141
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
142
+ .not_to raise_error
143
+
144
+ expect(a_request(:get, droplet_snapshot_url))
145
+ .to have_been_made
146
+ expect(a_request(:get, event_find_url))
147
+ .to have_been_made
148
+ end
149
+
150
+ it 'with error' do
151
+ stub_droplet_snapshot_fail(droplet_id, snapshot_name)
152
+
153
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
154
+ .to raise_error
155
+
156
+ expect(a_request(:get, droplet_snapshot_url))
157
+ .to have_been_made
158
+ end
159
+
160
+ it 'with event error' do
161
+ stub_droplet_snapshot(droplet_id, snapshot_name)
162
+ stub_event_fail(event_id)
163
+
164
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
165
+ .to raise_error
166
+
167
+ expect(a_request(:get, droplet_snapshot_url))
168
+ .to have_been_made
169
+ expect(a_request(:get, event_find_url))
170
+ .to have_been_made
171
+ end
172
+ end
173
+
174
+ describe '.cleanup_snapshots' do
175
+ it 'with success' do
176
+ stub_droplet(droplet_id)
177
+ stub_image_destroy(image_id)
178
+ stub_image_destroy(image_id2)
179
+
180
+ droplet = instance.droplet(droplet_id)
181
+ expect { instance.cleanup_snapshots(droplet.droplet, 1) }
182
+ .not_to raise_error
183
+ expect(log.buffer)
184
+ .to include 'Snapshot name: mrcr.ru_2014_07_19 delete requested.'
185
+
186
+ expect(a_request(:get, droplet_url))
187
+ .to have_been_made
188
+ expect(a_request(:get, image_destroy_url))
189
+ .to have_been_made
190
+ expect(a_request(:get, image_destroy2_url))
191
+ .to have_been_made
192
+ end
193
+
194
+ it 'with warning message' do
195
+ stub_droplet(droplet_id)
196
+ stub_image_destroy_fail(image_id)
197
+ stub_image_destroy_fail(image_id2)
198
+
199
+ droplet = instance.droplet(droplet_id)
200
+ expect { instance.cleanup_snapshots(droplet.droplet, 1) }
201
+ .not_to raise_error
202
+ expect(log.buffer)
203
+ .to include 'Some Message'
204
+
205
+ expect(a_request(:get, droplet_url))
206
+ .to have_been_made
207
+ expect(a_request(:get, image_destroy_url))
208
+ .to have_been_made
209
+ expect(a_request(:get, image_destroy2_url))
210
+ .to have_been_made
211
+ end
212
+ end
213
+ end
214
+
215
+ before(:each) do
216
+ log.buffer = %w()
217
+ end
218
+ end
@@ -0,0 +1,173 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe DoSnapshot::CLI do
5
+ include_context 'spec'
6
+
7
+ subject(:cli) { described_class }
8
+ subject(:command) { DoSnapshot::Command }
9
+ subject(:api) { DoSnapshot::API }
10
+
11
+ describe '.snap' do
12
+
13
+ it 'with exclude' do
14
+ excluded_droplets = %w( 100824 )
15
+ stub_all_api(%w(100825 100823))
16
+ hash_attribute_eq_no_stub(exclude: excluded_droplets, only: %w())
17
+
18
+ expect(command.send('exclude'))
19
+ .to eq excluded_droplets
20
+ end
21
+
22
+ it 'with only' do
23
+ selected_droplets = %w( 100823 )
24
+ stub_all_api(selected_droplets)
25
+ hash_attribute_eq_no_stub(only: selected_droplets)
26
+
27
+ expect(command.send('only'))
28
+ .to eq selected_droplets
29
+ end
30
+
31
+ it 'with 1 delay' do
32
+ set_api_attribute(delay: 1, timeout: timeout)
33
+ attribute_eq 'delay', 1
34
+ end
35
+
36
+ it 'with 0 delay' do
37
+ set_api_attribute(delay: 0, timeout: timeout)
38
+ attribute_eq 'delay', 0
39
+ end
40
+
41
+ it 'with custom timeout' do
42
+ set_api_attribute(timeout: 1, delay: delay)
43
+ attribute_eq 'timeout', 1
44
+ end
45
+
46
+ it 'with keep' do
47
+ attribute_eq 'keep', 7
48
+ end
49
+
50
+ it 'with quiet' do
51
+ attribute_eq 'quiet', true
52
+ end
53
+
54
+ it 'with no quiet' do
55
+ attribute_eq 'quiet', false
56
+ end
57
+
58
+ it 'with stop' do
59
+ attribute_eq 'stop', true
60
+ end
61
+
62
+ it 'with no stop' do
63
+ attribute_eq 'stop', false
64
+ end
65
+
66
+ it 'with clean' do
67
+ attribute_eq 'clean', true
68
+ end
69
+
70
+ it 'with no clean' do
71
+ attribute_eq 'clean', false
72
+ end
73
+
74
+ it 'with digital ocean credentials' do
75
+ with_hash_attribute_eq(cli_keys)
76
+ end
77
+
78
+ it 'with no digital ocean credentials' do
79
+ without_hash_attribute_eq(cli_keys)
80
+ end
81
+
82
+ it 'with mail' do
83
+ hash_attribute_eq(mail_options)
84
+ end
85
+
86
+ it 'with no mail' do
87
+ without_hash_attribute_eq(mail_options)
88
+ end
89
+
90
+ it 'with smtp' do
91
+ hash_attribute_eq(smtp_options)
92
+ end
93
+
94
+ it 'with no smtp' do
95
+ without_hash_attribute_eq(smtp_options)
96
+ end
97
+
98
+ it 'with log' do
99
+ hash_attribute_eq(log)
100
+ end
101
+
102
+ it 'with no log' do
103
+ without_hash_attribute_eq(log)
104
+ end
105
+ end
106
+
107
+ describe '.version' do
108
+ it 'shows the correct version' do
109
+ @cli.options = @cli.options.merge(version: true)
110
+ @cli.version
111
+
112
+ expect($stdout.string.chomp)
113
+ .to eq("#{DoSnapshot::VERSION}")
114
+ end
115
+ end
116
+
117
+ describe '.help' do
118
+ it 'shows a help message' do
119
+ @cli.help
120
+ expect($stdout.string)
121
+ .to match('Commands:')
122
+ end
123
+
124
+ it 'shows a help message for specific commands' do
125
+ @cli.help 'snap'
126
+ expect($stdout.string)
127
+ .to match('Usage:')
128
+ end
129
+ end
130
+
131
+ def attribute_eq(name, value)
132
+ stub_all_api
133
+ options = default_options.merge!(:"#{name}" => value)
134
+ @cli.options = @cli.options.merge(options)
135
+ @cli.snap
136
+
137
+ expect(command.send(name))
138
+ .to eq value
139
+ end
140
+
141
+ def hash_attribute_eq(hash)
142
+ stub_all_api
143
+ options = default_options.merge!(hash)
144
+ @cli.options = @cli.options.merge(options)
145
+ @cli.snap
146
+ end
147
+
148
+ def with_hash_attribute_eq(hash)
149
+ hash_attribute_eq hash
150
+ expect(@cli.options)
151
+ .to include(hash)
152
+ end
153
+
154
+ def without_hash_attribute_eq(hash)
155
+ hash_attribute_eq({})
156
+ expect(@cli.options)
157
+ .not_to include(hash)
158
+ end
159
+
160
+ def hash_attribute_eq_no_stub(hash)
161
+ options = default_options.merge!(hash)
162
+ @cli.options = @cli.options.merge(options)
163
+ @cli.snap
164
+ end
165
+
166
+ def set_api_attribute(options = { delay: delay, timeout: timeout }) # rubocop:disable Style/AccessorMethodName
167
+ command.send('api=', api.new(options))
168
+ end
169
+
170
+ after(:each) do
171
+ # stub_cleanup
172
+ end
173
+ end