do_snapshot 0.3.6 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/do_snapshot.rb +1 -3
- data/lib/do_snapshot/adapter/digitalocean.rb +3 -3
- data/lib/do_snapshot/adapter/digitalocean_v2.rb +31 -35
- data/lib/do_snapshot/command.rb +16 -0
- data/lib/do_snapshot/version.rb +1 -1
- data/spec/do_snapshot/adapter/digitalocean_spec.rb +2 -2
- data/spec/do_snapshot/adapter/digitalocean_v2_spec.rb +4 -7
- data/spec/do_snapshot/command_spec.rb +29 -3
- data/spec/do_snapshot_spec.rb +2 -2
- data/spec/shared/api_v2_helpers.rb +3 -3
- metadata +5 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 06606ebf6e8df99c994ce845c7f5fa63996f53e1
|
4
|
+
data.tar.gz: 42f86fa15f04f5e5d43e7785b0fcd46b6c0875e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbaea0198b09721b86e4419b5fb1aba1c1935469be3a7fb0fe16d9be044857767150fa7b5e5cc4da3b546b6e5ee353ce5466ca3cd096ba5fa8156f067d8ce499
|
7
|
+
data.tar.gz: f04fe0b3897ca82876cbc33b7b952017bcd9e569953c101486eae2a34304c73fffb90d3b56deb63bfa78931a8576a2a83ede049087586405f78286cac6d4d93f
|
data/README.md
CHANGED
@@ -193,7 +193,7 @@ Support this project and others by [merqlove](https://gratipay.com/~merqlove/) v
|
|
193
193
|
|
194
194
|
- [Thor](https://github.com/erikhuda/thor) for CLI.
|
195
195
|
- [Digitalocean](https://github.com/scottmotte/digitalocean) for API V1 requests.
|
196
|
-
- [
|
196
|
+
- [Barge](https://github.com/blom/barge) for API V2 requests.
|
197
197
|
- [Pony](https://github.com/benprew/pony) for mail notifications.
|
198
198
|
|
199
199
|
## Contributing
|
data/lib/do_snapshot.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require 'active_support/multibyte' # ActiveSupport 3.2 & Mail gem fix to work together.
|
3
|
-
|
4
2
|
require_relative 'do_snapshot/version'
|
5
3
|
require_relative 'do_snapshot/configuration'
|
6
4
|
|
@@ -77,7 +75,7 @@ module DoSnapshot
|
|
77
75
|
#
|
78
76
|
class DropletFindError < RequestError
|
79
77
|
def initialize(*args)
|
80
|
-
DoSnapshot.logger.error
|
78
|
+
DoSnapshot.logger.error "Droplet id: #{args[0]} Not Found"
|
81
79
|
super
|
82
80
|
end
|
83
81
|
end
|
@@ -12,7 +12,7 @@ module DoSnapshot
|
|
12
12
|
def droplet(id)
|
13
13
|
# noinspection RubyResolve
|
14
14
|
response = ::DigitaloceanC::Droplet.find(id)
|
15
|
-
fail DropletFindError, response.message unless response.status.include? 'OK'
|
15
|
+
fail DropletFindError.new(id), response.message unless response.status.include? 'OK'
|
16
16
|
response.droplet
|
17
17
|
end
|
18
18
|
|
@@ -124,9 +124,9 @@ module DoSnapshot
|
|
124
124
|
event = ::DigitaloceanC::Droplet.power_on(id)
|
125
125
|
case event && event.status
|
126
126
|
when 'OK'
|
127
|
-
logger.info
|
127
|
+
logger.info "Droplet id: #{id} is requested for Power On."
|
128
128
|
else
|
129
|
-
logger.error
|
129
|
+
logger.error "Droplet id: #{id} is failed to request for Power On."
|
130
130
|
end
|
131
131
|
end
|
132
132
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
-
require '
|
2
|
+
require 'barge' unless defined?(::Barge)
|
3
3
|
|
4
4
|
module DoSnapshot
|
5
5
|
module Adapter
|
@@ -13,22 +13,18 @@ module DoSnapshot
|
|
13
13
|
#
|
14
14
|
def droplet(id)
|
15
15
|
# noinspection RubyResolve
|
16
|
-
response = client.
|
17
|
-
fail DropletFindError unless response
|
18
|
-
response
|
19
|
-
rescue => e
|
20
|
-
raise DropletFindError, e.message
|
16
|
+
response = client.droplet.show(id)
|
17
|
+
fail DropletFindError.new(id), response.message unless response.respond_to?(:droplet)
|
18
|
+
response.droplet
|
21
19
|
end
|
22
20
|
|
23
21
|
# Get droplets list from DigitalOcean
|
24
22
|
#
|
25
23
|
def droplets
|
26
24
|
# noinspection RubyResolve
|
27
|
-
response = client.
|
28
|
-
fail DropletListError unless response
|
29
|
-
response.
|
30
|
-
rescue => e
|
31
|
-
raise DropletListError, e.message
|
25
|
+
response = client.droplet.all
|
26
|
+
fail DropletListError, response.message unless response.respond_to?(:droplets)
|
27
|
+
response.droplets
|
32
28
|
end
|
33
29
|
|
34
30
|
def snapshots(instance)
|
@@ -41,7 +37,7 @@ module DoSnapshot
|
|
41
37
|
# noinspection RubyResolve
|
42
38
|
instance = droplet(id)
|
43
39
|
|
44
|
-
return power_on(id) unless instance.status
|
40
|
+
return power_on(id) unless instance.status.include?('active')
|
45
41
|
|
46
42
|
logger.error "Droplet #{id} is still running. Skipping."
|
47
43
|
end
|
@@ -50,24 +46,24 @@ module DoSnapshot
|
|
50
46
|
#
|
51
47
|
def stop_droplet(id)
|
52
48
|
# noinspection RubyResolve,RubyResolve
|
53
|
-
client.
|
49
|
+
response = client.droplet.power_off(id)
|
50
|
+
|
51
|
+
fail DropletShutdownError.new(id), response.message unless response.respond_to?(:action)
|
54
52
|
|
55
53
|
# noinspection RubyResolve
|
56
|
-
|
57
|
-
rescue => e
|
58
|
-
raise DropletShutdownError.new(id), e.message, e.backtrace
|
54
|
+
wait_event(response.action.id)
|
59
55
|
end
|
60
56
|
|
61
57
|
# Sending event to create snapshot via DigitalOcean API and wait for success
|
62
58
|
#
|
63
59
|
def create_snapshot(id, name)
|
64
60
|
# noinspection RubyResolve,RubyResolve
|
65
|
-
|
61
|
+
response = client.droplet.snapshot(id, name: name)
|
66
62
|
|
67
|
-
fail DoSnapshot::SnapshotCreateError.new(id),
|
63
|
+
fail DoSnapshot::SnapshotCreateError.new(id), response.message unless response.respond_to?(:action)
|
68
64
|
|
69
65
|
# noinspection RubyResolve
|
70
|
-
wait_event(
|
66
|
+
wait_event(response.action.id)
|
71
67
|
end
|
72
68
|
|
73
69
|
# Checking if droplet is powered off.
|
@@ -84,14 +80,11 @@ module DoSnapshot
|
|
84
80
|
(0..size).each do |i|
|
85
81
|
# noinspection RubyResolve
|
86
82
|
snapshot = instance.snapshot_ids[i]
|
87
|
-
|
83
|
+
action = client.image.destroy(snapshot)
|
88
84
|
|
89
|
-
unless
|
90
|
-
logger.debug event
|
91
|
-
event = false
|
92
|
-
end
|
85
|
+
logger.debug action unless action.success?
|
93
86
|
|
94
|
-
after_cleanup(instance.id, instance.name, snapshot,
|
87
|
+
after_cleanup(instance.id, instance.name, snapshot, action)
|
95
88
|
end
|
96
89
|
end
|
97
90
|
|
@@ -106,13 +99,13 @@ module DoSnapshot
|
|
106
99
|
#
|
107
100
|
def set_id
|
108
101
|
logger.debug 'Setting DigitalOcean Access Token.'
|
109
|
-
@client = ::
|
102
|
+
@client = ::Barge::Client.new(access_token: ENV['DIGITAL_OCEAN_ACCESS_TOKEN'], timeout: 15, open_timeout: 15)
|
110
103
|
end
|
111
104
|
|
112
105
|
protected
|
113
106
|
|
114
|
-
def after_cleanup(droplet_id, droplet_name, snapshot,
|
115
|
-
if !
|
107
|
+
def after_cleanup(droplet_id, droplet_name, snapshot, action)
|
108
|
+
if !action.success?
|
116
109
|
logger.error "Destroy of snapshot #{snapshot} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
|
117
110
|
else
|
118
111
|
logger.debug "Snapshot: #{snapshot} delete requested."
|
@@ -124,23 +117,26 @@ module DoSnapshot
|
|
124
117
|
def get_event_status(id, time)
|
125
118
|
return true if timeout?(id, time)
|
126
119
|
|
127
|
-
|
120
|
+
response = client.action.show(id)
|
128
121
|
|
129
|
-
fail DoSnapshot::EventError.new(id),
|
122
|
+
fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:action)
|
130
123
|
|
131
124
|
# noinspection RubyResolve,RubyResolve
|
132
|
-
action.status.include?('completed') ? true : false
|
125
|
+
response.action.status.include?('completed') ? true : false
|
133
126
|
end
|
134
127
|
|
135
128
|
# Request Power On for droplet
|
136
129
|
#
|
137
130
|
def power_on(id)
|
138
131
|
# noinspection RubyResolve
|
139
|
-
|
140
|
-
|
141
|
-
|
132
|
+
response = client.droplet.power_on(id)
|
133
|
+
|
134
|
+
fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:action)
|
135
|
+
|
136
|
+
if response.action.status.include?('in-progress')
|
137
|
+
logger.info "Droplet id: #{id} is requested for Power On."
|
142
138
|
else
|
143
|
-
logger.error
|
139
|
+
logger.error "Droplet id: #{id} is failed to request for Power On."
|
144
140
|
end
|
145
141
|
end
|
146
142
|
end
|
data/lib/do_snapshot/command.rb
CHANGED
@@ -14,6 +14,7 @@ module DoSnapshot
|
|
14
14
|
def snap
|
15
15
|
logger.info 'Start performing operations'
|
16
16
|
work_with_droplets
|
17
|
+
power_on_failed_droplets
|
17
18
|
logger.info 'All operations has been finished.'
|
18
19
|
|
19
20
|
mailer.notify if mailer && notify && !quiet
|
@@ -82,10 +83,24 @@ module DoSnapshot
|
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
86
|
+
def power_on_failed_droplets
|
87
|
+
processed_droplet_ids
|
88
|
+
.select { |id| api.inactive?(id) }
|
89
|
+
.each { |id| api.start_droplet(id) }
|
90
|
+
end
|
91
|
+
|
92
|
+
# API launcher
|
93
|
+
#
|
85
94
|
def api
|
86
95
|
@api ||= DoSnapshot::Adapter.api(protocol, delay: delay, timeout: timeout)
|
87
96
|
end
|
88
97
|
|
98
|
+
# Processed droplets
|
99
|
+
#
|
100
|
+
def processed_droplet_ids
|
101
|
+
@droplet_ids ||= %w()
|
102
|
+
end
|
103
|
+
|
89
104
|
protected
|
90
105
|
|
91
106
|
attr_accessor :droplets, :exclude, :only
|
@@ -154,6 +169,7 @@ module DoSnapshot
|
|
154
169
|
return unless droplet
|
155
170
|
logger.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
|
156
171
|
return if too_much_snapshots(droplet)
|
172
|
+
processed_droplet_ids << droplet.id
|
157
173
|
thread_runner(droplet)
|
158
174
|
end
|
159
175
|
|
data/lib/do_snapshot/version.rb
CHANGED
@@ -42,7 +42,7 @@ RSpec.describe DoSnapshot::Adapter::Digitalocean do
|
|
42
42
|
expect { instance.droplet(droplet_id) }
|
43
43
|
.to raise_error(DoSnapshot::DropletFindError)
|
44
44
|
expect(DoSnapshot.logger.buffer)
|
45
|
-
.to include
|
45
|
+
.to include "Droplet id: #{droplet_id} Not Found"
|
46
46
|
|
47
47
|
expect(a_request(:get, droplet_url))
|
48
48
|
.to have_been_made
|
@@ -77,7 +77,7 @@ RSpec.describe DoSnapshot::Adapter::Digitalocean do
|
|
77
77
|
stub_droplet_start(droplet_id)
|
78
78
|
|
79
79
|
instance.start_droplet(droplet_id)
|
80
|
-
expect(DoSnapshot.logger.buffer).to include
|
80
|
+
expect(DoSnapshot.logger.buffer).to include "Droplet id: #{droplet_id} is requested for Power On."
|
81
81
|
|
82
82
|
expect(a_request(:get, droplet_start_url))
|
83
83
|
.to have_been_made
|
@@ -44,7 +44,7 @@ RSpec.describe DoSnapshot::Adapter::DigitaloceanV2 do
|
|
44
44
|
expect { instance.droplet(droplet_id) }
|
45
45
|
.to raise_error(DoSnapshot::DropletFindError)
|
46
46
|
expect(DoSnapshot.logger.buffer)
|
47
|
-
.to include
|
47
|
+
.to include "Droplet id: #{droplet_id} Not Found"
|
48
48
|
|
49
49
|
expect(a_request(:get, droplet_url))
|
50
50
|
.to have_been_made
|
@@ -79,7 +79,7 @@ RSpec.describe DoSnapshot::Adapter::DigitaloceanV2 do
|
|
79
79
|
stub_droplet_start(droplet_id)
|
80
80
|
|
81
81
|
instance.start_droplet(droplet_id)
|
82
|
-
expect(DoSnapshot.logger.buffer).to include
|
82
|
+
expect(DoSnapshot.logger.buffer).to include "Droplet id: #{droplet_id} is requested for Power On."
|
83
83
|
|
84
84
|
expect(a_request(:post, droplet_start_url))
|
85
85
|
.to have_been_made
|
@@ -114,23 +114,20 @@ RSpec.describe DoSnapshot::Adapter::DigitaloceanV2 do
|
|
114
114
|
it 'with success' do
|
115
115
|
stub_event_done(event_id)
|
116
116
|
stub_droplet_stop(droplet_id)
|
117
|
-
stub_droplet_inactive(droplet_id)
|
118
117
|
|
119
118
|
instance.stop_droplet(droplet_id)
|
120
119
|
|
121
120
|
expect(a_request(:post, droplet_stop_url))
|
122
121
|
.to have_been_made
|
123
|
-
expect(a_request(:get,
|
122
|
+
expect(a_request(:get, action_find_url))
|
124
123
|
.to have_been_made
|
125
124
|
end
|
126
125
|
|
127
126
|
it 'with error' do
|
128
127
|
stub_droplet_stop_fail(droplet_id)
|
129
|
-
|
130
|
-
instance.timeout = 1
|
128
|
+
|
131
129
|
expect { instance.stop_droplet(droplet_id) }
|
132
130
|
.to raise_error(DoSnapshot::DropletShutdownError)
|
133
|
-
instance.timeout = timeout
|
134
131
|
expect(DoSnapshot.logger.buffer)
|
135
132
|
.to include 'Droplet id: 100823 is Failed to Power Off.'
|
136
133
|
|
@@ -88,6 +88,32 @@ RSpec.describe DoSnapshot::Command do
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
describe '.power_on_failed_droplets' do
|
92
|
+
it 'when nothing' do
|
93
|
+
stub_droplet_start(droplet_id)
|
94
|
+
stub_droplet(droplet_id)
|
95
|
+
|
96
|
+
load_options
|
97
|
+
cmd.processed_droplet_ids << droplet_id
|
98
|
+
expect { cmd.power_on_failed_droplets }
|
99
|
+
.not_to raise_error
|
100
|
+
expect(DoSnapshot.logger.buffer)
|
101
|
+
.not_to include "Droplet id: #{droplet_id} is requested for Power On."
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'when one' do
|
105
|
+
stub_droplet_start(droplet_id)
|
106
|
+
stub_droplet_inactive(droplet_id)
|
107
|
+
|
108
|
+
load_options
|
109
|
+
cmd.processed_droplet_ids << droplet_id
|
110
|
+
expect { cmd.power_on_failed_droplets }
|
111
|
+
.not_to raise_error
|
112
|
+
expect(DoSnapshot.logger.buffer)
|
113
|
+
.to include "Droplet id: #{droplet_id} is requested for Power On."
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
91
117
|
describe '.stop_droplet' do
|
92
118
|
it 'when raised with error' do
|
93
119
|
stub_droplet_stop_fail(droplet_id)
|
@@ -150,7 +176,7 @@ RSpec.describe DoSnapshot::Command do
|
|
150
176
|
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
|
151
177
|
.not_to raise_error
|
152
178
|
expect(DoSnapshot.logger.buffer)
|
153
|
-
.to include
|
179
|
+
.to include "Droplet id: #{droplet_id} is requested for Power On."
|
154
180
|
end
|
155
181
|
|
156
182
|
it 'with request error' do
|
@@ -161,7 +187,7 @@ RSpec.describe DoSnapshot::Command do
|
|
161
187
|
expect(DoSnapshot.logger.buffer)
|
162
188
|
.to include 'Droplet id: 100823 is Failed to Power Off.'
|
163
189
|
expect(DoSnapshot.logger.buffer)
|
164
|
-
.to include
|
190
|
+
.to include "Droplet id: #{droplet_id} Not Found"
|
165
191
|
end
|
166
192
|
|
167
193
|
it 'with start error' do
|
@@ -172,7 +198,7 @@ RSpec.describe DoSnapshot::Command do
|
|
172
198
|
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
|
173
199
|
.not_to raise_error
|
174
200
|
expect(DoSnapshot.logger.buffer)
|
175
|
-
.to include
|
201
|
+
.to include "Droplet id: #{droplet_id} is failed to request for Power On."
|
176
202
|
end
|
177
203
|
end
|
178
204
|
end
|
data/spec/do_snapshot_spec.rb
CHANGED
@@ -8,9 +8,9 @@ RSpec.describe DoSnapshot do
|
|
8
8
|
subject(:error) { described_class }
|
9
9
|
|
10
10
|
it 'should work' do
|
11
|
-
error.new
|
11
|
+
error.new(droplet_id)
|
12
12
|
expect(DoSnapshot.logger.buffer)
|
13
|
-
.to include
|
13
|
+
.to include "Droplet id: #{droplet_id} Not Found"
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -9,13 +9,13 @@ shared_context 'api_v2_helpers' do
|
|
9
9
|
let(:actions_api_base) { "#{api_base}/actions" }
|
10
10
|
let(:images_api_base) { "#{api_base}/images" }
|
11
11
|
let(:image_destroy_uri) { "#{images_api_base}/[id]" }
|
12
|
-
let(:droplets_uri) { "#{droplets_api_base}?
|
13
|
-
let(:droplet_find_uri) { "#{droplets_api_base}/[id]" }
|
12
|
+
let(:droplets_uri) { "#{droplets_api_base}?per_page=200" }
|
13
|
+
let(:droplet_find_uri) { "#{droplets_api_base}/[id]?per_page=200" }
|
14
14
|
let(:droplet_stop_uri) { "#{droplets_api_base}/[id]/actions" }
|
15
15
|
let(:droplet_start_uri) { "#{droplets_api_base}/[id]/actions" }
|
16
16
|
let(:snapshot_uri) { "#{droplets_api_base}/[id]/actions" }
|
17
17
|
let(:event_find_uri) { "#{events_api_base}/[id]" }
|
18
|
-
let(:action_find_uri) { "#{actions_api_base}/[id]" }
|
18
|
+
let(:action_find_uri) { "#{actions_api_base}/[id]?per_page=200" }
|
19
19
|
|
20
20
|
# List of droplets
|
21
21
|
#
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: do_snapshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.7
|
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-
|
11
|
+
date: 2015-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '3.2'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '3.2'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: digitalocean_c
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,19 +25,19 @@ dependencies:
|
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '1.2'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
28
|
+
name: barge
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - "~>"
|
46
32
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
33
|
+
version: '0.11'
|
48
34
|
type: :runtime
|
49
35
|
prerelease: false
|
50
36
|
version_requirements: !ruby/object:Gem::Requirement
|
51
37
|
requirements:
|
52
38
|
- - "~>"
|
53
39
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
40
|
+
version: '0.11'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: thor
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|