do_snapshot 0.6.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -2
- data/bin/do_snapshot +1 -0
- data/lib/do_snapshot.rb +1 -0
- data/lib/do_snapshot/adapter.rb +10 -7
- data/lib/do_snapshot/adapter/abstract.rb +2 -1
- data/lib/do_snapshot/adapter/{digitalocean_v2.rb → droplet_kit.rb} +50 -33
- data/lib/do_snapshot/cli.rb +1 -0
- data/lib/do_snapshot/command.rb +1 -0
- data/lib/do_snapshot/configuration.rb +1 -0
- data/lib/do_snapshot/core_ext/hash.rb +1 -0
- data/lib/do_snapshot/distribution.rb +1 -0
- data/lib/do_snapshot/gem_ext/resource_kit.rb +30 -0
- data/lib/do_snapshot/helpers.rb +1 -0
- data/lib/do_snapshot/log.rb +1 -0
- data/lib/do_snapshot/mail.rb +1 -0
- data/lib/do_snapshot/rspec.rb +12 -0
- data/lib/do_snapshot/rspec/adapter.rb +265 -0
- data/lib/do_snapshot/rspec/api_helpers.rb +45 -0
- data/lib/do_snapshot/rspec/api_v2_helpers.rb +157 -0
- data/lib/do_snapshot/rspec/environment.rb +120 -0
- data/lib/do_snapshot/rspec/uri_helpers.rb +17 -0
- data/lib/do_snapshot/runner.rb +1 -0
- data/lib/do_snapshot/version.rb +2 -1
- data/spec/do_snapshot/adapter/abstract_spec.rb +2 -1
- data/spec/do_snapshot/adapter/droplet_kit_spec.rb +9 -0
- data/spec/do_snapshot/adapter_spec.rb +3 -2
- data/spec/do_snapshot/cli_spec.rb +4 -3
- data/spec/do_snapshot/command_spec.rb +4 -3
- data/spec/do_snapshot/configuration_spec.rb +1 -0
- data/spec/do_snapshot/log_spec.rb +2 -1
- data/spec/do_snapshot/mail_spec.rb +2 -1
- data/spec/do_snapshot/runner_spec.rb +3 -2
- data/spec/do_snapshot_spec.rb +2 -1
- data/spec/spec_helper.rb +2 -4
- data/spec/support/aruba.rb +1 -0
- data/spec/support/matchers.rb +1 -0
- metadata +47 -20
- data/spec/do_snapshot/adapter/digitalocean_v2_spec.rb +0 -264
- data/spec/shared/api_helpers.rb +0 -41
- data/spec/shared/api_v2_helpers.rb +0 -153
- data/spec/shared/environment.rb +0 -116
- data/spec/shared/uri_helpers.rb +0 -13
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module DoSnapshot
|
3
|
+
module RSpec
|
4
|
+
module ApiHelpers # rubocop:disable Style/Documentation
|
5
|
+
extend ::RSpec::Core::SharedContext
|
6
|
+
|
7
|
+
# Stub helpers
|
8
|
+
#
|
9
|
+
def stub_with_id(request, id, fixture, status = 200)
|
10
|
+
return unless request && fixture && id
|
11
|
+
stub_request(:get, url_with_id(request, id))
|
12
|
+
.to_return(status: status, body: fixture(fixture))
|
13
|
+
end
|
14
|
+
|
15
|
+
def stub_without_id(request, fixture, status = 200)
|
16
|
+
return unless request && fixture
|
17
|
+
stub_request(:get, request)
|
18
|
+
.to_return(status: status, body: fixture(fixture))
|
19
|
+
end
|
20
|
+
|
21
|
+
def stub_with_id_name(request, id, name, fixture, status = 200)
|
22
|
+
return unless request && fixture && id && name
|
23
|
+
stub_request(:get, url_with_id_name(request, id, name))
|
24
|
+
.to_return(status: status, body: fixture(fixture))
|
25
|
+
end
|
26
|
+
|
27
|
+
# Url helpers
|
28
|
+
#
|
29
|
+
def url_with_id(request, id)
|
30
|
+
return unless request && id
|
31
|
+
request.sub('[id]', id.to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
def url_with_event_id(request, droplet_id, id)
|
35
|
+
return unless request && id && droplet_id
|
36
|
+
request.sub('[id]', id.to_s).sub('[droplet_id]', droplet_id.to_s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def url_with_id_name(request, id, name)
|
40
|
+
return unless request && id && name
|
41
|
+
request.sub('[id]', id.to_s).sub('[name]', name)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module DoSnapshot
|
3
|
+
module RSpec
|
4
|
+
module ApiV2Helpers # rubocop:disable Style/Documentation,Metrics/ModuleLength
|
5
|
+
extend ::RSpec::Core::SharedContext
|
6
|
+
|
7
|
+
let(:api_base) { 'https://api.digitalocean.com/v2' }
|
8
|
+
let(:droplets_api_base) { "#{api_base}/droplets" }
|
9
|
+
let(:api_access_token) { "Bearer #{access_token}" }
|
10
|
+
let(:events_api_base) { "#{api_base}/droplets/[droplet_id]/actions" }
|
11
|
+
let(:actions_api_base) { "#{api_base}/actions" }
|
12
|
+
let(:images_api_base) { "#{api_base}/images" }
|
13
|
+
let(:image_destroy_uri) { "#{images_api_base}/[id]" }
|
14
|
+
let(:droplets_uri) { "#{droplets_api_base}?page=1&per_page=1000" }
|
15
|
+
let(:droplet_find_uri) { "#{droplets_api_base}/[id]" }
|
16
|
+
let(:droplet_stop_uri) { "#{droplets_api_base}/[id]/actions" }
|
17
|
+
let(:droplet_start_uri) { "#{droplets_api_base}/[id]/actions" }
|
18
|
+
let(:snapshot_uri) { "#{droplets_api_base}/[id]/actions" }
|
19
|
+
let(:event_find_uri) { "#{events_api_base}/[id]" }
|
20
|
+
let(:action_find_uri) { "#{actions_api_base}/[id]" }
|
21
|
+
|
22
|
+
# List of droplets
|
23
|
+
#
|
24
|
+
def stub_droplets
|
25
|
+
stub_without_id(droplets_uri, 'v2/show_droplets')
|
26
|
+
end
|
27
|
+
|
28
|
+
def stub_droplets_empty
|
29
|
+
stub_without_id(droplets_uri, 'v2/show_droplets_empty')
|
30
|
+
end
|
31
|
+
|
32
|
+
def stub_droplets_fail
|
33
|
+
stub_without_id(droplets_uri, 'v2/error_message')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Droplet data
|
37
|
+
#
|
38
|
+
def stub_droplet(id)
|
39
|
+
stub_with_id(droplet_find_uri, id, 'v2/show_droplet')
|
40
|
+
end
|
41
|
+
|
42
|
+
def stub_droplet_fail(id)
|
43
|
+
stub_with_id(droplet_find_uri, id, 'v2/error_message')
|
44
|
+
end
|
45
|
+
|
46
|
+
def stub_droplet_inactive(id)
|
47
|
+
stub_with_id(droplet_find_uri, id, 'v2/show_droplet_inactive')
|
48
|
+
end
|
49
|
+
|
50
|
+
# Droplet actions
|
51
|
+
#
|
52
|
+
def stub_droplet_stop(id)
|
53
|
+
stub_with_id(droplet_stop_uri, id, 'v2/show_event_power_off_start', :post,
|
54
|
+
type: 'power_off'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def stub_droplet_stop_fail(id)
|
59
|
+
stub_with_id(droplet_stop_uri, id, 'v2/error_message', :post,
|
60
|
+
{
|
61
|
+
type: 'power_off'
|
62
|
+
},
|
63
|
+
404
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def stub_droplet_start(id)
|
68
|
+
stub_with_id(droplet_start_uri, id, 'v2/show_event_power_on_start', :post,
|
69
|
+
type: 'power_on'
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def stub_droplet_start_done(id)
|
74
|
+
stub_with_id(droplet_start_uri, id, 'v2/show_event_power_on_done', :post,
|
75
|
+
type: 'power_on'
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
def stub_droplet_start_fail(id)
|
80
|
+
stub_with_id(droplet_start_uri, id, 'v2/error_message', :post,
|
81
|
+
type: 'power_on'
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Snapshot
|
86
|
+
#
|
87
|
+
def stub_droplet_snapshot(id, name)
|
88
|
+
stub_with_id_name(snapshot_uri, id, name, 'v2/response_event', :post,
|
89
|
+
type: 'snapshot',
|
90
|
+
name: name
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
def stub_droplet_snapshot_fail(id, name)
|
95
|
+
stub_with_id_name(snapshot_uri, id, name, 'v2/error_message', :post,
|
96
|
+
{
|
97
|
+
type: 'snapshot',
|
98
|
+
name: name
|
99
|
+
},
|
100
|
+
404
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Event status
|
105
|
+
#
|
106
|
+
def stub_event_done(id)
|
107
|
+
stub_with_id(action_find_uri, id, 'v2/show_event_done')
|
108
|
+
end
|
109
|
+
|
110
|
+
def stub_event_fail(id)
|
111
|
+
stub_with_id(action_find_uri, id, 'v2/error_message')
|
112
|
+
end
|
113
|
+
|
114
|
+
def stub_event_running(id)
|
115
|
+
stub_with_id(action_find_uri, id, 'v2/show_event_start')
|
116
|
+
end
|
117
|
+
|
118
|
+
# Image actions
|
119
|
+
#
|
120
|
+
def stub_image_destroy(id)
|
121
|
+
stub_with_id(image_destroy_uri, id, 'v2/empty', :delete, nil, 204)
|
122
|
+
end
|
123
|
+
|
124
|
+
def stub_image_destroy_fail(id)
|
125
|
+
stub_with_id(image_destroy_uri, id, 'v2/error_message', :delete, nil, 404)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Stub helpers
|
129
|
+
#
|
130
|
+
def stub_with_id(request, id, fixture, type = :get, body = nil, status = 200) # rubocop:disable Metrics/ParameterLists
|
131
|
+
return unless request && fixture && id
|
132
|
+
stub_request_body(type, url_with_id(request, id), body)
|
133
|
+
.to_return(status: status, body: fixture(fixture))
|
134
|
+
end
|
135
|
+
|
136
|
+
def stub_without_id(request, fixture, type = :get, body = nil, status = 200)
|
137
|
+
return unless request && fixture
|
138
|
+
stub_request_body(type, request, body)
|
139
|
+
.to_return(status: status, body: fixture(fixture))
|
140
|
+
end
|
141
|
+
|
142
|
+
def stub_with_id_name(request, id, name, fixture, type = :get, body = nil, status = 200) # rubocop:disable Metrics/ParameterLists
|
143
|
+
return unless request && fixture && id && name
|
144
|
+
stub_request_body(type, url_with_id_name(request, id, name), body)
|
145
|
+
.to_return(status: status, body: fixture(fixture))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Body Helpers
|
149
|
+
#
|
150
|
+
def stub_request_body(type, request, body)
|
151
|
+
stub_response = stub_request(type, request).with(headers: { 'Authorization' => api_access_token })
|
152
|
+
return stub_response.with(body: body) if body
|
153
|
+
stub_response
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module DoSnapshot
|
3
|
+
module RSpec
|
4
|
+
module Environment # rubocop:disable Style/Documentation
|
5
|
+
extend ::RSpec::Core::SharedContext
|
6
|
+
|
7
|
+
include ApiHelpers
|
8
|
+
|
9
|
+
def do_not_send_email
|
10
|
+
allow(Pony).to receive(:deliver) { |mail| mail }
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:client_key) { 'foo' }
|
14
|
+
let(:api_key) { 'bar' }
|
15
|
+
let(:access_token) { 'sometoken' }
|
16
|
+
let(:event_id) { '7499' }
|
17
|
+
let(:droplet_id) { '100823' }
|
18
|
+
let(:image_id) { '5019770' }
|
19
|
+
let(:image_id2) { '5019903' }
|
20
|
+
let(:cli_env_nil) { Hash['DIGITAL_OCEAN_CLIENT_ID' => nil, 'DIGITAL_OCEAN_API_KEY' => nil, 'DIGITAL_OCEAN_ACCESS_TOKEN' => nil] }
|
21
|
+
let(:cli_keys) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: access_token) }
|
22
|
+
let(:cli_keys_other) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: 'NOTTOK') }
|
23
|
+
let(:snapshot_name) { "example.com_#{DateTime.now.strftime('%Y_%m_%d')}" }
|
24
|
+
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] }
|
25
|
+
let(:default_options_cli) { default_options.reject { |key, _| %w( droplets threads ).include?(key.to_s) } }
|
26
|
+
let(:no_exclude) { [] }
|
27
|
+
let(:exclude) { %w( 100824 100825 ) }
|
28
|
+
let(:no_only) { [] }
|
29
|
+
let(:only) { %w( 100823 100824 ) }
|
30
|
+
let(:stop) { true }
|
31
|
+
let(:no_stop) { false }
|
32
|
+
let(:quiet) { true }
|
33
|
+
let(:no_quiet) { false }
|
34
|
+
let(:clean) { true }
|
35
|
+
let(:no_clean) { false }
|
36
|
+
let(:shutdown) { true }
|
37
|
+
let(:timeout) { 600 }
|
38
|
+
let(:delay) { 0 }
|
39
|
+
let(:log_path) { "#{project_path}/log/test.log" }
|
40
|
+
let(:mail_options) { Thor::CoreExt::HashWithIndifferentAccess.new(to: 'mail@somehost.com', from: 'from@host.com') }
|
41
|
+
let(:smtp_options) { Thor::CoreExt::HashWithIndifferentAccess.new(address: 'smtp.gmail.com', port: '25', user_name: 'someuser', password: 'somepassword') }
|
42
|
+
let(:log) { Thor::CoreExt::HashWithIndifferentAccess.new(log: log_path) }
|
43
|
+
|
44
|
+
def stub_all_api(droplets = nil, active = false)
|
45
|
+
drops = []
|
46
|
+
droplets ||= [droplet_id]
|
47
|
+
droplets.each do |droplet|
|
48
|
+
drops.push Hash[
|
49
|
+
stub_droplet: (active ? stub_droplet(droplet) : stub_droplet_inactive(droplet))
|
50
|
+
].merge(stub_droplet_api(droplet))
|
51
|
+
end
|
52
|
+
stubs = Hash[drops: drops]
|
53
|
+
@stubs = stubs.merge(default_stub_api)
|
54
|
+
end
|
55
|
+
|
56
|
+
def stub_droplet_api(droplet)
|
57
|
+
{
|
58
|
+
stub_droplet_stop: stub_droplet_stop(droplet),
|
59
|
+
stub_droplet_start: stub_droplet_start(droplet),
|
60
|
+
stub_droplet_snapshot: stub_droplet_snapshot(droplet, snapshot_name)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_stub_api
|
65
|
+
{
|
66
|
+
stub_event_done: stub_event_done(event_id),
|
67
|
+
stub_droplets: stub_droplets,
|
68
|
+
stub_image_destroy1: stub_image_destroy(image_id),
|
69
|
+
stub_image_destroy2: stub_image_destroy(image_id2)
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def stub_cleanup
|
74
|
+
@stubs ||= {}
|
75
|
+
@stubs.each_pair do |_k, v|
|
76
|
+
remove_request_stub(v) if v.class == WebMock::RequestStub
|
77
|
+
next unless v.class == Array
|
78
|
+
|
79
|
+
v.each do |d|
|
80
|
+
d.each_pair do |_dk, dv|
|
81
|
+
remove_request_stub(dv) if v.class == WebMock::RequestStub
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def reset_api_keys
|
88
|
+
ENV['DIGITAL_OCEAN_API_KEY'] = nil
|
89
|
+
ENV['DIGITAL_OCEAN_CLIENT_ID'] = nil
|
90
|
+
ENV['DIGITAL_OCEAN_ACCESS_TOKEN'] = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_api_keys
|
94
|
+
ENV['DIGITAL_OCEAN_API_KEY'] = api_key
|
95
|
+
ENV['DIGITAL_OCEAN_CLIENT_ID'] = client_key
|
96
|
+
ENV['DIGITAL_OCEAN_ACCESS_TOKEN'] = access_token
|
97
|
+
end
|
98
|
+
|
99
|
+
def reset_singletons
|
100
|
+
DoSnapshot.configure do |config|
|
101
|
+
# config.logger = Logger.new($stdout)
|
102
|
+
config.verbose = false
|
103
|
+
config.quiet = true
|
104
|
+
end
|
105
|
+
DoSnapshot.logger = DoSnapshot::Log.new
|
106
|
+
DoSnapshot.mailer = DoSnapshot.config.mailer
|
107
|
+
end
|
108
|
+
|
109
|
+
before(:all) do
|
110
|
+
WebMock.reset!
|
111
|
+
end
|
112
|
+
|
113
|
+
before(:each) do
|
114
|
+
do_not_send_email
|
115
|
+
set_api_keys
|
116
|
+
reset_singletons
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module DoSnapshot
|
3
|
+
module RSpec
|
4
|
+
module UriHelpers # rubocop:disable Style/Documentation
|
5
|
+
extend ::RSpec::Core::SharedContext
|
6
|
+
|
7
|
+
let(:droplet_url) { url_with_id(droplet_find_uri, droplet_id) }
|
8
|
+
let(:droplet_stop_url) { url_with_id(droplet_stop_uri, droplet_id) }
|
9
|
+
let(:droplet_start_url) { url_with_id(droplet_start_uri, droplet_id) }
|
10
|
+
let(:event_find_url) { url_with_id(event_find_uri, event_id) }
|
11
|
+
let(:image_destroy_url) { url_with_id(image_destroy_uri, image_id) }
|
12
|
+
let(:image_destroy2_url) { url_with_id(image_destroy_uri, image_id2) }
|
13
|
+
let(:action_find_url) { url_with_id(action_find_uri, event_id) }
|
14
|
+
let(:droplet_snapshot_url) { url_with_id_name(snapshot_uri, droplet_id, snapshot_name) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/do_snapshot/runner.rb
CHANGED
data/lib/do_snapshot/version.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'spec_helper'
|
3
4
|
|
4
5
|
RSpec.describe DoSnapshot::Adapter do
|
5
|
-
|
6
|
+
include DoSnapshot::RSpec::Environment
|
6
7
|
|
7
8
|
module DoSnapshot
|
8
9
|
module Adapter
|
@@ -17,7 +18,7 @@ RSpec.describe DoSnapshot::Adapter do
|
|
17
18
|
describe '#api' do
|
18
19
|
it 'when adapter' do
|
19
20
|
api = adapter.api(2)
|
20
|
-
expect(api).to be_a_kind_of(DoSnapshot::Adapter::
|
21
|
+
expect(api).to be_a_kind_of(DoSnapshot::Adapter::DropletKit)
|
21
22
|
end
|
22
23
|
|
23
24
|
it 'when custom adapter' do
|
@@ -1,12 +1,13 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'spec_helper'
|
3
4
|
|
4
5
|
RSpec.describe DoSnapshot::CLI do
|
5
|
-
|
6
|
-
|
6
|
+
include DoSnapshot::RSpec::Environment
|
7
|
+
include DoSnapshot::RSpec::ApiV2Helpers
|
7
8
|
|
8
9
|
subject(:cli) { described_class }
|
9
|
-
subject(:api) { DoSnapshot::Adapter::
|
10
|
+
subject(:api) { DoSnapshot::Adapter::DropletKit }
|
10
11
|
|
11
12
|
describe '.initialize' do
|
12
13
|
it 'with args & options' do
|
@@ -1,15 +1,16 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
# frozen_string_literal: true
|
2
3
|
require 'spec_helper'
|
3
4
|
|
4
5
|
RSpec.describe DoSnapshot::Command do
|
5
|
-
|
6
|
-
|
6
|
+
include DoSnapshot::RSpec::Environment
|
7
|
+
include DoSnapshot::RSpec::UriHelpers
|
7
8
|
|
8
9
|
subject(:cmd) { DoSnapshot::Command.new }
|
9
10
|
subject(:log) { DoSnapshot::Log }
|
10
11
|
|
11
12
|
describe 'V2' do
|
12
|
-
|
13
|
+
include DoSnapshot::RSpec::ApiV2Helpers
|
13
14
|
|
14
15
|
describe '.snap' do
|
15
16
|
context 'when success' do
|