Skip to content

Commit

Permalink
Update rubocop.
Browse files Browse the repository at this point in the history
Added rubies 2.1.5, 2.2.0 into Travis.
Fix style guide.
Refactored Command & API for better code & code style.
Added specs for Command.create_snapshot & Command.stop_droplet methods.
Moved .stop_droplet, .create_snapshot, .api method into the public in Command.
Dropped options setup from Command.snap., for .load_options method.
  • Loading branch information
merqlove committed Jan 10, 2015
1 parent 5cfd623 commit 3c78710
Show file tree
Hide file tree
Showing 12 changed files with 148 additions and 93 deletions.
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ TrailingComma:
AllCops:
Exclude:
- '*.gemspec'
- 'dist/*'
- 'dist/**/*'
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.3
2.2.0
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
language: ruby
rvm:
- 2.2.0
- 2.1.5
- 2.1.3
- 1.9.3
- jruby-19mode
Expand Down
1 change: 1 addition & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# rubocop:disable Lint/ShadowingOuterLocalVariable
# rubocop:disable Style/MultilineTernaryOperator
# rubocop:disable Lint/HandleExceptions
# rubocop:disable Metrics/AbcSize
require 'rubygems'

PROJECT_ROOT = File.expand_path('..', __FILE__)
Expand Down
18 changes: 11 additions & 7 deletions lib/do_snapshot/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,7 @@ def cleanup_snapshots(instance, size) # rubocop:disable MethodLength
snapshot = instance.snapshots[i]
event = Digitalocean::Image.destroy(snapshot.id)

if !event
Log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{instance.id} name: #{instance.name} is failed."
elsif event && !event.status.include?('OK')
Log.error event.message
else
Log.debug "Snapshot name: #{snapshot.name} delete requested."
end
after_cleanup(instance.id, instance.name, snapshot, event)
end
end

Expand Down Expand Up @@ -136,5 +130,15 @@ def power_on(id)
Log.error 'Power On failed to request.'
end
end

def after_cleanup(droplet_id, droplet_name, snapshot, event)
if !event
Log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
elsif event && !event.status.include?('OK')
Log.error event.message
else
Log.debug "Snapshot name: #{snapshot.name} delete requested."
end
end
end
end
17 changes: 11 additions & 6 deletions lib/do_snapshot/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,13 @@ def initialize(*args)
desc: 'DIGITAL_OCEAN_API_KEY. if you can\'t use environment.'

def snap
Command.snap options, %w( log mail smtp trace digital_ocean_client_id digital_ocean_api_key )
Command.load_options options, %w( log mail smtp trace digital_ocean_client_id digital_ocean_api_key )
Command.snap
rescue => e
Command.fail_power_off(e) if [SnapshotCreateError, DropletShutdownError].include?(e.class)
Log.error e.message
backtrace(e) if options.include? 'trace'
if Mail.opts
Mail.opts[:subject] = 'Digital Ocean: Error.'
Mail.opts[:body] = 'Please check your droplets.'
Mail.notify
end
send_error
end

desc 'version, -V', 'Shows the version of the currently installed DoSnapshot gem'
Expand All @@ -160,6 +157,14 @@ def set_mailer
Mail.smtp = options['smtp']
end

def send_error
return unless Mail.opts

Mail.opts[:subject] = 'Digital Ocean: Error.'
Mail.opts[:body] = 'Please check your droplets.'
Mail.notify
end

def set_logger
Log.quiet = options['quiet']
Log.verbose = options['trace']
Expand Down
141 changes: 71 additions & 70 deletions lib/do_snapshot/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,73 @@ module DoSnapshot
#
class Command # rubocop:disable ClassLength
class << self
def snap(options, skip)
return unless options

options.each_pair do |key, option|
send("#{key}=", option) unless skip.include?(key)
end

def snap
Log.info 'Start performing operations'
work_with_droplets
Log.info 'All operations has been finished.'

Mail.notify if notify && !quiet
end

def load_options(options = {}, skip = %w())
options.each_pair do |key, option|
send("#{key}=", option) unless skip.include?(key)
end if options
end

def fail_power_off(e)
return unless e && e.id
api.start_droplet(e.id)
rescue
raise DropletFindError, e.message, e.backtrace
end

protected
def stop_droplet(droplet)
Log.debug 'Shutting down droplet.'
api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
end

attr_accessor :droplets, :exclude, :only
attr_accessor :keep, :quiet, :stop, :clean, :timeout, :delay
# Trying to create a snapshot.
#
def create_snapshot(droplet) # rubocop:disable MethodLength,Metrics/AbcSize
Log.info "Start creating snapshot for droplet id: #{droplet.id} name: #{droplet.name}."

attr_writer :notify, :threads, :api
today = DateTime.now
name = "#{droplet.name}_#{today.strftime('%Y_%m_%d')}"
# noinspection RubyResolve
snapshot_size = droplet.snapshots.size

Log.debug 'Wait until snapshot will be created.'

api.create_snapshot droplet.id, name

snapshot_size += 1

Log.info "Snapshot name: #{name} created successfully."
Log.info "Droplet id: #{droplet.id} name: #{droplet.name} snapshots: #{snapshot_size}."

# Cleanup snapshots.
cleanup_snapshots droplet, snapshot_size if clean
rescue => e
case e.class.to_s
when 'DoSnapshot::SnapshotCleanupError'
raise e.class, e.message, e.backtrace
else
raise SnapshotCreateError.new(droplet.id), e.message, e.backtrace
end
end

def api
@api ||= API.new(delay: delay, timeout: timeout)
end

protected

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

attr_writer :notify, :threads, :api

def notify
@notify ||= false
end
Expand Down Expand Up @@ -69,12 +104,9 @@ def dispatch_droplets
droplets.each do |droplet|
id = droplet.id.to_s
next if exclude.include? id
next if !only.empty? && !only.include?(id)

Log.debug "Droplet id: #{id} name: #{droplet.name} "
instance = api.droplet id
next unless only.empty? || only.include?(id)

prepare_instance instance.droplet
prepare_droplet id, droplet.name
end
end

Expand All @@ -86,81 +118,50 @@ def thread_chain

# Run threads
#
def thread_runner(instance)
def thread_runner(droplet)
threads << Thread.new do
Log.debug 'Shutting down droplet.'
stop_droplet instance
create_snapshot instance
stop_droplet droplet
create_snapshot droplet
end
end

# Preparing instance to take snapshot.
# Instance must be powered off first!
# Preparing droplet to take a snapshot.
# Droplet instance must be powered off first!
#
def prepare_instance(instance)
return unless instance
Log.info "Preparing droplet id: #{instance.id} name: #{instance.name} to take snapshot."
return if too_much_snapshots(instance)
thread_runner(instance)
end
def prepare_droplet(id, name)
Log.debug "Droplet id: #{id} name: #{name} "
instance = api.droplet id
droplet = instance.droplet

def too_much_snapshots(instance)
# noinspection RubyResolve
if instance.snapshots.size >= keep
warning_size(instance.id, instance.name, keep)
return true if stop
end
false
end

def stop_droplet(instance)
api.stop_droplet(instance.id) unless instance.status.include? 'off'
return unless droplet
Log.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
return if too_much_snapshots(droplet)
thread_runner(droplet)
end

# Trying to create a snapshot.
#
def create_snapshot(instance) # rubocop:disable MethodLength
Log.info "Start creating snapshot for droplet id: #{instance.id} name: #{instance.name}."

today = DateTime.now
name = "#{instance.name}_#{today.strftime('%Y_%m_%d')}"
def too_much_snapshots(instance)
# noinspection RubyResolve
snapshot_size = instance.snapshots.size

Log.debug 'Wait until snapshot will be created.'

api.create_snapshot instance.id, name

snapshot_size += 1

Log.info "Snapshot name: #{name} created successfully."
Log.info "Droplet id: #{instance.id} name: #{instance.name} snapshots: #{snapshot_size}."

# Cleanup snapshots.
cleanup_snapshots instance, snapshot_size if clean
rescue => e
case e.class.to_s
when 'DoSnapshot::SnapshotCleanupError'
raise e.class, e.message, e.backtrace
else
raise SnapshotCreateError.new(instance.id), e.message, e.backtrace
end
return false unless instance.snapshots.size >= keep
warning_size(instance.id, instance.name, keep)
stop ? true : false
end

# Cleanup our snapshots.
#
def cleanup_snapshots(instance, size)
def cleanup_snapshots(droplet, size) # rubocop:disable Metrics/AbcSize
return unless size > keep

warning_size(instance.id, instance.name, size)
warning_size(droplet.id, droplet.name, size)

Log.debug "Cleaning up snapshots for droplet id: #{instance.id} name: #{instance.name}."
Log.debug "Cleaning up snapshots for droplet id: #{droplet.id} name: #{droplet.name}."

api.cleanup_snapshots(instance, size - keep - 1)
api.cleanup_snapshots(droplet, size - keep - 1)
rescue => e
raise SnapshotCleanupError, e.message, e.backtrace
end

# Helpers
#
def warning_size(id, name, keep)
message = "For droplet with id: #{id} and name: #{name} the maximum number #{keep} of snapshots is reached."
Log.warning message
Expand Down
2 changes: 1 addition & 1 deletion spec/do_snapshot/api_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
expect(a_request(:get, image_destroy_url))
.to have_been_made
expect(a_request(:get, image_destroy2_url))
.to have_been_made
.to have_been_made
end
end
end
Expand Down
1 change: 0 additions & 1 deletion spec/do_snapshot/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
subject(:api) { DoSnapshot::API }

describe '.snap' do

it 'with exclude' do
excluded_droplets = %w( 100824 )
stub_all_api(%w(100825 100823))
Expand Down
53 changes: 49 additions & 4 deletions spec/do_snapshot/command_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,47 @@
end
end

describe '.fail_power_off' do
describe '.stop_droplet' do
it 'when raised with error' do
stub_droplet_stop_fail(droplet_id)
load_options
instance = cmd.api.droplet droplet_id
droplet = instance.droplet
expect { cmd.stop_droplet(droplet) }
.to raise_error(DoSnapshot::DropletShutdownError)
end

it 'when stopped' do
stub_droplet_stop(droplet_id)
load_options
instance = cmd.api.droplet droplet_id
droplet = instance.droplet
expect { cmd.stop_droplet(droplet) }
.not_to raise_error
end
end

describe '.create_snapshot' do
it 'when raised with error' do
stub_droplet_snapshot_fail(droplet_id, snapshot_name)
load_options
instance = cmd.api.droplet droplet_id
droplet = instance.droplet
expect { cmd.create_snapshot(droplet) }
.to raise_error(DoSnapshot::SnapshotCreateError)
end

it 'when snapshot is created' do
stub_droplet_snapshot(droplet_id, snapshot_name)
load_options
instance = cmd.api.droplet droplet_id
droplet = instance.droplet
expect { cmd.create_snapshot(droplet) }
.not_to raise_error
end
end

describe '.fail_power_off' do
it 'when success' do
stub_droplet_inactive(droplet_id)

Expand All @@ -83,7 +123,7 @@
expect(log.buffer)
.to include 'Droplet id: 100823 is Failed to Power Off.'
expect(log.buffer)
.to include 'Droplet Not Found'
.to include 'Droplet Not Found'
end

it 'with start error' do
Expand All @@ -105,9 +145,14 @@
log.quiet = true
end

def snap_runner(options = nil)
def load_options(options = nil)
options ||= default_options
cmd.send('api=', nil)
cmd.snap(options, [:log, :mail, :smtp, :trace, :digital_ocean_client_id, :digital_ocean_api_key])
cmd.load_options(options, [:log, :mail, :smtp, :trace, :digital_ocean_client_id, :digital_ocean_api_key])
end

def snap_runner
load_options
cmd.snap
end
end
1 change: 0 additions & 1 deletion spec/do_snapshots_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
subject(:error) { described_class }

it 'should be' do

expect { error.new }
.not_to raise_error
end
Expand Down
Loading

0 comments on commit 3c78710

Please # to comment.