do_snapshot 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 25e673a7db69593b0007d27f55f873b12b2efad6
4
- data.tar.gz: 159359c4f15b5a85163b660b84e994c742f3cccd
3
+ metadata.gz: 0c4e8fd9920e0fb822c5f84dadf54aa6cf0a90b5
4
+ data.tar.gz: 26fa16b5c5e5a1ebb5d474e31467488fca1a3c07
5
5
  SHA512:
6
- metadata.gz: bb017632d9bdcff73d39310c7d5754fd0579f3975d23f6e16824797e3cf2afc7dfeeb041d645db05df370e1dd45b37842b4150d0f02d5e9158a8577d8e51c566
7
- data.tar.gz: 1ef277c08b234bc7925d9e797c85c1e3179d475512ee8debe4159bc4ec818ac274e596e30643f7c2551e92f46451ff5f9d748f86a3113e1ada5766084af401c0
6
+ metadata.gz: 8368fd230ea50254df7456a01a7e20199b8ee0d7a6937b7e036c11a8902206b7c0034f79ea7cb2f0b80d4621d48b6715c2f02b62b254e5bc01978fb54ae07b8a
7
+ data.tar.gz: 8139cdbee917477ecc0dea28a63c5d2fb07485e2f4f47781340959ba97fc94317b401c99f632685b8c37177cbaef35e585de39adad0818a5a4f0b12e996e1757
data/bin/do_snapshot CHANGED
@@ -10,6 +10,6 @@ bin_file = Pathname.new(__FILE__).realpath
10
10
  # add self to libpath
11
11
  $LOAD_PATH.unshift File.expand_path('../../lib', bin_file)
12
12
 
13
- require 'do_snapshot/cli'
13
+ require 'do_snapshot/runner'
14
14
 
15
- DoSnapshot::CLI.start(ARGV)
15
+ DoSnapshot::Runner.new(ARGV.dup).execute!
@@ -6,7 +6,7 @@ module DoSnapshot
6
6
  # Operating with Digital Ocean.
7
7
  #
8
8
  class Abstract
9
- include DoSnapshot::Log
9
+ include DoSnapshot::Helpers
10
10
 
11
11
  attr_accessor :delay, :timeout
12
12
 
@@ -26,18 +26,18 @@ module DoSnapshot
26
26
 
27
27
  # Waiting for event exit
28
28
  def wait_event(id)
29
- log.debug "Event Id: #{id}"
29
+ logger.debug "Event Id: #{id}"
30
30
  time = Time.now
31
31
  sleep(delay) until get_event_status(id, time)
32
32
  end
33
33
 
34
34
  def after_cleanup(droplet_id, droplet_name, snapshot, event)
35
35
  if !event
36
- log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
36
+ logger.error "Destroy of snapshot #{snapshot.name} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
37
37
  elsif event && !event.status.include?('OK')
38
- log.error event.message
38
+ logger.error event.message
39
39
  else
40
- log.debug "Snapshot name: #{snapshot.name} delete requested."
40
+ logger.debug "Snapshot name: #{snapshot.name} delete requested."
41
41
  end
42
42
  end
43
43
  end
@@ -36,7 +36,7 @@ module DoSnapshot
36
36
  instance = droplet(id)
37
37
 
38
38
  if instance.status.include? 'active'
39
- log.error 'Droplet is still running.'
39
+ logger.error 'Droplet is still running.'
40
40
  else
41
41
  power_on id
42
42
  end
@@ -85,10 +85,9 @@ module DoSnapshot
85
85
  end
86
86
 
87
87
  def check_keys
88
- log.debug 'Checking DigitalOcean Id\'s.'
89
- %w( DIGITAL_OCEAN_CLIENT_ID DIGITAL_OCEAN_API_KEY ).each do |key|
90
- log.error "You must have #{key} in environment or set it via options." if ENV[key].blank?
91
- end
88
+ logger.debug 'Checking DigitalOcean Id\'s.'
89
+ errors = %w( DIGITAL_OCEAN_CLIENT_ID DIGITAL_OCEAN_API_KEY ).map { |key| key if ENV[key].blank? }.compact
90
+ fail DoSnapshot::NoKeysError, "You must have #{errors.join(', ')} in environment or set it via options." if errors.size > 0
92
91
  end
93
92
 
94
93
  protected
@@ -96,7 +95,7 @@ module DoSnapshot
96
95
  # Set id's of Digital Ocean API.
97
96
  #
98
97
  def set_id
99
- log.debug 'Setting DigitalOcean Id\'s.'
98
+ logger.debug 'Setting DigitalOcean Id\'s.'
100
99
  ::DigitaloceanC.client_id = ENV['DIGITAL_OCEAN_CLIENT_ID']
101
100
  ::DigitaloceanC.api_key = ENV['DIGITAL_OCEAN_API_KEY']
102
101
  end
@@ -115,7 +114,7 @@ module DoSnapshot
115
114
 
116
115
  def timeout?(id, time)
117
116
  return false unless (Time.now - time) > @timeout
118
- log.debug "Event #{id} finished by timeout #{time}"
117
+ logger.debug "Event #{id} finished by timeout #{time}"
119
118
  true
120
119
  end
121
120
 
@@ -126,9 +125,9 @@ module DoSnapshot
126
125
  event = ::DigitaloceanC::Droplet.power_on(id)
127
126
  case event && event.status
128
127
  when 'OK'
129
- log.info 'Power On has been requested.'
128
+ logger.info 'Power On has been requested.'
130
129
  else
131
- log.error 'Power On failed to request.'
130
+ logger.error 'Power On failed to request.'
132
131
  end
133
132
  end
134
133
  end
@@ -42,7 +42,7 @@ module DoSnapshot
42
42
  instance = droplet(id)
43
43
 
44
44
  if instance.status && instance.status.include?('active')
45
- log.error 'Droplet is still running.'
45
+ logger.error 'Droplet is still running.'
46
46
  else
47
47
  power_on id
48
48
  end
@@ -81,7 +81,7 @@ module DoSnapshot
81
81
  event = client.images.delete(id: snapshot)
82
82
 
83
83
  unless event.is_a?(TrueClass)
84
- log.debug event
84
+ logger.debug event
85
85
  event = false
86
86
  end
87
87
 
@@ -90,16 +90,16 @@ module DoSnapshot
90
90
  end
91
91
 
92
92
  def check_keys
93
- log.debug 'Checking DigitalOcean Access Token.'
93
+ logger.debug 'Checking DigitalOcean Access Token.'
94
94
  %w( DIGITAL_OCEAN_ACCESS_TOKEN ).each do |key|
95
- log.error "You must have #{key} in environment or set it via options." if ENV[key].blank?
95
+ fail DoSnapshot::NoTokenError, "You must have #{key} in environment or set it via options." if ENV[key].blank?
96
96
  end
97
97
  end
98
98
 
99
99
  # Set id's of Digital Ocean API.
100
100
  #
101
101
  def set_id
102
- log.debug 'Setting DigitalOcean Access Token.'
102
+ logger.debug 'Setting DigitalOcean Access Token.'
103
103
  @client = ::DropletKit::Client.new(access_token: ENV['DIGITAL_OCEAN_ACCESS_TOKEN'])
104
104
  end
105
105
 
@@ -107,9 +107,9 @@ module DoSnapshot
107
107
 
108
108
  def after_cleanup(droplet_id, droplet_name, snapshot, event)
109
109
  if !event
110
- log.error "Destroy of snapshot #{snapshot} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
110
+ logger.error "Destroy of snapshot #{snapshot} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
111
111
  else
112
- log.debug "Snapshot: #{snapshot} delete requested."
112
+ logger.debug "Snapshot: #{snapshot} delete requested."
113
113
  end
114
114
  end
115
115
 
@@ -118,7 +118,7 @@ module DoSnapshot
118
118
  #
119
119
  def get_event_status(id, time)
120
120
  if (Time.now - time) > @timeout
121
- log.debug "Event #{id} finished by timeout #{time}"
121
+ logger.debug "Event #{id} finished by timeout #{time}"
122
122
  return true
123
123
  end
124
124
 
@@ -135,9 +135,9 @@ module DoSnapshot
135
135
  # noinspection RubyResolve
136
136
  event = client.droplet_actions.power_on(droplet_id: id)
137
137
  if event.status.include?('in-progress')
138
- log.info 'Power On has been requested.'
138
+ logger.info 'Power On has been requested.'
139
139
  else
140
- log.error 'Power On failed to request.'
140
+ logger.error 'Power On failed to request.'
141
141
  end
142
142
  end
143
143
  end
@@ -3,14 +3,14 @@ require 'thor'
3
3
  require 'do_snapshot'
4
4
  require_relative 'log'
5
5
  require_relative 'mail'
6
+ require_relative 'helpers'
6
7
  require_relative 'command'
7
8
 
8
9
  module DoSnapshot
9
10
  # CLI is here
10
11
  #
11
12
  class CLI < Thor # rubocop:disable ClassLength
12
- include DoSnapshot::Log
13
- include DoSnapshot::Mail
13
+ include DoSnapshot::Helpers
14
14
 
15
15
  default_task :snap
16
16
 
@@ -22,6 +22,7 @@ module DoSnapshot
22
22
  def initialize(*args)
23
23
  super
24
24
 
25
+ setup_config
25
26
  set_logger
26
27
  set_mailer
27
28
 
@@ -158,11 +159,11 @@ module DoSnapshot
158
159
 
159
160
  def snap
160
161
  command.snap
162
+ rescue DoSnapshot::NoTokenError, DoSnapshot::NoKeysError => e
163
+ error_simple(e)
161
164
  rescue => e
162
165
  command.fail_power_off(e) if [SnapshotCreateError, DropletShutdownError].include?(e.class)
163
- log.error e.message
164
- backtrace(e) if options.include? 'trace'
165
- send_error
166
+ error_with_backtrace(e)
166
167
  end
167
168
 
168
169
  desc 'version, -V', 'Shows the version of the currently installed DoSnapshot gem'
@@ -171,43 +172,60 @@ module DoSnapshot
171
172
  end
172
173
 
173
174
  no_commands do
175
+ def error_simple(e)
176
+ logger.error e.message
177
+ send_error
178
+ fail e
179
+ end
180
+
181
+ def error_with_backtrace(e)
182
+ logger.error e.message
183
+ backtrace(e) if options.include? 'trace'
184
+ send_error
185
+ fail e
186
+ end
187
+
174
188
  def command
175
- @command ||= Command.new(options,
176
- %w( log smtp mail trace digital_ocean_client_id digital_ocean_api_key digital_ocean_access_token ))
189
+ @command ||= Command.new(options, command_filter)
177
190
  end
178
191
 
179
192
  def update_command
180
- command.load_options(options,
181
- %w( log smtp mail trace digital_ocean_client_id digital_ocean_api_key digital_ocean_access_token ))
193
+ command.load_options(options, command_filter)
194
+ end
195
+
196
+ def command_filter
197
+ %w( log smtp mail trace digital_ocean_client_id digital_ocean_api_key digital_ocean_access_token )
198
+ end
199
+
200
+ def setup_config # rubocop:disable Metrics/AbcSize
201
+ DoSnapshot.configure do |config|
202
+ config.logger = ::Logger.new(options['log']) if options['log']
203
+ config.logger_level = Logger::DEBUG if config.verbose
204
+ config.verbose = options['trace']
205
+ config.quiet = options['quiet']
206
+ config.mailer = Mail.new(opts: options['mail'], smtp: options['smtp'])
207
+ end
182
208
  end
183
209
 
184
210
  def set_mailer
185
- Mail.load_options(opts: options['mail'], smtp: options['smtp'])
211
+ DoSnapshot.mailer = DoSnapshot.config.mailer
186
212
  end
187
213
 
188
214
  def send_error
189
- return unless mailer.opts
215
+ return unless DoSnapshot.mailer.opts
190
216
 
191
- Mail.opts[:subject] = 'Digital Ocean: Error.'
192
- Mail.opts[:body] = 'Please check your droplets.'
217
+ DoSnapshot.mailer.opts[:subject] = 'Digital Ocean: Error.'
218
+ DoSnapshot.mailer.opts[:body] = 'Please check your droplets.'
193
219
  mailer.notify
194
220
  end
195
221
 
196
222
  def set_logger
197
- Log.load_options(quiet: options['quiet'], verbose: options['trace'])
198
- # Use Thor shell
199
- Log.shell = shell unless options['quiet']
200
- init_logger if options.include?('log')
201
- end
202
-
203
- def init_logger
204
- Log.logger = Logger.new(options['log'])
205
- Log.logger.level = Log.verbose ? Logger::DEBUG : Logger::INFO
223
+ DoSnapshot.logger = Log.new(shell: shell)
206
224
  end
207
225
 
208
226
  def backtrace(e)
209
227
  e.backtrace.each do |t|
210
- log.error t
228
+ logger.error t
211
229
  end
212
230
  end
213
231
  end
@@ -5,19 +5,18 @@ module DoSnapshot
5
5
  # Our commands live here :)
6
6
  #
7
7
  class Command # rubocop:disable ClassLength
8
- include DoSnapshot::Log
9
- include DoSnapshot::Mail
8
+ include DoSnapshot::Helpers
10
9
 
11
10
  def initialize(*args)
12
11
  load_options(*args)
13
12
  end
14
13
 
15
14
  def snap
16
- log.info 'Start performing operations'
15
+ logger.info 'Start performing operations'
17
16
  work_with_droplets
18
- log.info 'All operations has been finished.'
17
+ logger.info 'All operations has been finished.'
19
18
 
20
- mailer.notify if notify && !quiet
19
+ mailer.notify if mailer && notify && !quiet
21
20
  end
22
21
 
23
22
  def fail_power_off(e)
@@ -41,28 +40,28 @@ module DoSnapshot
41
40
  end
42
41
 
43
42
  def stop_droplet(droplet)
44
- log.debug 'Shutting down droplet.'
43
+ logger.debug 'Shutting down droplet.'
45
44
  api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
46
45
  end
47
46
 
48
47
  # Trying to create a snapshot.
49
48
  #
50
49
  def create_snapshot(droplet) # rubocop:disable MethodLength,Metrics/AbcSize
51
- log.info "Start creating snapshot for droplet id: #{droplet.id} name: #{droplet.name}."
50
+ logger.info "Start creating snapshot for droplet id: #{droplet.id} name: #{droplet.name}."
52
51
 
53
52
  today = DateTime.now
54
53
  name = "#{droplet.name}_#{today.strftime('%Y_%m_%d')}"
55
54
  # noinspection RubyResolve
56
55
  snapshot_size = api.snapshots(droplet).size
57
56
 
58
- log.debug 'Wait until snapshot will be created.'
57
+ logger.debug 'Wait until snapshot will be created.'
59
58
 
60
59
  api.create_snapshot droplet.id, name
61
60
 
62
61
  snapshot_size += 1
63
62
 
64
- log.info "Snapshot name: #{name} created successfully."
65
- log.info "Droplet id: #{droplet.id} name: #{droplet.name} snapshots: #{snapshot_size}."
63
+ logger.info "Snapshot name: #{name} created successfully."
64
+ logger.info "Droplet id: #{droplet.id} name: #{droplet.name} snapshots: #{snapshot_size}."
66
65
 
67
66
  # Cleanup snapshots.
68
67
  cleanup_snapshots droplet, snapshot_size if clean
@@ -99,7 +98,7 @@ module DoSnapshot
99
98
  def work_with_droplets
100
99
  load_droplets
101
100
  dispatch_droplets
102
- log.debug 'Working with list of DigitalOcean droplets'
101
+ logger.debug 'Working with list of DigitalOcean droplets'
103
102
  thread_chain
104
103
  end
105
104
 
@@ -107,7 +106,7 @@ module DoSnapshot
107
106
  # And store into object.
108
107
  #
109
108
  def load_droplets
110
- log.debug 'Loading list of DigitalOcean droplets'
109
+ logger.debug 'Loading list of DigitalOcean droplets'
111
110
  self.droplets = api.droplets
112
111
  end
113
112
 
@@ -142,11 +141,11 @@ module DoSnapshot
142
141
  # Droplet instance must be powered off first!
143
142
  #
144
143
  def prepare_droplet(id, name)
145
- log.debug "Droplet id: #{id} name: #{name} "
144
+ logger.debug "Droplet id: #{id} name: #{name} "
146
145
  droplet = api.droplet id
147
146
 
148
147
  return unless droplet
149
- log.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
148
+ logger.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
150
149
  return if too_much_snapshots(droplet)
151
150
  thread_runner(droplet)
152
151
  end
@@ -165,7 +164,7 @@ module DoSnapshot
165
164
 
166
165
  warning_size(droplet.id, droplet.name, size)
167
166
 
168
- log.debug "Cleaning up snapshots for droplet id: #{droplet.id} name: #{droplet.name}."
167
+ logger.debug "Cleaning up snapshots for droplet id: #{droplet.id} name: #{droplet.name}."
169
168
 
170
169
  api.cleanup_snapshots(droplet, size - keep - 1)
171
170
  rescue => e
@@ -176,7 +175,7 @@ module DoSnapshot
176
175
  #
177
176
  def warning_size(id, name, keep)
178
177
  message = "For droplet with id: #{id} and name: #{name} the maximum number #{keep} of snapshots is reached."
179
- log.warn message
178
+ logger.warn message
180
179
  @notify = true
181
180
  end
182
181
  end
@@ -0,0 +1,19 @@
1
+ module DoSnapshot
2
+ # Configuration class. Used to share config across application.
3
+ #
4
+ class Configuration
5
+ attr_accessor :logger
6
+ attr_accessor :logger_level
7
+ attr_accessor :verbose
8
+ attr_accessor :quiet
9
+ attr_accessor :mailer
10
+
11
+ def initialize
12
+ @logger = nil
13
+ @logger_level = Logger::INFO
14
+ @verbose = false
15
+ @quiet = false
16
+ @mailer = nil
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ require_relative 'log'
2
+ require_relative 'mail'
3
+
4
+ module DoSnapshot
5
+ # Helpers for main class.
6
+ #
7
+ module Helpers
8
+ def logger
9
+ UniversalLogger
10
+ end
11
+
12
+ # UniversalLogger is a module to deal with singleton methods.
13
+ # Used to give classes access only for selected methods
14
+ #
15
+ module UniversalLogger
16
+ %w(debug info warn error fatal unknown).each do |name|
17
+ define_singleton_method(:"#{name}") { |*args, &block| DoSnapshot.logger.send(:"#{name}", *args, &block) }
18
+ end
19
+
20
+ def self.close
21
+ DoSnapshot.logger.close
22
+ end
23
+ end
24
+
25
+ def mailer
26
+ DoSnapshot.mailer
27
+ end
28
+ end
29
+ end
@@ -4,60 +4,65 @@ require 'logger'
4
4
  module DoSnapshot
5
5
  # Shared logger
6
6
  #
7
- module Log
8
- def log
9
- UniversalLogger
7
+ class Log
8
+ attr_reader :shell
9
+ attr_accessor :quiet, :verbose
10
+ attr_writer :buffer, :instance
11
+
12
+ def initialize(options = {})
13
+ @verbose = DoSnapshot.config.verbose
14
+ @quiet = DoSnapshot.config.quiet
15
+ options.each { |key, option| instance_variable_set(:"@#{key}", option) }
16
+ instance.level = DoSnapshot.config.logger_level if instance
10
17
  end
11
18
 
12
- # UniversalLogger is module to deal with singleton methods.
13
- # Used to give classes access only for selected methods
14
- #
15
- module UniversalLogger
16
- %i(info warn error debug).each do |type|
17
- define_singleton_method(type) { |message| Log.log type, message }
18
- end
19
+ def instance
20
+ @instance ||= DoSnapshot.config.logger
19
21
  end
20
22
 
21
- class << self
22
- attr_accessor :logger, :shell, :quiet, :verbose
23
- attr_writer :buffer
23
+ def buffer
24
+ @buffer ||= %w()
25
+ end
24
26
 
25
- def load_options(options = {})
26
- options.each { |key, option| send("#{key}=", option) }
27
- end
27
+ def shell=(shell)
28
+ @shell = shell unless quiet
29
+ end
28
30
 
29
- def buffer
30
- @buffer ||= %w()
31
- end
31
+ def close
32
+ instance.close if instance
33
+ end
32
34
 
33
- def log(type, message)
34
- buffer << message
35
- logger.send(type, message) if logger
35
+ %w(debug info warn error fatal unknown).each_with_index do |name, severity|
36
+ define_method(:"#{name}") { |*args, &block| log severity, *args, &block }
37
+ end
36
38
 
37
- say message, color(type) unless print?(type)
38
- end
39
+ def log(severity, message = nil, progname = nil, &block)
40
+ buffer << message
41
+ instance.add(severity, message, progname, &block) if instance
39
42
 
40
- protected
43
+ say message, color(severity) unless print?(severity)
44
+ end
41
45
 
42
- def print?(type)
43
- (type == :debug && !verbose) || quiet
44
- end
46
+ protected
45
47
 
46
- def say(message, color)
47
- shell.say message, color if shell
48
- end
48
+ def print?(type)
49
+ (type == :debug && !verbose) || quiet
50
+ end
51
+
52
+ def say(message, color)
53
+ shell.say message, color if shell
54
+ end
49
55
 
50
- def color(type)
51
- case type
52
- when :debug
53
- :white
54
- when :error
55
- :red
56
- when :warn
57
- :yellow
58
- else
59
- :green
60
- end
56
+ def color(severity)
57
+ case severity
58
+ when 0
59
+ :white
60
+ when 3
61
+ :red
62
+ when 2
63
+ :yellow
64
+ else
65
+ :green
61
66
  end
62
67
  end
63
68
  end