do_snapshot 0.4.0 → 0.4.1
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 +4 -4
- data/README.md +1 -0
- data/lib/do_snapshot/adapter/abstract.rb +25 -2
- data/lib/do_snapshot/adapter/digitalocean.rb +1 -12
- data/lib/do_snapshot/adapter/digitalocean_v2.rb +1 -12
- data/lib/do_snapshot/cli.rb +4 -1
- data/lib/do_snapshot/command.rb +6 -2
- data/lib/do_snapshot/configuration.rb +1 -1
- data/lib/do_snapshot/runner.rb +5 -1
- data/lib/do_snapshot/version.rb +1 -1
- data/spec/do_snapshot/adapter/abstract_spec.rb +2 -2
- data/spec/do_snapshot/adapter/digitalocean_spec.rb +35 -3
- data/spec/do_snapshot/adapter/digitalocean_v2_spec.rb +34 -3
- data/spec/do_snapshot/cli_spec.rb +8 -0
- data/spec/do_snapshot/command_spec.rb +24 -1
- data/spec/do_snapshot/runner_spec.rb +23 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2f557d0bd09889f074fdc153b9223a55f5866a3
|
4
|
+
data.tar.gz: 07e700c5e6e81e1b32a273204f6f25d4cd60a910
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70b662713abc68a487cabdd8cce90592b746e95e2067d45bd4a148da063456bc3756b1c40ec7d9f4689bc63627ffb3df775ea5a149e2856615f9e8a753ca401a
|
7
|
+
data.tar.gz: b75713e42882ff55dec16ab945dd2246447cde8fd9f9dcdb3abc4e24987b8bf9440a5326ea6bd1f5751f637bcfb4544b751b5307a06fd4fd5b0f3543e1240822
|
data/README.md
CHANGED
@@ -172,6 +172,7 @@ For working mailer you need to set e-mail settings via run options.
|
|
172
172
|
-l, [--log=/Users/someone/.do_snapshot/main.log] # Log file path. By default logging is disabled.
|
173
173
|
-c, [--clean], [--no-clean] # Cleanup snapshots after create. If you have more images than you want to `keep`, older will be deleted.
|
174
174
|
-s, [--stop], [--no-stop] # Stop creating snapshots if maximum is reached.
|
175
|
+
[--stop-by-power], [--no-stop-by-power] # Check if droplet stopped by its power status instead of waiting for event completed state.
|
175
176
|
-v, [--trace], [--no-trace] # Verbose mode.
|
176
177
|
-q, [--quiet], [--no-quiet] # Quiet mode. If don't need any messages in console.
|
177
178
|
[--digital-ocean-access-token=YOURLONGAPITOKEN] # DIGITAL_OCEAN_ACCESS_TOKEN. if you can't use environment.
|
@@ -9,6 +9,7 @@ module DoSnapshot
|
|
9
9
|
include DoSnapshot::Helpers
|
10
10
|
|
11
11
|
attr_accessor :delay, :timeout
|
12
|
+
attr_writer :stop_by
|
12
13
|
|
13
14
|
def initialize(options = {})
|
14
15
|
check_keys
|
@@ -18,12 +19,27 @@ module DoSnapshot
|
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
22
|
+
# Power On request for Droplet
|
23
|
+
#
|
24
|
+
def start_droplet(id)
|
25
|
+
# noinspection RubyResolve
|
26
|
+
instance = droplet(id)
|
27
|
+
|
28
|
+
return power_on(id) unless instance.status.include?('active')
|
29
|
+
|
30
|
+
logger.error "Droplet #{id} is still running. Skipping."
|
31
|
+
end
|
32
|
+
|
21
33
|
protected
|
22
34
|
|
23
35
|
def set_id; end
|
24
36
|
|
25
37
|
def check_keys; end
|
26
38
|
|
39
|
+
def stop_by
|
40
|
+
@stop_by ||= :event_status
|
41
|
+
end
|
42
|
+
|
27
43
|
# Waiting wrapper
|
28
44
|
def wait_wrap(id, message = "Event Id: #{id}", &status_block)
|
29
45
|
logger.debug message
|
@@ -37,8 +53,15 @@ module DoSnapshot
|
|
37
53
|
end
|
38
54
|
|
39
55
|
# Waiting for droplet shutdown
|
40
|
-
def wait_shutdown(droplet_id)
|
41
|
-
|
56
|
+
def wait_shutdown(droplet_id, event_id)
|
57
|
+
case stop_by
|
58
|
+
when :power_status
|
59
|
+
wait_wrap(droplet_id, "Droplet Id: #{droplet_id} shutting down") { |id, time| get_shutdown_status(id, time) }
|
60
|
+
when :event_status
|
61
|
+
wait_event(event_id)
|
62
|
+
else
|
63
|
+
fail 'Please define :stopper method (:droplet_status, :event_status'
|
64
|
+
end
|
42
65
|
end
|
43
66
|
|
44
67
|
def after_cleanup(droplet_id, droplet_name, snapshot, event)
|
@@ -29,17 +29,6 @@ module DoSnapshot
|
|
29
29
|
instance.snapshots
|
30
30
|
end
|
31
31
|
|
32
|
-
# Power On request for Droplet
|
33
|
-
#
|
34
|
-
def start_droplet(id)
|
35
|
-
# noinspection RubyResolve
|
36
|
-
instance = droplet(id)
|
37
|
-
|
38
|
-
return power_on(id) unless instance.status.include? 'active'
|
39
|
-
|
40
|
-
logger.error "Droplet #{id} is still running. Skipping."
|
41
|
-
end
|
42
|
-
|
43
32
|
# Request Power On for droplet
|
44
33
|
#
|
45
34
|
def power_on(id)
|
@@ -62,7 +51,7 @@ module DoSnapshot
|
|
62
51
|
fail event.message unless event.status.include? 'OK'
|
63
52
|
|
64
53
|
# noinspection RubyResolve
|
65
|
-
|
54
|
+
wait_shutdown(id, event.event_id)
|
66
55
|
rescue => e
|
67
56
|
raise DropletShutdownError.new(id), e.message, e.backtrace
|
68
57
|
end
|
@@ -31,17 +31,6 @@ module DoSnapshot
|
|
31
31
|
instance.snapshot_ids
|
32
32
|
end
|
33
33
|
|
34
|
-
# Power On request for Droplet
|
35
|
-
#
|
36
|
-
def start_droplet(id)
|
37
|
-
# noinspection RubyResolve
|
38
|
-
instance = droplet(id)
|
39
|
-
|
40
|
-
return power_on(id) unless instance.status.include?('active')
|
41
|
-
|
42
|
-
logger.error "Droplet #{id} is still running. Skipping."
|
43
|
-
end
|
44
|
-
|
45
34
|
# Request Power On for droplet
|
46
35
|
#
|
47
36
|
def power_on(id)
|
@@ -66,7 +55,7 @@ module DoSnapshot
|
|
66
55
|
fail DropletShutdownError.new(id), response.message unless response.respond_to?(:action)
|
67
56
|
|
68
57
|
# noinspection RubyResolve
|
69
|
-
|
58
|
+
wait_shutdown(id, response.action.id)
|
70
59
|
end
|
71
60
|
|
72
61
|
# Sending event to create snapshot via DigitalOcean API and wait for success
|
data/lib/do_snapshot/cli.rb
CHANGED
@@ -14,7 +14,7 @@ module DoSnapshot
|
|
14
14
|
|
15
15
|
default_task :snap
|
16
16
|
|
17
|
-
map %w( c s create )
|
17
|
+
map %w( c s create ) => :snap
|
18
18
|
map %w( -V ) => :version
|
19
19
|
|
20
20
|
# Overriding Thor method for custom initialization
|
@@ -135,6 +135,9 @@ module DoSnapshot
|
|
135
135
|
type: :boolean,
|
136
136
|
aliases: %w( -s),
|
137
137
|
desc: 'Stop creating snapshots if maximum is reached.'
|
138
|
+
method_option :stop_by_power,
|
139
|
+
type: :boolean,
|
140
|
+
desc: 'Check if droplet stopped by its power status instead of waiting for event completed state.'
|
138
141
|
method_option :trace,
|
139
142
|
type: :boolean,
|
140
143
|
aliases: %w( -v ),
|
data/lib/do_snapshot/command.rb
CHANGED
@@ -92,7 +92,7 @@ module DoSnapshot
|
|
92
92
|
# API launcher
|
93
93
|
#
|
94
94
|
def api
|
95
|
-
@api ||= DoSnapshot::Adapter.api(protocol, delay: delay, timeout: timeout)
|
95
|
+
@api ||= DoSnapshot::Adapter.api(protocol, delay: delay, timeout: timeout, stop_by: stop_by)
|
96
96
|
end
|
97
97
|
|
98
98
|
# Processed droplets
|
@@ -104,7 +104,7 @@ module DoSnapshot
|
|
104
104
|
protected
|
105
105
|
|
106
106
|
attr_accessor :droplets, :exclude, :only
|
107
|
-
attr_accessor :keep, :quiet, :stop, :clean, :timeout, :delay, :protocol
|
107
|
+
attr_accessor :keep, :quiet, :stop, :stop_by_power, :clean, :timeout, :delay, :protocol
|
108
108
|
|
109
109
|
attr_writer :threads, :api
|
110
110
|
|
@@ -116,6 +116,10 @@ module DoSnapshot
|
|
116
116
|
@threads ||= []
|
117
117
|
end
|
118
118
|
|
119
|
+
def stop_by
|
120
|
+
stop_by_power ? :power_status : :event_status
|
121
|
+
end
|
122
|
+
|
119
123
|
# Working with list of droplets.
|
120
124
|
#
|
121
125
|
def work_with_droplets
|
data/lib/do_snapshot/runner.rb
CHANGED
@@ -5,7 +5,11 @@ module DoSnapshot
|
|
5
5
|
#
|
6
6
|
class Runner
|
7
7
|
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
|
8
|
-
@argv
|
8
|
+
@argv = argv
|
9
|
+
@stdin = stdin
|
10
|
+
@stdout = stdout
|
11
|
+
@stderr = stderr
|
12
|
+
@kernel = kernel
|
9
13
|
end
|
10
14
|
|
11
15
|
def execute! # rubocop:disable Metrics/MethodLength
|
data/lib/do_snapshot/version.rb
CHANGED
@@ -10,13 +10,13 @@ RSpec.describe DoSnapshot::Adapter::Abstract do
|
|
10
10
|
describe '#delay' do
|
11
11
|
let(:delay) { 5 }
|
12
12
|
let(:instance) { api.new(delay: delay) }
|
13
|
-
it('with custom delay') { expect(instance.delay).to eq delay
|
13
|
+
it('with custom delay') { expect(instance.delay).to eq delay }
|
14
14
|
end
|
15
15
|
|
16
16
|
describe '#timeout' do
|
17
17
|
let(:timeout) { 5 }
|
18
18
|
let(:instance) { api.new(timeout: timeout) }
|
19
|
-
it('with custom timeout') { expect(instance.timeout).to eq timeout
|
19
|
+
it('with custom timeout') { expect(instance.timeout).to eq timeout }
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -12,13 +12,13 @@ RSpec.describe DoSnapshot::Adapter::Digitalocean do
|
|
12
12
|
describe '#delay' do
|
13
13
|
let(:delay) { 5 }
|
14
14
|
let(:instance) { api.new(delay: delay) }
|
15
|
-
it('with custom delay') { expect(instance.delay).to eq delay
|
15
|
+
it('with custom delay') { expect(instance.delay).to eq delay }
|
16
16
|
end
|
17
17
|
|
18
18
|
describe '#timeout' do
|
19
19
|
let(:timeout) { 5 }
|
20
20
|
let(:instance) { api.new(timeout: timeout) }
|
21
|
-
it('with custom timeout') { expect(instance.timeout).to eq timeout
|
21
|
+
it('with custom timeout') { expect(instance.timeout).to eq timeout }
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -108,7 +108,39 @@ RSpec.describe DoSnapshot::Adapter::Digitalocean do
|
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
|
-
describe '.stop_droplet' do
|
111
|
+
describe '.stop_droplet by power status' do
|
112
|
+
let(:instance) { api.new(delay: delay, timeout: timeout, stop_by: :power_status) }
|
113
|
+
|
114
|
+
it 'with success' do
|
115
|
+
stub_event_done(event_id)
|
116
|
+
stub_droplet_stop(droplet_id)
|
117
|
+
stub_droplet_inactive(droplet_id)
|
118
|
+
|
119
|
+
instance.stop_droplet(droplet_id)
|
120
|
+
|
121
|
+
expect(a_request(:get, droplet_stop_url))
|
122
|
+
.to have_been_made
|
123
|
+
expect(a_request(:get, droplet_url))
|
124
|
+
.to have_been_made
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'with error' do
|
128
|
+
stub_droplet_stop_fail(droplet_id)
|
129
|
+
stub_droplet(droplet_id)
|
130
|
+
|
131
|
+
instance.timeout = 1
|
132
|
+
expect { instance.stop_droplet(droplet_id) }
|
133
|
+
.to raise_error(DoSnapshot::DropletShutdownError)
|
134
|
+
instance.timeout = timeout
|
135
|
+
expect(DoSnapshot.logger.buffer)
|
136
|
+
.to include 'Droplet id: 100823 is Failed to Power Off.'
|
137
|
+
|
138
|
+
expect(a_request(:get, droplet_stop_url))
|
139
|
+
.to have_been_made
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '.stop_droplet by event' do
|
112
144
|
it 'with success' do
|
113
145
|
stub_event_done(event_id)
|
114
146
|
stub_droplet_stop(droplet_id)
|
@@ -14,13 +14,13 @@ RSpec.describe DoSnapshot::Adapter::DigitaloceanV2 do
|
|
14
14
|
describe '#delay' do
|
15
15
|
let(:delay) { 5 }
|
16
16
|
let(:instance) { api.new(delay: delay) }
|
17
|
-
it('with custom delay') { expect(instance.delay).to eq delay
|
17
|
+
it('with custom delay') { expect(instance.delay).to eq delay }
|
18
18
|
end
|
19
19
|
|
20
20
|
describe '#timeout' do
|
21
21
|
let(:timeout) { 5 }
|
22
22
|
let(:instance) { api.new(timeout: timeout) }
|
23
|
-
it('with custom timeout') { expect(instance.timeout).to eq timeout
|
23
|
+
it('with custom timeout') { expect(instance.timeout).to eq timeout }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -110,7 +110,38 @@ RSpec.describe DoSnapshot::Adapter::DigitaloceanV2 do
|
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
113
|
-
describe '.stop_droplet' do
|
113
|
+
describe '.stop_droplet by power status' do
|
114
|
+
let(:instance) { api.new(delay: delay, timeout: timeout, stop_by: :power_status) }
|
115
|
+
|
116
|
+
it 'with success' do
|
117
|
+
stub_event_done(event_id)
|
118
|
+
stub_droplet_stop(droplet_id)
|
119
|
+
stub_droplet_inactive(droplet_id)
|
120
|
+
|
121
|
+
instance.stop_droplet(droplet_id)
|
122
|
+
|
123
|
+
expect(a_request(:post, droplet_stop_url))
|
124
|
+
.to have_been_made
|
125
|
+
expect(a_request(:get, droplet_url))
|
126
|
+
.to have_been_made
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'with error' do
|
130
|
+
stub_droplet_stop_fail(droplet_id)
|
131
|
+
stub_droplet(droplet_id)
|
132
|
+
instance.timeout = 1
|
133
|
+
expect { instance.stop_droplet(droplet_id) }
|
134
|
+
.to raise_error(DoSnapshot::DropletShutdownError)
|
135
|
+
instance.timeout = timeout
|
136
|
+
expect(DoSnapshot.logger.buffer)
|
137
|
+
.to include 'Droplet id: 100823 is Failed to Power Off.'
|
138
|
+
|
139
|
+
expect(a_request(:post, droplet_stop_url))
|
140
|
+
.to have_been_made
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe '.stop_droplet by event' do
|
114
145
|
it 'with success' do
|
115
146
|
stub_event_done(event_id)
|
116
147
|
stub_droplet_stop(droplet_id)
|
@@ -75,6 +75,14 @@ RSpec.describe DoSnapshot::CLI do
|
|
75
75
|
attribute_eq 'stop', false
|
76
76
|
end
|
77
77
|
|
78
|
+
it 'with stop by power' do
|
79
|
+
attribute_eq 'stop_by_power', true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'with stop by event' do
|
83
|
+
attribute_eq 'stop_by_power', false
|
84
|
+
end
|
85
|
+
|
78
86
|
it 'with clean' do
|
79
87
|
attribute_eq 'clean', true
|
80
88
|
end
|
@@ -114,7 +114,30 @@ RSpec.describe DoSnapshot::Command do
|
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
117
|
-
describe '.stop_droplet' do
|
117
|
+
describe '.stop_droplet by power status' do
|
118
|
+
it 'when raised with error' do
|
119
|
+
stub_droplet_stop_fail(droplet_id)
|
120
|
+
load_options(stop_by_power: true)
|
121
|
+
droplet = cmd.api.droplet droplet_id
|
122
|
+
expect { cmd.stop_droplet(droplet) }
|
123
|
+
.not_to raise_error
|
124
|
+
expect(cmd.stop_droplet(droplet))
|
125
|
+
.to be_falsey
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'when stopped' do
|
129
|
+
stub_droplet_inactive(droplet_id)
|
130
|
+
stub_droplet_stop(droplet_id)
|
131
|
+
load_options(stop_by_power: true)
|
132
|
+
droplet = cmd.api.droplet droplet_id
|
133
|
+
expect { cmd.stop_droplet(droplet) }
|
134
|
+
.not_to raise_error
|
135
|
+
expect(cmd.stop_droplet(droplet))
|
136
|
+
.to be_truthy
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '.stop_droplet by event' do
|
118
141
|
it 'when raised with error' do
|
119
142
|
stub_droplet_stop_fail(droplet_id)
|
120
143
|
load_options
|
@@ -109,6 +109,24 @@ RSpec.describe DoSnapshot::Runner, type: :aruba do
|
|
109
109
|
expect(all_stdout).to include(t_snapshot_created(snapshot_name))
|
110
110
|
end
|
111
111
|
|
112
|
+
it 'with stop by power' do
|
113
|
+
attribute_eq 'stop_by_power', true
|
114
|
+
|
115
|
+
expect(last_command).to have_exit_status(0)
|
116
|
+
expect(all_stdout).to include(t_droplet_shutdown)
|
117
|
+
expect(all_stdout).to include(t_wait_until_create)
|
118
|
+
expect(all_stdout).to include(t_snapshot_created(snapshot_name))
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'with stop by event' do
|
122
|
+
attribute_eq 'stop_by_power', false
|
123
|
+
|
124
|
+
expect(last_command).to have_exit_status(0)
|
125
|
+
expect(all_stdout).to include(t_droplet_shutdown)
|
126
|
+
expect(all_stdout).to include(t_wait_until_create)
|
127
|
+
expect(all_stdout).to include(t_snapshot_created(snapshot_name))
|
128
|
+
end
|
129
|
+
|
112
130
|
it 'with clean' do
|
113
131
|
attribute_eq 'clean', true
|
114
132
|
|
@@ -314,18 +332,12 @@ RSpec.describe DoSnapshot::Runner, type: :aruba do
|
|
314
332
|
elsif value.is_a?(Numeric)
|
315
333
|
"--#{key}=#{value}"
|
316
334
|
elsif value.is_a?(Array)
|
317
|
-
|
318
|
-
|
319
|
-
else
|
320
|
-
nil
|
321
|
-
end
|
335
|
+
next unless value.size > 0
|
336
|
+
"--#{key}=#{value.join(' ')}"
|
322
337
|
elsif value.is_a?(Hash)
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
else
|
327
|
-
nil
|
328
|
-
end
|
338
|
+
next unless value.size > 0
|
339
|
+
items = value.map { |param, setting| "#{param}:#{setting}" }.join(' ')
|
340
|
+
"--#{key}=#{items}"
|
329
341
|
else
|
330
342
|
"--#{key}"
|
331
343
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: do_snapshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Merkulov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: digitalocean_c
|