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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -2
  3. data/bin/do_snapshot +1 -0
  4. data/lib/do_snapshot.rb +1 -0
  5. data/lib/do_snapshot/adapter.rb +10 -7
  6. data/lib/do_snapshot/adapter/abstract.rb +2 -1
  7. data/lib/do_snapshot/adapter/{digitalocean_v2.rb → droplet_kit.rb} +50 -33
  8. data/lib/do_snapshot/cli.rb +1 -0
  9. data/lib/do_snapshot/command.rb +1 -0
  10. data/lib/do_snapshot/configuration.rb +1 -0
  11. data/lib/do_snapshot/core_ext/hash.rb +1 -0
  12. data/lib/do_snapshot/distribution.rb +1 -0
  13. data/lib/do_snapshot/gem_ext/resource_kit.rb +30 -0
  14. data/lib/do_snapshot/helpers.rb +1 -0
  15. data/lib/do_snapshot/log.rb +1 -0
  16. data/lib/do_snapshot/mail.rb +1 -0
  17. data/lib/do_snapshot/rspec.rb +12 -0
  18. data/lib/do_snapshot/rspec/adapter.rb +265 -0
  19. data/lib/do_snapshot/rspec/api_helpers.rb +45 -0
  20. data/lib/do_snapshot/rspec/api_v2_helpers.rb +157 -0
  21. data/lib/do_snapshot/rspec/environment.rb +120 -0
  22. data/lib/do_snapshot/rspec/uri_helpers.rb +17 -0
  23. data/lib/do_snapshot/runner.rb +1 -0
  24. data/lib/do_snapshot/version.rb +2 -1
  25. data/spec/do_snapshot/adapter/abstract_spec.rb +2 -1
  26. data/spec/do_snapshot/adapter/droplet_kit_spec.rb +9 -0
  27. data/spec/do_snapshot/adapter_spec.rb +3 -2
  28. data/spec/do_snapshot/cli_spec.rb +4 -3
  29. data/spec/do_snapshot/command_spec.rb +4 -3
  30. data/spec/do_snapshot/configuration_spec.rb +1 -0
  31. data/spec/do_snapshot/log_spec.rb +2 -1
  32. data/spec/do_snapshot/mail_spec.rb +2 -1
  33. data/spec/do_snapshot/runner_spec.rb +3 -2
  34. data/spec/do_snapshot_spec.rb +2 -1
  35. data/spec/spec_helper.rb +2 -4
  36. data/spec/support/aruba.rb +1 -0
  37. data/spec/support/matchers.rb +1 -0
  38. metadata +47 -20
  39. data/spec/do_snapshot/adapter/digitalocean_v2_spec.rb +0 -264
  40. data/spec/shared/api_helpers.rb +0 -41
  41. data/spec/shared/api_v2_helpers.rb +0 -153
  42. data/spec/shared/environment.rb +0 -116
  43. data/spec/shared/uri_helpers.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95c8aa6d9470c9eae1cc0f27b822e15b17d2bb61
4
- data.tar.gz: 90ace05ddc9bf40be16447f3880390a9168eb072
3
+ metadata.gz: eb7ae5cc912690b2cd5850c46fd364ced760b5dd
4
+ data.tar.gz: a1664c690b7940bc93f6ae58904ff111af531551
5
5
  SHA512:
6
- metadata.gz: b460b5736c090dd0345989d134068442d1589759e05f118e8e30b9a910d4e5acc80987640ae27f642ff536d872ae088c02383ad690b739dd9407ca6bec32246d
7
- data.tar.gz: d1a35778507e3d9379df0678aa78186ca3a079507c163e7ac8a752a5e39ec2f744eba576a34b9db27a41bae25074de4211cf59875f8dead74cadfd3d582e86e7
6
+ metadata.gz: b2554982045d10d24c5d054ae03dd51cd7745412d64eb5da06dca91d0b3b46e5391ef71725ff3f8407ac86c9a4564963e362e6f2f8c3819db0fde574dcd0fe26
7
+ data.tar.gz: eb9d432913d910285373520713a695ac5572303517de158a13921f5d8bad1739c8bcc0b505d7a349c1b58454350c4ede9992c04052115fdbcece902353dc4c1f
data/README.md CHANGED
@@ -13,6 +13,7 @@
13
13
  Use this tool to backup DigitalOcean droplet's via snapshot method, on the fly!
14
14
 
15
15
  ## API Changes:
16
+ - 20.08.17: Change `Barge` to `DropletKit`. Release `1.0.0`.
16
17
  - 03.08.16: DO now automagically keeps our droplets running when snapshot is processing, so:
17
18
  Added options `--shutdown`, `--no-shutdown`.
18
19
  `shutdown` now disabled by default, no downtime anymore, `YES`!
@@ -36,7 +37,13 @@ Here are some features:
36
37
 
37
38
  ## Compatibility
38
39
 
39
- Ruby versions 1.9.3 and higher. JRuby 1.7, 9.0.0.0 or later is also supported.
40
+ From `1.0.0`:
41
+ - Ruby version 2.0.0 or higher
42
+ - JRuby 9.1.0.0 or higher
43
+
44
+ Prior to `0.6.4`:
45
+ - Ruby version 1.9.3 or higher
46
+ - JRuby 1.7, 9.0.0.0 or higher
40
47
 
41
48
  <img src="https://raw.githubusercontent.com/merqlove/do_snapshot/master/assets/example.png" style="max-width:100%" alt="DoSnaphot example">
42
49
 
@@ -195,7 +202,7 @@ Support this project and others by [merqlove](https://gratipay.com/~merqlove/) v
195
202
  ## Dependencies:
196
203
 
197
204
  - [Thor](https://github.com/erikhuda/thor) for CLI.
198
- - [Barge](https://github.com/blom/barge) for API V2 requests.
205
+ - [DropletKit](https://github.com/digitalocean/droplet_kit) for API V2 requests.
199
206
  - [Pony](https://github.com/benprew/pony) for mail notifications.
200
207
 
201
208
  ## Contributing
data/bin/do_snapshot CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- encoding : utf-8 -*-
3
+ # frozen_string_literal: true
3
4
 
4
5
  Signal.trap('INT') { exit 1 }
5
6
 
data/lib/do_snapshot.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require_relative 'do_snapshot/version'
3
4
  require_relative 'do_snapshot/configuration'
4
5
 
@@ -1,29 +1,32 @@
1
+ # frozen_string_literal: true
1
2
  module DoSnapshot
2
3
  # Adapter interface for API connections
3
4
  # Ability to select DigitalOcean API versions.
4
5
  #
5
6
  module Adapter
6
7
  autoload :Abstract, 'do_snapshot/adapter/abstract'
7
- autoload :DigitaloceanV2, 'do_snapshot/adapter/digitalocean_v2'
8
+ autoload :DropletKit, 'do_snapshot/adapter/droplet_kit'
8
9
 
9
10
  class << self
10
11
  def api(protocol, options = {})
11
12
  konst = find_protocol(protocol)
12
- fail DoSnapshot::NoProtocolError, "Not existing protocol: #{protocol}." unless
13
- DoSnapshot::Adapter.const_defined?(konst)
13
+ error_protocol(protocol) unless DoSnapshot::Adapter.const_defined?(konst)
14
14
  obj = DoSnapshot::Adapter.const_get(konst)
15
15
  obj.new(options)
16
16
  end
17
17
 
18
18
  private
19
19
 
20
+ def error_protocol(protocol)
21
+ fail DoSnapshot::NoProtocolError, "Not existing protocol: #{protocol}."
22
+ end
23
+
20
24
  def find_protocol(protocol)
21
- if protocol.is_a?(Integer)
22
- "DigitaloceanV#{protocol}"
23
- elsif protocol.is_a?(String)
25
+ if protocol.is_a?(String)
24
26
  protocol
25
27
  else
26
- 'DigitaloceanV2'
28
+ error_protocol(protocol) if protocol.is_a?(Integer) && protocol < 2
29
+ 'DropletKit'
27
30
  end
28
31
  end
29
32
  end
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
 
3
4
  module DoSnapshot
4
5
  module Adapter
@@ -25,7 +26,7 @@ module DoSnapshot
25
26
  # noinspection RubyResolve
26
27
  instance = droplet(id)
27
28
 
28
- return power_on(id) unless instance.status.include?('active')
29
+ return power_on(id) if instance.respond_to?(:status) && !instance.status.include?('active')
29
30
 
30
31
  logger.error "Droplet #{id} is still running. Skipping."
31
32
  end
@@ -1,73 +1,86 @@
1
1
  # -*- encoding : utf-8 -*-
2
- require 'barge' unless defined?(::Barge)
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../gem_ext/resource_kit'
5
+ require 'droplet_kit' unless defined?(::DropletKit)
3
6
 
4
7
  module DoSnapshot
5
8
  module Adapter
6
9
  # API for CLI commands
7
10
  # Operating with Digital Ocean.
8
11
  #
9
- class DigitaloceanV2 < Abstract
10
- attr_reader :client
12
+ class DropletKit < Abstract
13
+ attr_reader :client, :per_page, :page
14
+
15
+ def initialize(*args)
16
+ @per_page = 1000
17
+ @page = 1
18
+ super(*args)
19
+ end
11
20
 
12
21
  # Get single droplet from DigitalOcean
13
22
  #
14
23
  def droplet(id)
15
24
  # noinspection RubyResolve
16
- response = client.droplet.show(id)
17
- fail DropletFindError.new(id), response.message unless response.respond_to?(:droplet)
18
- response.droplet
25
+ result = client.droplets.find(id: id)
26
+ fail DropletFindError, id unless result
27
+ result
28
+ rescue ::DropletKit::Error => e
29
+ raise DropletFindError, id unless e.message
19
30
  end
20
31
 
21
32
  # Get droplets list from DigitalOcean
22
33
  #
23
34
  def droplets
24
35
  # noinspection RubyResolve
25
- response = client.droplet.all
26
- fail DropletListError, response.message unless response.respond_to?(:droplets)
27
- response.droplets
36
+ response = client.droplets.all(page: page, per_page: per_page)
37
+ response.many?
38
+ response
39
+ rescue ::NoMethodError => e
40
+ fail DropletListError, e
28
41
  end
29
42
 
30
43
  def snapshots(instance)
31
- instance.snapshot_ids
44
+ instance.snapshot_ids if instance.respond_to?(:snapshot_ids)
32
45
  end
33
46
 
34
47
  # Request Power On for droplet
35
48
  #
36
49
  def power_on(id)
37
50
  # noinspection RubyResolve
38
- response = client.droplet.power_on(id)
51
+ response = client.droplet_actions.power_on(droplet_id: id)
39
52
 
40
- fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:action)
41
-
42
- if response.action.status.include?('in-progress')
53
+ if response.status.include?('in-progress')
43
54
  logger.info "Droplet id: #{id} is requested for Power On."
44
55
  else
45
56
  logger.error "Droplet id: #{id} is failed to request for Power On."
46
57
  end
58
+ rescue ::DropletKit::Error => e
59
+ fail DoSnapshot::EventError.new(id), e.message
47
60
  end
48
61
 
49
62
  # Power Off request for Droplet
50
63
  #
51
64
  def stop_droplet(id)
52
65
  # noinspection RubyResolve,RubyResolve
53
- response = client.droplet.power_off(id)
54
-
55
- fail DropletShutdownError.new(id), response.message unless response.respond_to?(:action)
66
+ response = client.droplet_actions.power_off(droplet_id: id)
56
67
 
57
68
  # noinspection RubyResolve
58
- wait_shutdown(id, response.action.id)
69
+ wait_shutdown(id, response.id)
70
+ rescue ::DropletKit::Error => e
71
+ fail DropletShutdownError.new(id), e.message
59
72
  end
60
73
 
61
74
  # Sending event to create snapshot via DigitalOcean API and wait for success
62
75
  #
63
76
  def create_snapshot(id, name)
64
77
  # noinspection RubyResolve,RubyResolve
65
- response = client.droplet.snapshot(id, name: name)
66
-
67
- fail DoSnapshot::SnapshotCreateError.new(id), response.message unless response.respond_to?(:action)
78
+ response = client.droplet_actions.snapshot(droplet_id: id, name: name)
68
79
 
69
80
  # noinspection RubyResolve
70
- wait_event(response.action.id)
81
+ wait_event(response.id)
82
+ rescue ::DropletKit::Error => e
83
+ fail DoSnapshot::SnapshotCreateError.new(id), e.message
71
84
  end
72
85
 
73
86
  # Checking if droplet is powered off.
@@ -75,7 +88,7 @@ module DoSnapshot
75
88
  def inactive?(id)
76
89
  instance = droplet(id)
77
90
 
78
- instance.status.include?('off')
91
+ instance.status.include?('off') if instance.respond_to?(:status)
79
92
  end
80
93
 
81
94
  # Cleanup our snapshots.
@@ -83,12 +96,8 @@ module DoSnapshot
83
96
  def cleanup_snapshots(instance, size)
84
97
  (0..size).each do |i|
85
98
  # noinspection RubyResolve
86
- snapshot = instance.snapshot_ids[i]
87
- action = client.image.destroy(snapshot)
88
-
89
- logger.debug action unless action.success?
90
-
91
- after_cleanup(instance.id, instance.name, snapshot, action)
99
+ snapshot = snapshots(instance)[i]
100
+ delete_image(instance, snapshot)
92
101
  end
93
102
  end
94
103
 
@@ -103,13 +112,21 @@ module DoSnapshot
103
112
  #
104
113
  def set_id
105
114
  logger.debug 'Setting DigitalOcean Access Token.'
106
- @client = ::Barge::Client.new(access_token: ENV['DIGITAL_OCEAN_ACCESS_TOKEN'], timeout: 15, open_timeout: 15)
115
+ @client = ::DropletKit::Client.new(access_token: ENV['DIGITAL_OCEAN_ACCESS_TOKEN'])
107
116
  end
108
117
 
109
118
  protected
110
119
 
120
+ def delete_image(instance, snapshot) # rubocop:disable Metrics/AbcSize
121
+ action = client.images.delete(id: snapshot)
122
+ after_cleanup(instance.id, instance.name, snapshot, action)
123
+ rescue ::DropletKit::Error => e
124
+ logger.debug "#{snapshot} #{e.message}"
125
+ after_cleanup(instance.id, instance.name, snapshot, false)
126
+ end
127
+
111
128
  def after_cleanup(droplet_id, droplet_name, snapshot, action)
112
- if !action.success?
129
+ if !action
113
130
  logger.error "Destroy of snapshot #{snapshot} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
114
131
  else
115
132
  logger.debug "Snapshot: #{snapshot} delete requested."
@@ -121,9 +138,9 @@ module DoSnapshot
121
138
  def get_event_status(id, time)
122
139
  return true if timeout?(id, time)
123
140
 
124
- response = client.action.show(id)
141
+ response = client.actions.find(id: id)
125
142
 
126
- fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:action)
143
+ fail DoSnapshot::EventError.new(id), response.message unless response.respond_to?(:status)
127
144
 
128
145
  # noinspection RubyResolve,RubyResolve
129
146
  response.action.status.include?('completed') ? true : false
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'thor'
3
4
  require 'do_snapshot'
4
5
  require_relative 'log'
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require_relative 'adapter'
3
4
 
4
5
  module DoSnapshot
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module DoSnapshot
2
3
  # Configuration class. Used to share config across application.
3
4
  #
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  # Rails symbolize keys methods for Hash
3
4
  #
4
5
  class Hash
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  module DoSnapshot
3
4
  # Distributive files
4
5
  # Used part of Heroku script https://github.com/heroku/heroku
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ require 'resource_kit'
3
+
4
+ # TODO: Remove after `resource_kit` gem update.
5
+ ResourceKit::Action.class_eval do
6
+ def handler(*response_codes, &block)
7
+ if response_codes.empty?
8
+ handlers[:any] = block
9
+ else
10
+ response_codes.each do |code|
11
+ code = ResourceKit::StatusCodeMapper.code_for(code) unless code.is_a?(Integer)
12
+ handlers[code] = block
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ # TODO: Remove after `resource_kit` gem update.
19
+ ResourceKit::ResourceCollection.class_eval do
20
+ def default_handler(*response_codes, &block)
21
+ if response_codes.empty?
22
+ default_handlers[:any] = block
23
+ else
24
+ response_codes.each do |code|
25
+ code = ResourceKit::StatusCodeMapper.code_for(code) unless code.is_a?(Integer)
26
+ default_handlers[code] = block
27
+ end
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'log'
2
3
  require_relative 'mail'
3
4
 
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'logger'
3
4
  require 'hashie'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
+ # frozen_string_literal: true
2
3
  require 'date'
3
4
  require 'pony'
4
5
  require_relative 'core_ext/hash'
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'rspec/core/shared_context'
3
+
4
+ module DoSnapshot
5
+ module RSpec # rubocop:disable Style/Documentation
6
+ autoload :Adapter, 'do_snapshot/rspec/adapter'
7
+ autoload :ApiHelpers, 'do_snapshot/rspec/api_helpers'
8
+ autoload :ApiV2Helpers, 'do_snapshot/rspec/api_v2_helpers'
9
+ autoload :Environment, 'do_snapshot/rspec/environment'
10
+ autoload :UriHelpers, 'do_snapshot/rspec/uri_helpers'
11
+ end
12
+ end
@@ -0,0 +1,265 @@
1
+ # frozen_string_literal: true
2
+ module DoSnapshot
3
+ module RSpec
4
+ module Adapter # rubocop:disable Style/Documentation,Metrics/ModuleLength
5
+ extend ::RSpec::Core::SharedContext
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 UriHelpers
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(DoSnapshot::DropletFindError)
43
+ expect(DoSnapshot.logger.buffer)
44
+ .to include "Droplet id: #{droplet_id} 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
+ expect(instance.droplets.many?).to be_truthy
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(DoSnapshot::DropletListError)
65
+ expect(DoSnapshot.logger.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(DoSnapshot.logger.buffer).to include "Droplet id: #{droplet_id} is requested for Power On."
80
+
81
+ expect(a_request(:post, 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(DoSnapshot.logger.buffer)
93
+ .to include "Droplet #{droplet_id} is still running. Skipping."
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(DoSnapshot::DropletFindError)
104
+
105
+ expect(a_request(:get, droplet_url))
106
+ .to have_been_made
107
+ end
108
+ end
109
+
110
+ describe '.stop_droplet by power status' do
111
+ let(:instance) { api.new(delay: delay, timeout: timeout, stop_by: :power_status) }
112
+
113
+ it 'with success' do
114
+ stub_event_done(event_id)
115
+ stub_droplet_stop(droplet_id)
116
+ stub_droplet_inactive(droplet_id)
117
+
118
+ instance.stop_droplet(droplet_id)
119
+
120
+ expect(a_request(:post, droplet_stop_url))
121
+ .to have_been_made
122
+ expect(a_request(:get, droplet_url))
123
+ .to have_been_made
124
+ end
125
+
126
+ it 'with error' do
127
+ stub_droplet_stop_fail(droplet_id)
128
+ stub_droplet(droplet_id)
129
+ instance.timeout = 1
130
+ expect { instance.stop_droplet(droplet_id) }
131
+ .to raise_error(DoSnapshot::DropletShutdownError)
132
+ instance.timeout = timeout
133
+ expect(DoSnapshot.logger.buffer)
134
+ .to include 'Droplet id: 100823 is Failed to Power Off.'
135
+
136
+ expect(a_request(:post, droplet_stop_url))
137
+ .to have_been_made
138
+ end
139
+ end
140
+
141
+ describe '.stop_droplet by event' do
142
+ it 'with success' do
143
+ stub_event_done(event_id)
144
+ stub_droplet_stop(droplet_id)
145
+
146
+ instance.stop_droplet(droplet_id)
147
+
148
+ expect(a_request(:post, droplet_stop_url))
149
+ .to have_been_made
150
+ expect(a_request(:get, action_find_url))
151
+ .to have_been_made
152
+ end
153
+
154
+ it 'with error' do
155
+ stub_droplet_stop_fail(droplet_id)
156
+
157
+ expect { instance.stop_droplet(droplet_id) }
158
+ .to raise_error(DoSnapshot::DropletShutdownError)
159
+ expect(DoSnapshot.logger.buffer)
160
+ .to include 'Droplet id: 100823 is Failed to Power Off.'
161
+
162
+ expect(a_request(:post, droplet_stop_url))
163
+ .to have_been_made
164
+ end
165
+ end
166
+
167
+ describe '.create_snapshot' do
168
+ it 'with success' do
169
+ stub_event_done(event_id)
170
+ stub_droplet_snapshot(droplet_id, snapshot_name)
171
+
172
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
173
+ .not_to raise_error
174
+
175
+ expect(a_request(:post, droplet_snapshot_url))
176
+ .to have_been_made
177
+ expect(a_request(:get, action_find_url))
178
+ .to have_been_made
179
+ end
180
+
181
+ it 'with error' do
182
+ stub_droplet_snapshot_fail(droplet_id, snapshot_name)
183
+
184
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
185
+ .to raise_error(DoSnapshot::SnapshotCreateError)
186
+
187
+ expect(a_request(:post, droplet_snapshot_url))
188
+ .to have_been_made
189
+ end
190
+
191
+ it 'with event error' do
192
+ stub_droplet_snapshot(droplet_id, snapshot_name)
193
+ stub_event_fail(event_id)
194
+
195
+ expect { instance.create_snapshot(droplet_id, snapshot_name) }
196
+ .not_to raise_error
197
+ expect(DoSnapshot.logger.buffer)
198
+ .to include "Event id: #{event_id} is failed!"
199
+
200
+ expect(a_request(:post, droplet_snapshot_url))
201
+ .to have_been_made
202
+ expect(a_request(:get, action_find_url))
203
+ .to have_been_made
204
+ end
205
+ end
206
+
207
+ describe '.inactive?' do
208
+ it 'when inactive' do
209
+ stub_droplet_inactive(droplet_id)
210
+
211
+ expect(instance.inactive?(droplet_id))
212
+ .to be_truthy
213
+ end
214
+
215
+ it 'when active' do
216
+ stub_droplet(droplet_id)
217
+
218
+ expect(instance.inactive?(droplet_id))
219
+ .to be_falsey
220
+ end
221
+ end
222
+
223
+ describe '.cleanup_snapshots' do
224
+ it 'with success' do
225
+ stub_droplet(droplet_id)
226
+ stub_image_destroy(image_id)
227
+ stub_image_destroy(image_id2)
228
+
229
+ droplet = instance.droplet(droplet_id)
230
+ expect { instance.cleanup_snapshots(droplet, 1) }
231
+ .not_to raise_error
232
+ expect(DoSnapshot.logger.buffer)
233
+ .to include 'Snapshot: 5019770 delete requested.'
234
+
235
+ expect(a_request(:get, droplet_url))
236
+ .to have_been_made
237
+ expect(a_request(:delete, image_destroy_url))
238
+ .to have_been_made
239
+ expect(a_request(:delete, image_destroy2_url))
240
+ .to have_been_made
241
+ end
242
+
243
+ it 'with warning message' do
244
+ stub_droplet(droplet_id)
245
+ stub_image_destroy_fail(image_id)
246
+ stub_image_destroy_fail(image_id2)
247
+
248
+ droplet = instance.droplet(droplet_id)
249
+ expect { instance.cleanup_snapshots(droplet, 1) }
250
+ .not_to raise_error
251
+ expect(DoSnapshot.logger.buffer)
252
+ .to include 'Destroy of snapshot 5019903 for droplet id: 100823 name: example.com is failed.'
253
+
254
+ expect(a_request(:get, droplet_url))
255
+ .to have_been_made
256
+ expect(a_request(:delete, image_destroy_url))
257
+ .to have_been_made
258
+ expect(a_request(:delete, image_destroy2_url))
259
+ .to have_been_made
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end