do_snapshot 0.0.6 → 0.0.7

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.
@@ -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