Skip to content

Commit

Permalink
Don't shutdown droplets by default.
Browse files Browse the repository at this point in the history
Add specs for this behavior.
Add docs.
  • Loading branch information
merqlove committed Aug 3, 2016
1 parent ff7a3ae commit b253660
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 10 deletions.
7 changes: 6 additions & 1 deletion README.md
Expand Up @@ -13,6 +13,10 @@
Use this tool to backup DigitalOcean droplet's via snapshot method, on the fly!

## API Changes:
- 03.08.16: DO now automagically keeps our droplets running when snapshot is processing, so:
Added options `--shutdown`, `--no-shutdown`.
`shutdown` now disabled by default, no downtime anymore, `YES`!
If you want `shutdown` back use `--shutdown` option.
- 08.01.16: now we have to use DO API V2 only, because V1 is not work anymore.
- 17.10.15: now we use DO API V2 by default, due V1 deprecation at 11.2015.

Expand Down Expand Up @@ -147,6 +151,7 @@ For working mailer you need to set e-mail settings via run options.
Options:
-p, [--protocol=1] # Select api version.
# Default: 2
[--shutdown], [--no-shutdown] # Check if you want to stop your droplet before the snapshot.
-o, [--only=123456 123456 123456] # Select some droplets.
-e, [--exclude=123456 123456 123456] # Except some droplets.
-k, [--keep=5] # How much snapshots you want to keep?
Expand All @@ -160,7 +165,7 @@ For working mailer you need to set e-mail settings via run options.
-l, [--log=/Users/someone/.do_snapshot/main.log] # Log file path. By default logging is disabled.
-c, [--clean], [--no-clean] # Cleanup snapshots after create. If you have more images than you want to `keep`, older will be deleted.
-s, [--stop], [--no-stop] # Stop creating snapshots if maximum is reached.
[--stop-by-power], [--no-stop-by-power] # Check if droplet stopped by its power status instead of waiting for event completed state.
[--stop-by-power], [--no-stop-by-power] # Droplet stop method, by it's power status (instead of waiting for event completed state).
-v, [--trace], [--no-trace] # Verbose mode.
-q, [--quiet], [--no-quiet] # Quiet mode. If don't need any messages in console.
[--digital-ocean-access-token=YOURLONGAPITOKEN] # DIGITAL_OCEAN_ACCESS_TOKEN. if you can't use environment.
Expand Down
6 changes: 5 additions & 1 deletion lib/do_snapshot/cli.rb
Expand Up @@ -82,6 +82,10 @@ def initialize(*args)
aliases: %w( -p ),
banner: '1',
desc: 'Select api version.'
method_option :shutdown,
default: false,
type: :boolean,
desc: 'Check if you want to stop droplet before the snapshot.'
method_option :only,
type: :array,
default: [],
Expand Down Expand Up @@ -137,7 +141,7 @@ def initialize(*args)
desc: 'Stop creating snapshots if maximum is reached.'
method_option :stop_by_power,
type: :boolean,
desc: 'Check if droplet stopped by its power status instead of waiting for event completed state.'
desc: "Droplet stop method, by it's power status (instead of waiting for event completed state)."
method_option :trace,
type: :boolean,
aliases: %w( -v ),
Expand Down
10 changes: 8 additions & 2 deletions lib/do_snapshot/command.rb
Expand Up @@ -7,6 +7,10 @@ module DoSnapshot
class Command # rubocop:disable ClassLength
include DoSnapshot::Helpers

RESET_OPTIONS = [:droplets, :exclude, :only, :keep, :quiet,
:stop, :clean, :timeout, :shutdown, :delay,
:protocol, :threads, :api]

def initialize(*args)
load_options(*args)
end
Expand All @@ -21,6 +25,7 @@ def snap
end

def fail_power_off(e)
return unless shutdown
return unless e && e.id
api.start_droplet(e.id)
rescue
Expand All @@ -35,12 +40,13 @@ def load_options(options = {}, skip = %w())
end

def reset_options
[:droplets, :exclude, :only, :keep, :quiet, :stop, :clean, :timeout, :delay, :protocol, :threads, :api].each do |key|
RESET_OPTIONS.each do |key|
send("#{key}=", nil)
end
end

def stop_droplet(droplet)
return true unless shutdown
logger.debug 'Shutting down droplet.'
api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
true
Expand Down Expand Up @@ -104,7 +110,7 @@ def processed_droplet_ids
protected

attr_accessor :droplets, :exclude, :only
attr_accessor :keep, :quiet, :stop, :stop_by_power, :clean, :timeout, :delay, :protocol
attr_accessor :keep, :quiet, :shutdown, :stop, :stop_by_power, :clean, :timeout, :delay, :protocol

attr_writer :threads, :api

Expand Down
8 changes: 8 additions & 0 deletions spec/do_snapshot/cli_spec.rb
Expand Up @@ -75,6 +75,14 @@
attribute_eq 'stop', false
end

it 'with shutdown' do
attribute_eq 'shutdown', true
end

it 'with no shutdown' do
attribute_eq 'shutdown', false
end

it 'with stop by power' do
attribute_eq 'stop_by_power', true
end
Expand Down
49 changes: 44 additions & 5 deletions spec/do_snapshot/command_spec.rb
Expand Up @@ -113,7 +113,7 @@
describe '.stop_droplet by power status' do
it 'when raised with error' do
stub_droplet_stop_fail(droplet_id)
load_options(stop_by_power: true)
load_options(stop_by_power: true, shutdown: true)
droplet = cmd.api.droplet droplet_id
expect { cmd.stop_droplet(droplet) }
.not_to raise_error
Expand All @@ -124,7 +124,17 @@
it 'when stopped' do
stub_droplet_inactive(droplet_id)
stub_droplet_stop(droplet_id)
load_options(stop_by_power: true)
load_options(stop_by_power: true, shutdown: true)
droplet = cmd.api.droplet droplet_id
expect { cmd.stop_droplet(droplet) }
.not_to raise_error
expect(cmd.stop_droplet(droplet))
.to be_truthy
end

it 'when nothing' do
stub_droplet(droplet_id)
load_options(stop_by_power: true, shutdown: false)
droplet = cmd.api.droplet droplet_id
expect { cmd.stop_droplet(droplet) }
.not_to raise_error
Expand Down Expand Up @@ -154,6 +164,16 @@
expect(cmd.stop_droplet(droplet))
.to be_truthy
end

it 'when nothing' do
stub_droplet(droplet_id)
load_options(shutdown: false)
droplet = cmd.api.droplet droplet_id
expect { cmd.stop_droplet(droplet) }
.not_to raise_error
expect(cmd.stop_droplet(droplet))
.to be_truthy
end
end

describe '.create_snapshot' do
Expand All @@ -176,6 +196,16 @@
.not_to raise_error
end

it 'when snapshot is created with no shutdown' do
stub_droplet(droplet_id)
stub_droplet_snapshot(droplet_id, snapshot_name)
load_options(shutdown: false)
droplet = cmd.api.droplet droplet_id
cmd.create_snapshot(droplet)
expect { cmd.create_snapshot(droplet) }
.not_to raise_error
end

it 'when droplet is running' do
stub_droplet(droplet_id)
load_options
Expand All @@ -191,16 +221,25 @@
describe '.fail_power_off' do
it 'when success' do
stub_droplet_inactive(droplet_id)

load_options(shutdown: true)
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
.not_to raise_error
expect(DoSnapshot.logger.buffer)
.to include "Droplet id: #{droplet_id} is requested for Power On."
end

it 'with request error' do
it 'not rescue when shutdown is true' do
stub_droplet_fail(droplet_id)
load_options(shutdown: false)
expect { cmd.fail_power_off(DoSnapshot::SnapshotCreateError.new(droplet_id)) }
.not_to raise_error
expect(DoSnapshot.logger.buffer)
.to include "Droplet id: #{droplet_id} is Failed to Snapshot."
end

it 'with request error' do
stub_droplet_fail(droplet_id)
load_options(shutdown: true)
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
.to raise_error(DoSnapshot::DropletFindError)
expect(DoSnapshot.logger.buffer)
Expand All @@ -212,7 +251,7 @@
it 'with start error' do
stub_droplet_inactive(droplet_id)
stub_droplet_start_done(droplet_id)

load_options(shutdown: true)
expect { cmd.fail_power_off(DoSnapshot::DropletShutdownError.new(droplet_id)) }
.not_to raise_error
expect(DoSnapshot.logger.buffer)
Expand Down
18 changes: 18 additions & 0 deletions spec/do_snapshot/runner_spec.rb
Expand Up @@ -109,6 +109,24 @@
expect(all_stdout).to include(t_snapshot_created(snapshot_name))
end

it 'with shutdown' do
attribute_eq 'shutdown', true

expect(last_command).to have_exit_status(0)
expect(all_stdout).to include(t_droplet_shutdown)
expect(all_stdout).to include(t_wait_until_create)
expect(all_stdout).to include(t_snapshot_created(snapshot_name))
end

it 'with no shutdown' do
attribute_eq 'shutdown', false

expect(last_command).to have_exit_status(0)
expect(all_stdout).not_to include(t_droplet_shutdown)
expect(all_stdout).to include(t_wait_until_create)
expect(all_stdout).to include(t_snapshot_created(snapshot_name))
end

it 'with stop by power' do
attribute_eq 'stop_by_power', true

Expand Down
3 changes: 2 additions & 1 deletion spec/shared/environment.rb
Expand Up @@ -19,7 +19,7 @@ def do_not_send_email
let(:cli_keys) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: access_token) }
let(:cli_keys_other) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_access_token: 'NOTTOK') }
let(:snapshot_name) { "example.com_#{DateTime.now.strftime('%Y_%m_%d')}" }
let(:default_options) { Hash[protocol: 2, only: %w( 100823 ), exclude: %w(), keep: 3, stop: false, trace: true, clean: true, delay: 0, timeout: 600] }
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] }
let(:default_options_cli) { default_options.reject { |key, _| %w( droplets threads ).include?(key.to_s) } }
let(:no_exclude) { [] }
let(:exclude) { %w( 100824 100825 ) }
Expand All @@ -31,6 +31,7 @@ def do_not_send_email
let(:no_quiet) { false }
let(:clean) { true }
let(:no_clean) { false }
let(:shutdown) { true }
let(:timeout) { 600 }
let(:delay) { 0 }
let(:log_path) { "#{project_path}/log/test.log" }
Expand Down

0 comments on commit b253660

Please sign in to comment.