do_snapshot 0.2.2 → 0.3.0

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: 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