do_snapshot 0.6.2 → 0.6.3
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 +9 -4
- data/lib/do_snapshot/adapter/digitalocean_v2.rb +1 -1
- data/lib/do_snapshot/cli.rb +5 -1
- data/lib/do_snapshot/command.rb +14 -3
- data/lib/do_snapshot/version.rb +1 -1
- data/spec/do_snapshot/cli_spec.rb +8 -0
- data/spec/do_snapshot/command_spec.rb +46 -5
- data/spec/do_snapshot/runner_spec.rb +18 -0
- data/spec/shared/environment.rb +2 -1
- 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: 5ee1fb26e08febbd07bd95db15ede7e27288c6ac
|
4
|
+
data.tar.gz: e94d18d396f7afe4a2746b7d5f26ab4bf162cc1e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9222fbba54f8d23156befea3fbe36aebb173e566f29710d09a84c9ab4915ad177e8800818744c54c02ece99fd167b30a013054ff526fc749ce128358cd66e6c
|
7
|
+
data.tar.gz: bc3c05e81971b6a62e217785035361179e2832c9b52f8cab5371d64655eedf57dded6bbc9f5064aa340fbfa1584adc0028c00307f6ff951ffcfdba732fe991c0
|
data/README.md
CHANGED
@@ -13,6 +13,10 @@
|
|
13
13
|
Use this tool to backup DigitalOcean droplet's via snapshot method, on the fly!
|
14
14
|
|
15
15
|
## API Changes:
|
16
|
+
- 03.08.16: DO now automagically keeps our droplets running when snapshot is processing, so:
|
17
|
+
Added options `--shutdown`, `--no-shutdown`.
|
18
|
+
`shutdown` now disabled by default, no downtime anymore, `YES`!
|
19
|
+
If you want `shutdown` back use `--shutdown` option.
|
16
20
|
- 08.01.16: now we have to use DO API V2 only, because V1 is not work anymore.
|
17
21
|
- 17.10.15: now we use DO API V2 by default, due V1 deprecation at 11.2015.
|
18
22
|
|
@@ -87,8 +91,9 @@ If you want to set keys without environment, than set it via options when you ru
|
|
87
91
|
### How-To
|
88
92
|
|
89
93
|
##### Tutorials:
|
90
|
-
- [
|
91
|
-
|
94
|
+
- [Automate Taking Snapshots of Your DigitalOcean Droplets with DOSnapshot
|
95
|
+
, Tyler Longren](https://longren.io/automate-making-snapshots-of-your-digitalocean-droplets/)
|
96
|
+
- [How to Automate Taking Digital Ocean Droplet Snaphot with DoSnapShot Script, Arun Kumar](http://www.ashout.com/automate-digital-ocean-droplet-snaphot/)
|
92
97
|
|
93
98
|
Here we `keeping` only 5 **latest** snapshots and cleanup older after new one is created. If creation of snapshots failed no one will be deleted. By default we keeping `10` droplets.
|
94
99
|
|
@@ -147,6 +152,7 @@ For working mailer you need to set e-mail settings via run options.
|
|
147
152
|
Options:
|
148
153
|
-p, [--protocol=1] # Select api version.
|
149
154
|
# Default: 2
|
155
|
+
[--shutdown], [--no-shutdown] # Check if you want to stop your droplet before the snapshot.
|
150
156
|
-o, [--only=123456 123456 123456] # Select some droplets.
|
151
157
|
-e, [--exclude=123456 123456 123456] # Except some droplets.
|
152
158
|
-k, [--keep=5] # How much snapshots you want to keep?
|
@@ -160,7 +166,7 @@ For working mailer you need to set e-mail settings via run options.
|
|
160
166
|
-l, [--log=/Users/someone/.do_snapshot/main.log] # Log file path. By default logging is disabled.
|
161
167
|
-c, [--clean], [--no-clean] # Cleanup snapshots after create. If you have more images than you want to `keep`, older will be deleted.
|
162
168
|
-s, [--stop], [--no-stop] # Stop creating snapshots if maximum is reached.
|
163
|
-
[--stop-by-power], [--no-stop-by-power] #
|
169
|
+
[--stop-by-power], [--no-stop-by-power] # Droplet stop method, by it's power status (instead of waiting for event completed state).
|
164
170
|
-v, [--trace], [--no-trace] # Verbose mode.
|
165
171
|
-q, [--quiet], [--no-quiet] # Quiet mode. If don't need any messages in console.
|
166
172
|
[--digital-ocean-access-token=YOURLONGAPITOKEN] # DIGITAL_OCEAN_ACCESS_TOKEN. if you can't use environment.
|
@@ -189,7 +195,6 @@ Support this project and others by [merqlove](https://gratipay.com/~merqlove/) v
|
|
189
195
|
## Dependencies:
|
190
196
|
|
191
197
|
- [Thor](https://github.com/erikhuda/thor) for CLI.
|
192
|
-
- [Digitalocean](https://github.com/scottmotte/digitalocean) for API V1 requests.
|
193
198
|
- [Barge](https://github.com/blom/barge) for API V2 requests.
|
194
199
|
- [Pony](https://github.com/benprew/pony) for mail notifications.
|
195
200
|
|
@@ -95,7 +95,7 @@ module DoSnapshot
|
|
95
95
|
def check_keys
|
96
96
|
logger.debug 'Checking DigitalOcean Access Token.'
|
97
97
|
%w( DIGITAL_OCEAN_ACCESS_TOKEN ).each do |key|
|
98
|
-
fail DoSnapshot::NoTokenError, "You must have #{key} in environment or set it via options." if ENV[key].
|
98
|
+
fail DoSnapshot::NoTokenError, "You must have #{key} in environment or set it via options." if ENV[key].nil? || ENV[key].empty?
|
99
99
|
end
|
100
100
|
end
|
101
101
|
|
data/lib/do_snapshot/cli.rb
CHANGED
@@ -82,6 +82,10 @@ module DoSnapshot
|
|
82
82
|
aliases: %w( -p ),
|
83
83
|
banner: '1',
|
84
84
|
desc: 'Select api version.'
|
85
|
+
method_option :shutdown,
|
86
|
+
default: false,
|
87
|
+
type: :boolean,
|
88
|
+
desc: 'Check if you want to stop droplet before the snapshot.'
|
85
89
|
method_option :only,
|
86
90
|
type: :array,
|
87
91
|
default: [],
|
@@ -137,7 +141,7 @@ module DoSnapshot
|
|
137
141
|
desc: 'Stop creating snapshots if maximum is reached.'
|
138
142
|
method_option :stop_by_power,
|
139
143
|
type: :boolean,
|
140
|
-
desc:
|
144
|
+
desc: "Droplet stop method, by it's power status (instead of waiting for event completed state)."
|
141
145
|
method_option :trace,
|
142
146
|
type: :boolean,
|
143
147
|
aliases: %w( -v ),
|
data/lib/do_snapshot/command.rb
CHANGED
@@ -7,6 +7,10 @@ module DoSnapshot
|
|
7
7
|
class Command # rubocop:disable ClassLength
|
8
8
|
include DoSnapshot::Helpers
|
9
9
|
|
10
|
+
RESET_OPTIONS = [:droplets, :exclude, :only, :keep, :quiet,
|
11
|
+
:stop, :clean, :timeout, :shutdown, :delay,
|
12
|
+
:protocol, :threads, :api]
|
13
|
+
|
10
14
|
def initialize(*args)
|
11
15
|
load_options(*args)
|
12
16
|
end
|
@@ -21,6 +25,7 @@ module DoSnapshot
|
|
21
25
|
end
|
22
26
|
|
23
27
|
def fail_power_off(e)
|
28
|
+
return unless shutdown
|
24
29
|
return unless e && e.id
|
25
30
|
api.start_droplet(e.id)
|
26
31
|
rescue
|
@@ -35,12 +40,13 @@ module DoSnapshot
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def reset_options
|
38
|
-
|
43
|
+
RESET_OPTIONS.each do |key|
|
39
44
|
send("#{key}=", nil)
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
48
|
def stop_droplet(droplet)
|
49
|
+
return true unless shutdown
|
44
50
|
logger.debug 'Shutting down droplet.'
|
45
51
|
api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
|
46
52
|
true
|
@@ -49,10 +55,15 @@ module DoSnapshot
|
|
49
55
|
false
|
50
56
|
end
|
51
57
|
|
58
|
+
def fail_if_shutdown(droplet)
|
59
|
+
return unless shutdown
|
60
|
+
fail DropletPowerError.new(droplet.id), droplet.name unless api.inactive?(droplet.id)
|
61
|
+
end
|
62
|
+
|
52
63
|
# Trying to create a snapshot.
|
53
64
|
#
|
54
65
|
def create_snapshot(droplet) # rubocop:disable MethodLength,Metrics/AbcSize
|
55
|
-
|
66
|
+
fail_if_shutdown(droplet)
|
56
67
|
|
57
68
|
logger.info "Start creating snapshot for droplet id: #{droplet.id} name: #{droplet.name}."
|
58
69
|
|
@@ -104,7 +115,7 @@ module DoSnapshot
|
|
104
115
|
protected
|
105
116
|
|
106
117
|
attr_accessor :droplets, :exclude, :only
|
107
|
-
attr_accessor :keep, :quiet, :stop, :stop_by_power, :clean, :timeout, :delay, :protocol
|
118
|
+
attr_accessor :keep, :quiet, :shutdown, :stop, :stop_by_power, :clean, :timeout, :delay, :protocol
|
108
119
|
|
109
120
|
attr_writer :threads, :api
|
110
121
|
|
data/lib/do_snapshot/version.rb
CHANGED
@@ -75,6 +75,14 @@ RSpec.describe DoSnapshot::CLI do
|
|
75
75
|
attribute_eq 'stop', false
|
76
76
|
end
|
77
77
|
|
78
|
+
it 'with shutdown' do
|
79
|
+
attribute_eq 'shutdown', true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'with no shutdown' do
|
83
|
+
attribute_eq 'shutdown', false
|
84
|
+
end
|
85
|
+
|
78
86
|
it 'with stop by power' do
|
79
87
|
attribute_eq 'stop_by_power', true
|
80
88
|
end
|
@@ -113,7 +113,7 @@ RSpec.describe DoSnapshot::Command do
|
|
113
113
|
describe '.stop_droplet by power status' do
|
114
114
|
it 'when raised with error' do
|
115
115
|
stub_droplet_stop_fail(droplet_id)
|
116
|
-
load_options(stop_by_power: true)
|
116
|
+
load_options(stop_by_power: true, shutdown: true)
|
117
117
|
droplet = cmd.api.droplet droplet_id
|
118
118
|
expect { cmd.stop_droplet(droplet) }
|
119
119
|
.not_to raise_error
|
@@ -124,7 +124,17 @@ RSpec.describe DoSnapshot::Command do
|
|
124
124
|
it 'when stopped' do
|
125
125
|
stub_droplet_inactive(droplet_id)
|
126
126
|
stub_droplet_stop(droplet_id)
|
127
|
-
load_options(stop_by_power: true)
|
127
|
+
load_options(stop_by_power: true, shutdown: true)
|
128
|
+
droplet = cmd.api.droplet droplet_id
|
129
|
+
expect { cmd.stop_droplet(droplet) }
|
130
|
+
.not_to raise_error
|
131
|
+
expect(cmd.stop_droplet(droplet))
|
132
|
+
.to be_truthy
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'when nothing' do
|
136
|
+
stub_droplet(droplet_id)
|
137
|
+
load_options(stop_by_power: true, shutdown: false)
|
128
138
|
droplet = cmd.api.droplet droplet_id
|
129
139
|
expect { cmd.stop_droplet(droplet) }
|
130
140
|
.not_to raise_error
|
@@ -154,6 +164,16 @@ RSpec.describe DoSnapshot::Command do
|
|
154
164
|
expect(cmd.stop_droplet(droplet))
|
155
165
|
.to be_truthy
|
156
166
|
end
|
167
|
+
|
168
|
+
it 'when nothing' do
|
169
|
+
stub_droplet(droplet_id)
|
170
|
+
load_options(shutdown: false)
|
171
|
+
droplet = cmd.api.droplet droplet_id
|
172
|
+
expect { cmd.stop_droplet(droplet) }
|
173
|
+
.not_to raise_error
|
174
|
+
expect(cmd.stop_droplet(droplet))
|
175
|
+
.to be_truthy
|
176
|
+
end
|
157
177
|
end
|
158
178
|
|
159
179
|
describe '.create_snapshot' do
|
@@ -176,6 +196,18 @@ RSpec.describe DoSnapshot::Command do
|
|
176
196
|
.not_to raise_error
|
177
197
|
end
|
178
198
|
|
199
|
+
it 'when snapshot is created with no shutdown' do
|
200
|
+
stub_droplet(droplet_id)
|
201
|
+
stub_droplet_snapshot(droplet_id, snapshot_name)
|
202
|
+
load_options(shutdown: false)
|
203
|
+
droplet = cmd.api.droplet droplet_id
|
204
|
+
cmd.create_snapshot(droplet)
|
205
|
+
expect(DoSnapshot.logger.buffer)
|
206
|
+
.not_to include "Droplet id: #{droplet_id} must be Powered Off!"
|
207
|
+
expect { cmd.create_snapshot(droplet) }
|
208
|
+
.not_to raise_error
|
209
|
+
end
|
210
|
+
|
179
211
|
it 'when droplet is running' do
|
180
212
|
stub_droplet(droplet_id)
|
181
213
|
load_options
|
@@ -191,16 +223,25 @@ RSpec.describe DoSnapshot::Command do
|
|
191
223
|
describe '.fail_power_off' do
|
192
224
|
it 'when success' do
|
193
225
|
stub_droplet_inactive(droplet_id)
|
194
|
-
|
226
|
+
load_options(shutdown: true)
|
195
227
|
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
|
196
228
|
.not_to raise_error
|
197
229
|
expect(DoSnapshot.logger.buffer)
|
198
230
|
.to include "Droplet id: #{droplet_id} is requested for Power On."
|
199
231
|
end
|
200
232
|
|
201
|
-
it '
|
233
|
+
it 'not rescue when shutdown is true' do
|
202
234
|
stub_droplet_fail(droplet_id)
|
235
|
+
load_options(shutdown: false)
|
236
|
+
expect { cmd.fail_power_off(DoSnapshot::SnapshotCreateError.new(droplet_id)) }
|
237
|
+
.not_to raise_error
|
238
|
+
expect(DoSnapshot.logger.buffer)
|
239
|
+
.to include "Droplet id: #{droplet_id} is Failed to Snapshot."
|
240
|
+
end
|
203
241
|
|
242
|
+
it 'with request error' do
|
243
|
+
stub_droplet_fail(droplet_id)
|
244
|
+
load_options(shutdown: true)
|
204
245
|
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
|
205
246
|
.to raise_error(DoSnapshot::DropletFindError)
|
206
247
|
expect(DoSnapshot.logger.buffer)
|
@@ -212,7 +253,7 @@ RSpec.describe DoSnapshot::Command do
|
|
212
253
|
it 'with start error' do
|
213
254
|
stub_droplet_inactive(droplet_id)
|
214
255
|
stub_droplet_start_done(droplet_id)
|
215
|
-
|
256
|
+
load_options(shutdown: true)
|
216
257
|
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
|
217
258
|
.not_to raise_error
|
218
259
|
expect(DoSnapshot.logger.buffer)
|
@@ -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 shutdown' do
|
113
|
+
attribute_eq 'shutdown', 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 no shutdown' do
|
122
|
+
attribute_eq 'shutdown', false
|
123
|
+
|
124
|
+
expect(last_command).to have_exit_status(0)
|
125
|
+
expect(all_stdout).not_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 stop by power' do
|
113
131
|
attribute_eq 'stop_by_power', true
|
114
132
|
|
data/spec/shared/environment.rb
CHANGED
@@ -19,7 +19,7 @@ RSpec.shared_context 'environment' do
|
|
19
19
|
let(:cli_keys) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: access_token) }
|
20
20
|
let(:cli_keys_other) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: 'NOTTOK') }
|
21
21
|
let(:snapshot_name) { "example.com_#{DateTime.now.strftime('%Y_%m_%d')}" }
|
22
|
-
let(:default_options) { Hash[protocol: 2, only: %w( 100823 ), exclude: %w(), keep: 3, stop: false, trace: true, clean: true, delay: 0, timeout: 600] }
|
22
|
+
let(:default_options) { Hash[protocol: 2, only: %w( 100823 ), exclude: %w(), keep: 3, stop: false, trace: true, clean: true, delay: 0, shutdown: true, timeout: 600] }
|
23
23
|
let(:default_options_cli) { default_options.reject { |key, _| %w( droplets threads ).include?(key.to_s) } }
|
24
24
|
let(:no_exclude) { [] }
|
25
25
|
let(:exclude) { %w( 100824 100825 ) }
|
@@ -31,6 +31,7 @@ RSpec.shared_context 'environment' do
|
|
31
31
|
let(:no_quiet) { false }
|
32
32
|
let(:clean) { true }
|
33
33
|
let(:no_clean) { false }
|
34
|
+
let(:shutdown) { true }
|
34
35
|
let(:timeout) { 600 }
|
35
36
|
let(:delay) { 0 }
|
36
37
|
let(:log_path) { "#{project_path}/log/test.log" }
|
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.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Merkulov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: barge
|