do_snapshot 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1832957a7416c15f2755720be734b7153dc19856
4
- data.tar.gz: 4cd6ea976f4bbbe26051e10b538e4e213f7cd87c
3
+ metadata.gz: fd8a67c728fd77180645b3ea87ee37db50ab627e
4
+ data.tar.gz: e3196ed56ad208a890c3be2f55bb02cb7499a06f
5
5
  SHA512:
6
- metadata.gz: 2c988328d3c25992b45336a37e34ff535f5db6e4545ae9946c77b24dd9866517734bf27653e4e170451463ae94580053c88a968f2f9acda141b00ccbb66a0b12
7
- data.tar.gz: 10532b1d32445a9cd7c28d84119524cd6a8399103295639dcabfe308dd6eddb2aa2c2a1fb4c95e2eecd36a7d026574d33d4693e745a5a00b93d89662272fc471
6
+ metadata.gz: 1f91dd0dc2e68e03eb59a48e7e2077893d2d4574d6f2fc2900070adcaa1c9c580b9d001ece9283d34da67fdbe4ec93e0ed8894d0f74e446b774f3837ed4f1a44
7
+ data.tar.gz: 7a27ff1d46bc31ffd257ae77f0e474408172d4dc6dd755615215dedf280e842f88c1fe543b099ca522bf552a8ec070744d4d7ee661a712638e9d0211495aafbb
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- # DoSnapshot CLI
1
+ # DoSnapshot CLI
2
+ [Project Page at Digital Ocean](https://www.digitalocean.com/community/projects/dosnapshot), comment or vote for this project.
2
3
 
3
4
  [![Gem Version](https://badge.fury.io/rb/do_snapshot.svg)](http://badge.fury.io/rb/do_snapshot)
4
5
  [![Build Status](https://travis-ci.org/merqlove/do_snapshot.svg?branch=master)](https://travis-ci.org/merqlove/do_snapshot)
@@ -183,4 +184,4 @@ For working mailer you need to set e-mail settings via run options.
183
184
 
184
185
  Copyright (c) 2014 Alexander Merkulov
185
186
 
186
- MIT License
187
+ MIT License
@@ -87,13 +87,7 @@ module DoSnapshot
87
87
  snapshot = instance.snapshots[i]
88
88
  event = Digitalocean::Image.destroy(snapshot.id)
89
89
 
90
- if !event
91
- Log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{instance.id} name: #{instance.name} is failed."
92
- elsif event && !event.status.include?('OK')
93
- Log.error event.message
94
- else
95
- Log.debug "Snapshot name: #{snapshot.name} delete requested."
96
- end
90
+ after_cleanup(instance.id, instance.name, snapshot, event)
97
91
  end
98
92
  end
99
93
 
@@ -136,5 +130,15 @@ module DoSnapshot
136
130
  Log.error 'Power On failed to request.'
137
131
  end
138
132
  end
133
+
134
+ def after_cleanup(droplet_id, droplet_name, snapshot, event)
135
+ if !event
136
+ Log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
137
+ elsif event && !event.status.include?('OK')
138
+ Log.error event.message
139
+ else
140
+ Log.debug "Snapshot name: #{snapshot.name} delete requested."
141
+ end
142
+ end
139
143
  end
140
144
  end
@@ -1,9 +1,9 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  require 'thor'
3
3
  require 'do_snapshot'
4
- require 'do_snapshot/command'
5
- require 'do_snapshot/mail'
6
- require 'do_snapshot/log'
4
+ require_relative 'command'
5
+ require_relative 'mail'
6
+ require_relative 'log'
7
7
 
8
8
  module DoSnapshot
9
9
  # CLI is here
@@ -137,16 +137,13 @@ module DoSnapshot
137
137
  desc: 'DIGITAL_OCEAN_API_KEY. if you can\'t use environment.'
138
138
 
139
139
  def snap
140
- Command.snap options, %w( log mail smtp trace digital_ocean_client_id digital_ocean_api_key )
140
+ Command.load_options options, %w( log mail smtp trace digital_ocean_client_id digital_ocean_api_key )
141
+ Command.snap
141
142
  rescue => e
142
143
  Command.fail_power_off(e) if [SnapshotCreateError, DropletShutdownError].include?(e.class)
143
144
  Log.error e.message
144
145
  backtrace(e) if options.include? 'trace'
145
- if Mail.opts
146
- Mail.opts[:subject] = 'Digital Ocean: Error.'
147
- Mail.opts[:body] = 'Please check your droplets.'
148
- Mail.notify
149
- end
146
+ send_error
150
147
  end
151
148
 
152
149
  desc 'version, -V', 'Shows the version of the currently installed DoSnapshot gem'
@@ -160,6 +157,14 @@ module DoSnapshot
160
157
  Mail.smtp = options['smtp']
161
158
  end
162
159
 
160
+ def send_error
161
+ return unless Mail.opts
162
+
163
+ Mail.opts[:subject] = 'Digital Ocean: Error.'
164
+ Mail.opts[:body] = 'Please check your droplets.'
165
+ Mail.notify
166
+ end
167
+
163
168
  def set_logger
164
169
  Log.quiet = options['quiet']
165
170
  Log.verbose = options['trace']
@@ -1,18 +1,12 @@
1
1
  # -*- encoding : utf-8 -*-
2
- require 'do_snapshot/api'
2
+ require_relative 'api'
3
3
 
4
4
  module DoSnapshot
5
5
  # Our commands live here :)
6
6
  #
7
7
  class Command # rubocop:disable ClassLength
8
8
  class << self
9
- def snap(options, skip)
10
- return unless options
11
-
12
- options.each_pair do |key, option|
13
- send("#{key}=", option) unless skip.include?(key)
14
- end
15
-
9
+ def snap
16
10
  Log.info 'Start performing operations'
17
11
  work_with_droplets
18
12
  Log.info 'All operations has been finished.'
@@ -20,6 +14,12 @@ module DoSnapshot
20
14
  Mail.notify if notify && !quiet
21
15
  end
22
16
 
17
+ def load_options(options = {}, skip = %w())
18
+ options.each_pair do |key, option|
19
+ send("#{key}=", option) unless skip.include?(key)
20
+ end if options
21
+ end
22
+
23
23
  def fail_power_off(e)
24
24
  return unless e && e.id
25
25
  api.start_droplet(e.id)
@@ -27,17 +27,52 @@ module DoSnapshot
27
27
  raise DropletFindError, e.message, e.backtrace
28
28
  end
29
29
 
30
- protected
30
+ def stop_droplet(droplet)
31
+ Log.debug 'Shutting down droplet.'
32
+ api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
33
+ end
31
34
 
32
- attr_accessor :droplets, :exclude, :only
33
- attr_accessor :keep, :quiet, :stop, :clean, :timeout, :delay
35
+ # Trying to create a snapshot.
36
+ #
37
+ def create_snapshot(droplet) # rubocop:disable MethodLength,Metrics/AbcSize
38
+ Log.info "Start creating snapshot for droplet id: #{droplet.id} name: #{droplet.name}."
34
39
 
35
- attr_writer :notify, :threads, :api
40
+ today = DateTime.now
41
+ name = "#{droplet.name}_#{today.strftime('%Y_%m_%d')}"
42
+ # noinspection RubyResolve
43
+ snapshot_size = droplet.snapshots.size
44
+
45
+ Log.debug 'Wait until snapshot will be created.'
46
+
47
+ api.create_snapshot droplet.id, name
48
+
49
+ snapshot_size += 1
50
+
51
+ Log.info "Snapshot name: #{name} created successfully."
52
+ Log.info "Droplet id: #{droplet.id} name: #{droplet.name} snapshots: #{snapshot_size}."
53
+
54
+ # Cleanup snapshots.
55
+ cleanup_snapshots droplet, snapshot_size if clean
56
+ rescue => e
57
+ case e.class.to_s
58
+ when 'DoSnapshot::SnapshotCleanupError'
59
+ raise e.class, e.message, e.backtrace
60
+ else
61
+ raise SnapshotCreateError.new(droplet.id), e.message, e.backtrace
62
+ end
63
+ end
36
64
 
37
65
  def api
38
66
  @api ||= API.new(delay: delay, timeout: timeout)
39
67
  end
40
68
 
69
+ protected
70
+
71
+ attr_accessor :droplets, :exclude, :only
72
+ attr_accessor :keep, :quiet, :stop, :clean, :timeout, :delay
73
+
74
+ attr_writer :notify, :threads, :api
75
+
41
76
  def notify
42
77
  @notify ||= false
43
78
  end
@@ -69,12 +104,9 @@ module DoSnapshot
69
104
  droplets.each do |droplet|
70
105
  id = droplet.id.to_s
71
106
  next if exclude.include? id
72
- next if !only.empty? && !only.include?(id)
73
-
74
- Log.debug "Droplet id: #{id} name: #{droplet.name} "
75
- instance = api.droplet id
107
+ next unless only.empty? || only.include?(id)
76
108
 
77
- prepare_instance instance.droplet
109
+ prepare_droplet id, droplet.name
78
110
  end
79
111
  end
80
112
 
@@ -86,81 +118,50 @@ module DoSnapshot
86
118
 
87
119
  # Run threads
88
120
  #
89
- def thread_runner(instance)
121
+ def thread_runner(droplet)
90
122
  threads << Thread.new do
91
- Log.debug 'Shutting down droplet.'
92
- stop_droplet instance
93
- create_snapshot instance
123
+ stop_droplet droplet
124
+ create_snapshot droplet
94
125
  end
95
126
  end
96
127
 
97
- # Preparing instance to take snapshot.
98
- # Instance must be powered off first!
128
+ # Preparing droplet to take a snapshot.
129
+ # Droplet instance must be powered off first!
99
130
  #
100
- def prepare_instance(instance)
101
- return unless instance
102
- Log.info "Preparing droplet id: #{instance.id} name: #{instance.name} to take snapshot."
103
- return if too_much_snapshots(instance)
104
- thread_runner(instance)
105
- end
131
+ def prepare_droplet(id, name)
132
+ Log.debug "Droplet id: #{id} name: #{name} "
133
+ instance = api.droplet id
134
+ droplet = instance.droplet
106
135
 
107
- def too_much_snapshots(instance)
108
- # noinspection RubyResolve
109
- if instance.snapshots.size >= keep
110
- warning_size(instance.id, instance.name, keep)
111
- return true if stop
112
- end
113
- false
114
- end
115
-
116
- def stop_droplet(instance)
117
- api.stop_droplet(instance.id) unless instance.status.include? 'off'
136
+ return unless droplet
137
+ Log.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
138
+ return if too_much_snapshots(droplet)
139
+ thread_runner(droplet)
118
140
  end
119
141
 
120
- # Trying to create a snapshot.
121
- #
122
- def create_snapshot(instance) # rubocop:disable MethodLength
123
- Log.info "Start creating snapshot for droplet id: #{instance.id} name: #{instance.name}."
124
-
125
- today = DateTime.now
126
- name = "#{instance.name}_#{today.strftime('%Y_%m_%d')}"
142
+ def too_much_snapshots(instance)
127
143
  # noinspection RubyResolve
128
- snapshot_size = instance.snapshots.size
129
-
130
- Log.debug 'Wait until snapshot will be created.'
131
-
132
- api.create_snapshot instance.id, name
133
-
134
- snapshot_size += 1
135
-
136
- Log.info "Snapshot name: #{name} created successfully."
137
- Log.info "Droplet id: #{instance.id} name: #{instance.name} snapshots: #{snapshot_size}."
138
-
139
- # Cleanup snapshots.
140
- cleanup_snapshots instance, snapshot_size if clean
141
- rescue => e
142
- case e.class.to_s
143
- when 'DoSnapshot::SnapshotCleanupError'
144
- raise e.class, e.message, e.backtrace
145
- else
146
- raise SnapshotCreateError.new(instance.id), e.message, e.backtrace
147
- end
144
+ return false unless instance.snapshots.size >= keep
145
+ warning_size(instance.id, instance.name, keep)
146
+ stop ? true : false
148
147
  end
149
148
 
150
149
  # Cleanup our snapshots.
151
150
  #
152
- def cleanup_snapshots(instance, size)
151
+ def cleanup_snapshots(droplet, size) # rubocop:disable Metrics/AbcSize
153
152
  return unless size > keep
154
153
 
155
- warning_size(instance.id, instance.name, size)
154
+ warning_size(droplet.id, droplet.name, size)
156
155
 
157
- Log.debug "Cleaning up snapshots for droplet id: #{instance.id} name: #{instance.name}."
156
+ Log.debug "Cleaning up snapshots for droplet id: #{droplet.id} name: #{droplet.name}."
158
157
 
159
- api.cleanup_snapshots(instance, size - keep - 1)
158
+ api.cleanup_snapshots(droplet, size - keep - 1)
160
159
  rescue => e
161
160
  raise SnapshotCleanupError, e.message, e.backtrace
162
161
  end
163
162
 
163
+ # Helpers
164
+ #
164
165
  def warning_size(id, name, keep)
165
166
  message = "For droplet with id: #{id} and name: #{name} the maximum number #{keep} of snapshots is reached."
166
167
  Log.warning message
@@ -1,7 +1,7 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  require 'date'
3
3
  require 'pony'
4
- require 'do_snapshot/core_ext/hash'
4
+ require_relative 'core_ext/hash'
5
5
 
6
6
  module DoSnapshot
7
7
  # Shared mailer.
@@ -2,5 +2,5 @@
2
2
  # Current version
3
3
  #
4
4
  module DoSnapshot
5
- VERSION = '0.0.12'
5
+ VERSION = '0.0.13'
6
6
  end
data/lib/do_snapshot.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
- require 'do_snapshot/version'
2
+ require_relative 'do_snapshot/version'
3
3
 
4
4
  # Used primary for creating snapshot's as backups for DigitalOcean
5
5
  #
@@ -207,7 +207,7 @@ describe DoSnapshot::API do
207
207
  expect(a_request(:get, image_destroy_url))
208
208
  .to have_been_made
209
209
  expect(a_request(:get, image_destroy2_url))
210
- .to have_been_made
210
+ .to have_been_made
211
211
  end
212
212
  end
213
213
  end
@@ -9,7 +9,6 @@ describe DoSnapshot::CLI do
9
9
  subject(:api) { DoSnapshot::API }
10
10
 
11
11
  describe '.snap' do
12
-
13
12
  it 'with exclude' do
14
13
  excluded_droplets = %w( 100824 )
15
14
  stub_all_api(%w(100825 100823))
@@ -65,7 +65,47 @@ describe DoSnapshot::Command do
65
65
  end
66
66
  end
67
67
 
68
- describe '.fail_power_off' do
68
+ describe '.stop_droplet' do
69
+ it 'when raised with error' do
70
+ stub_droplet_stop_fail(droplet_id)
71
+ load_options
72
+ instance = cmd.api.droplet droplet_id
73
+ droplet = instance.droplet
74
+ expect { cmd.stop_droplet(droplet) }
75
+ .to raise_error(DoSnapshot::DropletShutdownError)
76
+ end
77
+
78
+ it 'when stopped' do
79
+ stub_droplet_stop(droplet_id)
80
+ load_options
81
+ instance = cmd.api.droplet droplet_id
82
+ droplet = instance.droplet
83
+ expect { cmd.stop_droplet(droplet) }
84
+ .not_to raise_error
85
+ end
86
+ end
87
+
88
+ describe '.create_snapshot' do
89
+ it 'when raised with error' do
90
+ stub_droplet_snapshot_fail(droplet_id, snapshot_name)
91
+ load_options
92
+ instance = cmd.api.droplet droplet_id
93
+ droplet = instance.droplet
94
+ expect { cmd.create_snapshot(droplet) }
95
+ .to raise_error(DoSnapshot::SnapshotCreateError)
96
+ end
97
+
98
+ it 'when snapshot is created' do
99
+ stub_droplet_snapshot(droplet_id, snapshot_name)
100
+ load_options
101
+ instance = cmd.api.droplet droplet_id
102
+ droplet = instance.droplet
103
+ expect { cmd.create_snapshot(droplet) }
104
+ .not_to raise_error
105
+ end
106
+ end
107
+
108
+ describe '.fail_power_off' do
69
109
  it 'when success' do
70
110
  stub_droplet_inactive(droplet_id)
71
111
 
@@ -83,7 +123,7 @@ describe DoSnapshot::Command do
83
123
  expect(log.buffer)
84
124
  .to include 'Droplet id: 100823 is Failed to Power Off.'
85
125
  expect(log.buffer)
86
- .to include 'Droplet Not Found'
126
+ .to include 'Droplet Not Found'
87
127
  end
88
128
 
89
129
  it 'with start error' do
@@ -105,9 +145,14 @@ describe DoSnapshot::Command do
105
145
  log.quiet = true
106
146
  end
107
147
 
108
- def snap_runner(options = nil)
148
+ def load_options(options = nil)
109
149
  options ||= default_options
110
150
  cmd.send('api=', nil)
111
- cmd.snap(options, [:log, :mail, :smtp, :trace, :digital_ocean_client_id, :digital_ocean_api_key])
151
+ cmd.load_options(options, [:log, :mail, :smtp, :trace, :digital_ocean_client_id, :digital_ocean_api_key])
152
+ end
153
+
154
+ def snap_runner
155
+ load_options
156
+ cmd.snap
112
157
  end
113
158
  end
@@ -30,7 +30,6 @@ describe DoSnapshot do
30
30
  subject(:error) { described_class }
31
31
 
32
32
  it 'should be' do
33
-
34
33
  expect { error.new }
35
34
  .not_to raise_error
36
35
  end
@@ -2,7 +2,6 @@
2
2
  require 'spec_helper'
3
3
 
4
4
  shared_context 'api_helpers' do
5
-
6
5
  # List of droplets
7
6
  #
8
7
  def stub_droplets
data/spec/spec_helper.rb CHANGED
@@ -8,10 +8,9 @@ end
8
8
  require 'do_snapshot/cli'
9
9
  require 'webmock/rspec'
10
10
  require 'digitalocean'
11
- require 'shared/api_helpers'
12
- require 'shared/uri_helpers'
13
- require 'shared/environment'
14
- require 'shared/uri_helpers'
11
+ require_relative 'shared/api_helpers'
12
+ require_relative 'shared/uri_helpers'
13
+ require_relative 'shared/environment'
15
14
  require 'do_snapshot/core_ext/hash'
16
15
 
17
16
  WebMock.disable_net_connect!(allow_localhost: true)
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.0.12
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Merkulov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-24 00:00:00.000000000 Z
11
+ date: 2015-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: digitalocean
@@ -263,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
263
263
  version: '0'
264
264
  requirements: []
265
265
  rubyforge_project:
266
- rubygems_version: 2.2.2
266
+ rubygems_version: 2.4.5
267
267
  signing_key:
268
268
  specification_version: 4
269
269
  summary: A command-line snapshot maker for your DigitalOcean droplets. Fully Automated.