do_snapshot 0.0.15 → 0.2.2

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: daa05c7961b1c4dbf9275fb6242817289a52f9c8
4
- data.tar.gz: fc001ff0e7c71e660220972f9494106d1293e162
3
+ metadata.gz: 25e673a7db69593b0007d27f55f873b12b2efad6
4
+ data.tar.gz: 159359c4f15b5a85163b660b84e994c742f3cccd
5
5
  SHA512:
6
- metadata.gz: a1fd3c4e7b308883ffd689aadfaed8cc45295879ad471636ce0735e63f3e426387caca44ed110f5de6fc3190871f953c11cafd27121e45038c4bf7aa51bd1dc1
7
- data.tar.gz: 754e0414a459cc7125ca7991068cde13f3e12cfe82adbd8c07ad62f9d07ab6cd662c1a5a2a794b1320993d3fee816813163548304e5dd268767e2625a606cf52
6
+ metadata.gz: bb017632d9bdcff73d39310c7d5754fd0579f3975d23f6e16824797e3cf2afc7dfeeb041d645db05df370e1dd45b37842b4150d0f02d5e9158a8577d8e51c566
7
+ data.tar.gz: 1ef277c08b234bc7925d9e797c85c1e3179d475512ee8debe4159bc4ec818ac274e596e30643f7c2551e92f46451ff5f9d748f86a3113e1ada5766084af401c0
@@ -6,10 +6,11 @@ module DoSnapshot
6
6
  # Operating with Digital Ocean.
7
7
  #
8
8
  class Abstract
9
- attr_accessor :delay
10
- attr_accessor :timeout
9
+ include DoSnapshot::Log
11
10
 
12
- def initialize(options)
11
+ attr_accessor :delay, :timeout
12
+
13
+ def initialize(options = {})
13
14
  check_keys
14
15
  set_id
15
16
  options.each_pair do |key, option|
@@ -25,18 +26,18 @@ module DoSnapshot
25
26
 
26
27
  # Waiting for event exit
27
28
  def wait_event(id)
28
- Log.debug "Event Id: #{id}"
29
+ log.debug "Event Id: #{id}"
29
30
  time = Time.now
30
31
  sleep(delay) until get_event_status(id, time)
31
32
  end
32
33
 
33
34
  def after_cleanup(droplet_id, droplet_name, snapshot, event)
34
35
  if !event
35
- Log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
36
+ log.error "Destroy of snapshot #{snapshot.name} for droplet id: #{droplet_id} name: #{droplet_name} is failed."
36
37
  elsif event && !event.status.include?('OK')
37
- Log.error event.message
38
+ log.error event.message
38
39
  else
39
- Log.debug "Snapshot name: #{snapshot.name} delete requested."
40
+ log.debug "Snapshot name: #{snapshot.name} delete requested."
40
41
  end
41
42
  end
42
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
+ log.error 'Droplet is still running.'
40
40
  else
41
41
  power_on id
42
42
  end
@@ -74,7 +74,7 @@ module DoSnapshot
74
74
 
75
75
  # Cleanup our snapshots.
76
76
  #
77
- def cleanup_snapshots(instance, size) # rubocop:disable MethodLength
77
+ def cleanup_snapshots(instance, size)
78
78
  (0..size).each do |i|
79
79
  # noinspection RubyResolve
80
80
  snapshot = instance.snapshots[i]
@@ -85,9 +85,9 @@ module DoSnapshot
85
85
  end
86
86
 
87
87
  def check_keys
88
- Log.debug 'Checking DigitalOcean Id\'s.'
88
+ log.debug 'Checking DigitalOcean Id\'s.'
89
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?
90
+ log.error "You must have #{key} in environment or set it via options." if ENV[key].blank?
91
91
  end
92
92
  end
93
93
 
@@ -96,7 +96,7 @@ module DoSnapshot
96
96
  # Set id's of Digital Ocean API.
97
97
  #
98
98
  def set_id
99
- Log.debug 'Setting DigitalOcean Id\'s.'
99
+ log.debug 'Setting DigitalOcean Id\'s.'
100
100
  ::DigitaloceanC.client_id = ENV['DIGITAL_OCEAN_CLIENT_ID']
101
101
  ::DigitaloceanC.api_key = ENV['DIGITAL_OCEAN_API_KEY']
102
102
  end
@@ -105,10 +105,7 @@ module DoSnapshot
105
105
  # Before snapshot we to know that machine has powered off.
106
106
  #
107
107
  def get_event_status(id, time)
108
- if (Time.now - time) > @timeout
109
- Log.debug "Event #{id} finished by timeout #{time}"
110
- return true
111
- end
108
+ return true if timeout?(id, time)
112
109
 
113
110
  event = ::DigitaloceanC::Event.find(id)
114
111
  fail event.message unless event.status.include?('OK')
@@ -116,6 +113,12 @@ module DoSnapshot
116
113
  event.event.percentage && event.event.percentage.include?('100') ? true : false
117
114
  end
118
115
 
116
+ def timeout?(id, time)
117
+ return false unless (Time.now - time) > @timeout
118
+ log.debug "Event #{id} finished by timeout #{time}"
119
+ true
120
+ end
121
+
119
122
  # Request Power On for droplet
120
123
  #
121
124
  def power_on(id)
@@ -123,9 +126,9 @@ module DoSnapshot
123
126
  event = ::DigitaloceanC::Droplet.power_on(id)
124
127
  case event && event.status
125
128
  when 'OK'
126
- Log.info 'Power On has been requested.'
129
+ log.info 'Power On has been requested.'
127
130
  else
128
- Log.error 'Power On failed to request.'
131
+ log.error 'Power On failed to request.'
129
132
  end
130
133
  end
131
134
  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
+ log.error 'Droplet is still running.'
46
46
  else
47
47
  power_on id
48
48
  end
@@ -74,14 +74,14 @@ module DoSnapshot
74
74
 
75
75
  # Cleanup our snapshots.
76
76
  #
77
- def cleanup_snapshots(instance, size) # rubocop:disable MethodLength
77
+ def cleanup_snapshots(instance, size)
78
78
  (0..size).each do |i|
79
79
  # noinspection RubyResolve
80
80
  snapshot = instance.snapshot_ids[i]
81
81
  event = client.images.delete(id: snapshot)
82
82
 
83
83
  unless event.is_a?(TrueClass)
84
- Log.debug event
84
+ log.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
+ log.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
+ log.error "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
+ log.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
+ log.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
+ log.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
+ log.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
+ log.info 'Power On has been requested.'
139
139
  else
140
- Log.error 'Power On failed to request.'
140
+ log.error 'Power On failed to request.'
141
141
  end
142
142
  end
143
143
  end
@@ -1,14 +1,17 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  require 'thor'
3
3
  require 'do_snapshot'
4
- require_relative 'command'
5
- require_relative 'mail'
6
4
  require_relative 'log'
5
+ require_relative 'mail'
6
+ require_relative 'command'
7
7
 
8
8
  module DoSnapshot
9
9
  # CLI is here
10
10
  #
11
11
  class CLI < Thor # rubocop:disable ClassLength
12
+ include DoSnapshot::Log
13
+ include DoSnapshot::Mail
14
+
12
15
  default_task :snap
13
16
 
14
17
  map %w( c s create ) => :snap
@@ -154,11 +157,10 @@ module DoSnapshot
154
157
  desc: 'DIGITAL_OCEAN_API_KEY. if you can\'t use environment.'
155
158
 
156
159
  def snap
157
- Command.load_options options, %w( log mail smtp trace digital_ocean_client_id digital_ocean_api_key digital_ocean_access_token )
158
- Command.snap
160
+ command.snap
159
161
  rescue => e
160
- Command.fail_power_off(e) if [SnapshotCreateError, DropletShutdownError].include?(e.class)
161
- Log.error e.message
162
+ command.fail_power_off(e) if [SnapshotCreateError, DropletShutdownError].include?(e.class)
163
+ log.error e.message
162
164
  backtrace(e) if options.include? 'trace'
163
165
  send_error
164
166
  end
@@ -169,22 +171,30 @@ module DoSnapshot
169
171
  end
170
172
 
171
173
  no_commands do
174
+ 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 ))
177
+ end
178
+
179
+ 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 ))
182
+ end
183
+
172
184
  def set_mailer
173
- Mail.opts = options['mail']
174
- Mail.smtp = options['smtp']
185
+ Mail.load_options(opts: options['mail'], smtp: options['smtp'])
175
186
  end
176
187
 
177
188
  def send_error
178
- return unless Mail.opts
189
+ return unless mailer.opts
179
190
 
180
191
  Mail.opts[:subject] = 'Digital Ocean: Error.'
181
192
  Mail.opts[:body] = 'Please check your droplets.'
182
- Mail.notify
193
+ mailer.notify
183
194
  end
184
195
 
185
196
  def set_logger
186
- Log.quiet = options['quiet']
187
- Log.verbose = options['trace']
197
+ Log.load_options(quiet: options['quiet'], verbose: options['trace'])
188
198
  # Use Thor shell
189
199
  Log.shell = shell unless options['quiet']
190
200
  init_logger if options.include?('log')
@@ -197,7 +207,7 @@ module DoSnapshot
197
207
 
198
208
  def backtrace(e)
199
209
  e.backtrace.each do |t|
200
- Log.error t
210
+ log.error t
201
211
  end
202
212
  end
203
213
  end
@@ -5,167 +5,179 @@ module DoSnapshot
5
5
  # Our commands live here :)
6
6
  #
7
7
  class Command # rubocop:disable ClassLength
8
- class << self
9
- def snap
10
- Log.info 'Start performing operations'
11
- work_with_droplets
12
- Log.info 'All operations has been finished.'
8
+ include DoSnapshot::Log
9
+ include DoSnapshot::Mail
13
10
 
14
- Mail.notify if notify && !quiet
15
- end
11
+ def initialize(*args)
12
+ load_options(*args)
13
+ end
16
14
 
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
15
+ def snap
16
+ log.info 'Start performing operations'
17
+ work_with_droplets
18
+ log.info 'All operations has been finished.'
22
19
 
23
- def fail_power_off(e)
24
- return unless e && e.id
25
- api.start_droplet(e.id)
26
- rescue
27
- raise DropletFindError, e.message, e.backtrace
28
- end
20
+ mailer.notify if notify && !quiet
21
+ end
22
+
23
+ def fail_power_off(e)
24
+ return unless e && e.id
25
+ api.start_droplet(e.id)
26
+ rescue
27
+ raise DropletFindError, e.message, e.backtrace
28
+ end
29
+
30
+ def load_options(options = {}, skip = %w())
31
+ reset_options
32
+ options.each_pair do |key, option|
33
+ send("#{key}=", option) unless skip.include?(key)
34
+ end if options
35
+ end
29
36
 
30
- def stop_droplet(droplet)
31
- Log.debug 'Shutting down droplet.'
32
- api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
37
+ def reset_options
38
+ %i(droplets exclude only keep quiet stop clean timeout delay protocol threads api).each do |key|
39
+ send("#{key}=", nil)
33
40
  end
41
+ end
34
42
 
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}."
43
+ def stop_droplet(droplet)
44
+ log.debug 'Shutting down droplet.'
45
+ api.stop_droplet(droplet.id) unless droplet.status.include? 'off'
46
+ end
39
47
 
40
- today = DateTime.now
41
- name = "#{droplet.name}_#{today.strftime('%Y_%m_%d')}"
42
- # noinspection RubyResolve
43
- snapshot_size = api.snapshots(droplet).size
48
+ # Trying to create a snapshot.
49
+ #
50
+ def create_snapshot(droplet) # rubocop:disable MethodLength,Metrics/AbcSize
51
+ log.info "Start creating snapshot for droplet id: #{droplet.id} name: #{droplet.name}."
44
52
 
45
- Log.debug 'Wait until snapshot will be created.'
53
+ today = DateTime.now
54
+ name = "#{droplet.name}_#{today.strftime('%Y_%m_%d')}"
55
+ # noinspection RubyResolve
56
+ snapshot_size = api.snapshots(droplet).size
46
57
 
47
- api.create_snapshot droplet.id, name
58
+ log.debug 'Wait until snapshot will be created.'
48
59
 
49
- snapshot_size += 1
60
+ api.create_snapshot droplet.id, name
50
61
 
51
- Log.info "Snapshot name: #{name} created successfully."
52
- Log.info "Droplet id: #{droplet.id} name: #{droplet.name} snapshots: #{snapshot_size}."
62
+ snapshot_size += 1
53
63
 
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
64
+ log.info "Snapshot name: #{name} created successfully."
65
+ log.info "Droplet id: #{droplet.id} name: #{droplet.name} snapshots: #{snapshot_size}."
64
66
 
65
- def api
66
- @api ||= DoSnapshot::Adapter.api(protocol, delay: delay, timeout: timeout)
67
+ # Cleanup snapshots.
68
+ cleanup_snapshots droplet, snapshot_size if clean
69
+ rescue => e
70
+ case e.class.to_s
71
+ when 'DoSnapshot::SnapshotCleanupError'
72
+ raise e.class, e.message, e.backtrace
73
+ else
74
+ raise SnapshotCreateError.new(droplet.id), e.message, e.backtrace
67
75
  end
76
+ end
68
77
 
69
- protected
78
+ def api
79
+ @api ||= DoSnapshot::Adapter.api(protocol, delay: delay, timeout: timeout)
80
+ end
70
81
 
71
- attr_accessor :droplets, :exclude, :only
72
- attr_accessor :keep, :quiet, :stop, :clean, :timeout, :delay, :protocol
82
+ protected
73
83
 
74
- attr_writer :notify, :threads, :api
84
+ attr_accessor :droplets, :exclude, :only
85
+ attr_accessor :keep, :quiet, :stop, :clean, :timeout, :delay, :protocol
75
86
 
76
- def notify
77
- @notify ||= false
78
- end
87
+ attr_writer :threads, :api
79
88
 
80
- def threads
81
- @threads ||= []
82
- end
89
+ def notify
90
+ @notify ||= false
91
+ end
83
92
 
84
- # Working with list of droplets.
85
- #
86
- def work_with_droplets
87
- load_droplets
88
- dispatch_droplets
89
- Log.debug 'Working with list of DigitalOcean droplets'
90
- thread_chain
91
- end
93
+ def threads
94
+ @threads ||= []
95
+ end
92
96
 
93
- # Getting droplets list from API.
94
- # And store into object.
95
- #
96
- def load_droplets
97
- Log.debug 'Loading list of DigitalOcean droplets'
98
- self.droplets = api.droplets
99
- end
97
+ # Working with list of droplets.
98
+ #
99
+ def work_with_droplets
100
+ load_droplets
101
+ dispatch_droplets
102
+ log.debug 'Working with list of DigitalOcean droplets'
103
+ thread_chain
104
+ end
100
105
 
101
- # Dispatch received droplets, each by each.
102
- #
103
- def dispatch_droplets
104
- droplets.each do |droplet|
105
- id = droplet.id.to_s
106
- next if exclude.include? id
107
- next unless only.empty? || only.include?(id)
106
+ # Getting droplets list from API.
107
+ # And store into object.
108
+ #
109
+ def load_droplets
110
+ log.debug 'Loading list of DigitalOcean droplets'
111
+ self.droplets = api.droplets
112
+ end
108
113
 
109
- prepare_droplet id, droplet.name
110
- end
111
- end
114
+ # Dispatch received droplets, each by each.
115
+ #
116
+ def dispatch_droplets
117
+ droplets.each do |droplet|
118
+ id = droplet.id.to_s
119
+ next if exclude.include? id
120
+ next unless only.empty? || only.include?(id)
112
121
 
113
- # Join threads
114
- #
115
- def thread_chain
116
- threads.each(&:join)
122
+ prepare_droplet id, droplet.name
117
123
  end
124
+ end
118
125
 
119
- # Run threads
120
- #
121
- def thread_runner(droplet)
122
- threads << Thread.new do
123
- stop_droplet droplet
124
- create_snapshot droplet
125
- end
126
- end
126
+ # Join threads
127
+ #
128
+ def thread_chain
129
+ threads.each(&:join)
130
+ end
127
131
 
128
- # Preparing droplet to take a snapshot.
129
- # Droplet instance must be powered off first!
130
- #
131
- def prepare_droplet(id, name)
132
- Log.debug "Droplet id: #{id} name: #{name} "
133
- droplet = api.droplet id
134
-
135
- return unless droplet
136
- Log.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
137
- return if too_much_snapshots(droplet)
138
- thread_runner(droplet)
132
+ # Run threads
133
+ #
134
+ def thread_runner(droplet)
135
+ threads << Thread.new do
136
+ stop_droplet droplet
137
+ create_snapshot droplet
139
138
  end
139
+ end
140
140
 
141
- def too_much_snapshots(instance)
142
- # noinspection RubyResolve
143
- return false unless api.snapshots(instance).size >= keep
144
- warning_size(instance.id, instance.name, keep)
145
- stop ? true : false
146
- end
141
+ # Preparing droplet to take a snapshot.
142
+ # Droplet instance must be powered off first!
143
+ #
144
+ def prepare_droplet(id, name)
145
+ log.debug "Droplet id: #{id} name: #{name} "
146
+ droplet = api.droplet id
147
+
148
+ return unless droplet
149
+ log.info "Preparing droplet id: #{droplet.id} name: #{droplet.name} to take snapshot."
150
+ return if too_much_snapshots(droplet)
151
+ thread_runner(droplet)
152
+ end
153
+
154
+ def too_much_snapshots(instance)
155
+ # noinspection RubyResolve
156
+ return false unless api.snapshots(instance).size >= keep
157
+ warning_size(instance.id, instance.name, keep)
158
+ stop ? true : false
159
+ end
147
160
 
148
- # Cleanup our snapshots.
149
- #
150
- def cleanup_snapshots(droplet, size) # rubocop:disable Metrics/AbcSize
151
- return unless size > keep
161
+ # Cleanup our snapshots.
162
+ #
163
+ def cleanup_snapshots(droplet, size) # rubocop:disable Metrics/AbcSize
164
+ return unless size > keep
152
165
 
153
- warning_size(droplet.id, droplet.name, size)
166
+ warning_size(droplet.id, droplet.name, size)
154
167
 
155
- Log.debug "Cleaning up snapshots for droplet id: #{droplet.id} name: #{droplet.name}."
168
+ log.debug "Cleaning up snapshots for droplet id: #{droplet.id} name: #{droplet.name}."
156
169
 
157
- api.cleanup_snapshots(droplet, size - keep - 1)
158
- rescue => e
159
- raise SnapshotCleanupError, e.message, e.backtrace
160
- end
170
+ api.cleanup_snapshots(droplet, size - keep - 1)
171
+ rescue => e
172
+ raise SnapshotCleanupError, e.message, e.backtrace
173
+ end
161
174
 
162
- # Helpers
163
- #
164
- def warning_size(id, name, keep)
165
- message = "For droplet with id: #{id} and name: #{name} the maximum number #{keep} of snapshots is reached."
166
- Log.warning message
167
- self.notify = true
168
- end
175
+ # Helpers
176
+ #
177
+ def warning_size(id, name, keep)
178
+ message = "For droplet with id: #{id} and name: #{name} the maximum number #{keep} of snapshots is reached."
179
+ log.warn message
180
+ @notify = true
169
181
  end
170
182
  end
171
183
  end
@@ -4,33 +4,32 @@ require 'logger'
4
4
  module DoSnapshot
5
5
  # Shared logger
6
6
  #
7
- class Log
8
- class << self
9
- attr_accessor :logger, :shell, :quiet, :verbose
10
- attr_writer :buffer
11
-
12
- def buffer
13
- @buffer ||= %w()
14
- end
7
+ module Log
8
+ def log
9
+ UniversalLogger
10
+ end
15
11
 
16
- def info(message)
17
- log :info, message
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
18
  end
19
+ end
19
20
 
20
- def warning(message)
21
- log :warn, message
22
- end
21
+ class << self
22
+ attr_accessor :logger, :shell, :quiet, :verbose
23
+ attr_writer :buffer
23
24
 
24
- def error(message)
25
- log :error, message
25
+ def load_options(options = {})
26
+ options.each { |key, option| send("#{key}=", option) }
26
27
  end
27
28
 
28
- def debug(message)
29
- log :debug, message
29
+ def buffer
30
+ @buffer ||= %w()
30
31
  end
31
32
 
32
- protected
33
-
34
33
  def log(type, message)
35
34
  buffer << message
36
35
  logger.send(type, message) if logger
@@ -38,6 +37,8 @@ module DoSnapshot
38
37
  say message, color(type) unless print?(type)
39
38
  end
40
39
 
40
+ protected
41
+
41
42
  def print?(type)
42
43
  (type == :debug && !verbose) || quiet
43
44
  end
@@ -2,17 +2,63 @@
2
2
  require 'date'
3
3
  require 'pony'
4
4
  require_relative 'core_ext/hash'
5
+ require_relative 'log'
5
6
 
6
7
  module DoSnapshot
7
8
  # Shared mailer.
8
9
  #
9
- class Mail
10
+ module Mail
11
+ def mailer
12
+ UniversalMailer
13
+ end
14
+
15
+ # UniversalMailer is module to deal with singleton methods.
16
+ # Used to give classes access only for selected methods
17
+ #
18
+ module UniversalMailer
19
+ module_function
20
+
21
+ def notify
22
+ Mail.notify
23
+ end
24
+ end
25
+
10
26
  class << self
11
- attr_accessor :opts
12
- attr_writer :smtp, :opts_default, :smtp_default
27
+ include DoSnapshot::Log
28
+
29
+ attr_writer :mailer, :opts_default, :smtp_default
30
+
31
+ def load_options(options = {})
32
+ options.each { |key, option| send("#{key}=", option) }
33
+ end
34
+
35
+ def reset_options
36
+ @opts = opts_default
37
+ @smtp = smtp_default
38
+ end
39
+
40
+ def mailer
41
+ @mailer ||= Pony.method(:mail)
42
+ end
13
43
 
14
44
  def smtp
15
- @smtp ||= {}
45
+ @smtp ||= smtp_default.dup
46
+ end
47
+
48
+ def opts
49
+ @opts ||= opts_default.dup
50
+ end
51
+
52
+ def smtp=(options)
53
+ options.each_pair do |key, value|
54
+ smtp[key.to_sym] = value
55
+ end if options
56
+ end
57
+
58
+ def opts=(options)
59
+ options.each_pair do |key, value|
60
+ opts[key.to_sym] = value
61
+ end if options
16
62
  end
17
63
 
18
64
  # Sending message via Hash params.
@@ -20,17 +66,10 @@ module DoSnapshot
20
66
  # Options:: --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
21
67
  #
22
68
  def notify
23
- return unless opts
24
-
25
- opts.symbolize_keys!
26
- smtp.symbolize_keys!
27
-
28
- opts_setup
29
- smtp_setup
30
-
31
- Log.debug 'Sending e-mail notification.'
69
+ setup_notify
70
+ log.debug 'Sending e-mail notification.'
32
71
  # Look into your inbox :)
33
- Pony.mail(opts)
72
+ mailer.call(opts)
34
73
  end
35
74
 
36
75
  protected
@@ -52,17 +91,8 @@ module DoSnapshot
52
91
  }
53
92
  end
54
93
 
55
- def opts_setup
56
- opts_default.each_pair do |key, value|
57
- opts[key] = value unless opts.include? key
58
- end
59
- opts[:body] = "#{opts[:body]}\n\nTrace: #{DateTime.now}\n#{Log.buffer.join("\n")}"
60
- end
61
-
62
- def smtp_setup
63
- smtp_default.each_pair do |key, value|
64
- smtp[key] = value unless smtp.include? key
65
- end
94
+ def setup_notify
95
+ opts[:body] = "#{opts[:body]}\n\nTrace: #{DateTime.now}\n#{Log.buffer.join("\n")}"
66
96
  opts[:via_options] = smtp
67
97
  end
68
98
  end
@@ -2,5 +2,5 @@
2
2
  # Current version
3
3
  #
4
4
  module DoSnapshot
5
- VERSION = '0.0.15'
5
+ VERSION = '0.2.2'
6
6
  end
data/lib/do_snapshot.rb CHANGED
@@ -22,7 +22,7 @@ module DoSnapshot
22
22
  #
23
23
  class DropletShutdownError < RequestActionError
24
24
  def initialize(*args)
25
- Log.error "Droplet id: #{args[0]} is Failed to Power Off."
25
+ Log.log :error, "Droplet id: #{args[0]} is Failed to Power Off."
26
26
  super
27
27
  end
28
28
  end
@@ -32,7 +32,7 @@ module DoSnapshot
32
32
  #
33
33
  class SnapshotCreateError < RequestActionError
34
34
  def initialize(*args)
35
- Log.error "Droplet id: #{args[0]} is Failed to Snapshot."
35
+ Log.log :error, "Droplet id: #{args[0]} is Failed to Snapshot."
36
36
  super
37
37
  end
38
38
  end
@@ -42,7 +42,7 @@ module DoSnapshot
42
42
  #
43
43
  class DropletFindError < RequestError
44
44
  def initialize(*args)
45
- Log.error 'Droplet Not Found'
45
+ Log.log :error, 'Droplet Not Found'
46
46
  super
47
47
  end
48
48
  end
@@ -52,7 +52,7 @@ module DoSnapshot
52
52
  #
53
53
  class DropletListError < RequestError
54
54
  def initialize(*args)
55
- Log.error 'Droplet Listing is failed to retrieve'
55
+ Log.log :error, 'Droplet Listing is failed to retrieve'
56
56
  super
57
57
  end
58
58
  end
@@ -6,7 +6,6 @@ describe DoSnapshot::CLI do
6
6
  include_context 'api_v1_helpers'
7
7
 
8
8
  subject(:cli) { described_class }
9
- subject(:command) { DoSnapshot::Command }
10
9
  subject(:api) { DoSnapshot::Adapter::Digitalocean }
11
10
 
12
11
  describe '.initialize' do
@@ -28,7 +27,7 @@ describe DoSnapshot::CLI do
28
27
  stub_all_api(%w(100825 100823))
29
28
  hash_attribute_eq_no_stub(exclude: excluded_droplets, only: %w())
30
29
 
31
- expect(command.send('exclude'))
30
+ expect(@cli.command.send('exclude'))
32
31
  .to eq excluded_droplets
33
32
  end
34
33
 
@@ -37,7 +36,7 @@ describe DoSnapshot::CLI do
37
36
  stub_all_api(selected_droplets)
38
37
  hash_attribute_eq_no_stub(only: selected_droplets)
39
38
 
40
- expect(command.send('only'))
39
+ expect(@cli.command.send('only'))
41
40
  .to eq selected_droplets
42
41
  end
43
42
 
@@ -93,19 +92,19 @@ describe DoSnapshot::CLI do
93
92
  end
94
93
 
95
94
  it 'with mail' do
96
- hash_attribute_eq(mail_options)
95
+ hash_attribute_eq(mail: mail_options)
97
96
  end
98
97
 
99
98
  it 'with no mail' do
100
- without_hash_attribute_eq(mail_options)
99
+ without_hash_attribute_eq(mail: mail_options)
101
100
  end
102
101
 
103
102
  it 'with smtp' do
104
- hash_attribute_eq(smtp_options)
103
+ hash_attribute_eq(smtp: smtp_options)
105
104
  end
106
105
 
107
106
  it 'with no smtp' do
108
- without_hash_attribute_eq(smtp_options)
107
+ without_hash_attribute_eq(smtp: smtp_options)
109
108
  end
110
109
 
111
110
  it 'with log' do
@@ -153,9 +152,9 @@ describe DoSnapshot::CLI do
153
152
  stub_all_api
154
153
  options = default_options.merge!(:"#{name}" => value)
155
154
  @cli.options = @cli.options.merge(options)
156
- @cli.snap
155
+ @cli.update_command
157
156
 
158
- expect(command.send(name))
157
+ expect(@cli.command.send(name))
159
158
  .to eq value
160
159
  end
161
160
 
@@ -163,7 +162,7 @@ describe DoSnapshot::CLI do
163
162
  stub_all_api
164
163
  options = default_options.merge!(hash)
165
164
  @cli.options = @cli.options.merge(options)
166
- @cli.snap
165
+ @cli.update_command
167
166
  end
168
167
 
169
168
  def with_hash_attribute_eq(hash)
@@ -181,11 +180,11 @@ describe DoSnapshot::CLI do
181
180
  def hash_attribute_eq_no_stub(hash)
182
181
  options = default_options.merge!(hash)
183
182
  @cli.options = @cli.options.merge(options)
184
- @cli.snap
183
+ @cli.update_command
185
184
  end
186
185
 
187
186
  def set_api_attribute(options = { delay: delay, timeout: timeout }) # rubocop:disable Style/AccessorMethodName
188
- command.send('api=', api.new(options))
187
+ @cli.command.send('api=', api.new(options))
189
188
  end
190
189
 
191
190
  before(:each) do
@@ -6,7 +6,7 @@ describe DoSnapshot::Command do
6
6
  include_context 'uri_helpers'
7
7
  include_context 'api_v1_helpers'
8
8
 
9
- subject(:cmd) { DoSnapshot::Command }
9
+ subject(:cmd) { DoSnapshot::Command.new }
10
10
  subject(:log) { DoSnapshot::Log }
11
11
 
12
12
  describe '.snap' do
@@ -144,7 +144,6 @@ describe DoSnapshot::Command do
144
144
 
145
145
  def load_options(options = nil)
146
146
  options ||= default_options
147
- cmd.send('api=', nil)
148
147
  cmd.load_options(options, [:log, :mail, :smtp, :trace, :digital_ocean_client_id, :digital_ocean_api_key])
149
148
  end
150
149
 
@@ -0,0 +1,15 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ describe DoSnapshot::Mail do
5
+ include_context 'spec'
6
+
7
+ describe 'will send mail with options' do
8
+ it '#notify' do
9
+ DoSnapshot::Mail.reset_options
10
+ DoSnapshot::Mail.load_options(opts: mail_options, smtp: smtp_options)
11
+ expect { DoSnapshot::Mail.notify }.not_to raise_error
12
+ expect(DoSnapshot::Mail.smtp[:address]).to eq(smtp_options[:address])
13
+ end
14
+ end
15
+ end
@@ -4,6 +4,10 @@ require 'spec_helper'
4
4
  shared_context 'spec' do
5
5
  include_context 'api_helpers'
6
6
 
7
+ def do_not_send_email
8
+ allow(Pony).to receive(:deliver)
9
+ end
10
+
7
11
  let(:client_key) { 'foo' }
8
12
  let(:api_key) { 'bar' }
9
13
  let(:access_token) { 'sometoken' }
@@ -11,7 +15,7 @@ shared_context 'spec' do
11
15
  let(:droplet_id) { '100823' }
12
16
  let(:image_id) { '5019770' }
13
17
  let(:image_id2) { '5019903' }
14
- let(:cli_keys) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_client_id: 'NOTFOO', digital_ocean_client_key: 'NOTBAR', digital_ocean_access_token: 'NOTTOK') }
18
+ let(:cli_keys) { Thor::CoreExt::HashWithIndifferentAccess.new(digital_ocean_client_id: 'NOTFOO', digital_ocean_api_key: 'NOTBAR', digital_ocean_access_token: 'NOTTOK') }
15
19
  let(:snapshot_name) { "foo_#{DateTime.now.strftime('%Y_%m_%d')}" }
16
20
  let(:default_options) { Hash[protocol: 1, only: %w( 100823 ), exclude: %w(), keep: 3, stop: false, trace: true, clean: true, delay: 0, timeout: 600, droplets: nil, threads: []] }
17
21
  let(:no_exclude) { [] }
@@ -30,7 +34,7 @@ shared_context 'spec' do
30
34
  let(:smtp_options) { Thor::CoreExt::HashWithIndifferentAccess.new(address: 'smtp.gmail.com', port: '25', user_name: 'someuser', password: 'somepassword') }
31
35
  let(:log) { Thor::CoreExt::HashWithIndifferentAccess.new(log: "#{project_path}/log/test.log") }
32
36
 
33
- def stub_all_api(droplets = nil, active = false) # rubocop:disable MethodLength
37
+ def stub_all_api(droplets = nil, active = false)
34
38
  drops = []
35
39
  droplets ||= [droplet_id]
36
40
  droplets.each do |droplet|
@@ -90,6 +94,7 @@ shared_context 'spec' do
90
94
  end
91
95
 
92
96
  before(:each) do
97
+ do_not_send_email
93
98
  set_api_keys
94
99
  end
95
100
  end
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,6 @@
2
2
  require 'coveralls'
3
3
  Coveralls.wear! do
4
4
  add_filter '/spec/*'
5
- add_filter '/lib/do_snapshot/mail.rb'
6
5
  end
7
6
 
8
7
  require 'do_snapshot/cli'
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: do_snapshot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Merkulov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-06 00:00:00.000000000 Z
11
+ date: 2015-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: digitalocean_c
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -95,6 +109,7 @@ files:
95
109
  - spec/do_snapshot/adapter/digitalocean_v2_spec.rb
96
110
  - spec/do_snapshot/cli_spec.rb
97
111
  - spec/do_snapshot/command_spec.rb
112
+ - spec/do_snapshot/mail_spec.rb
98
113
  - spec/do_snapshots_spec.rb
99
114
  - spec/fixtures/digitalocean/v1/error_message.json
100
115
  - spec/fixtures/digitalocean/v1/response_event.json
@@ -155,6 +170,7 @@ test_files:
155
170
  - spec/do_snapshot/adapter/digitalocean_v2_spec.rb
156
171
  - spec/do_snapshot/cli_spec.rb
157
172
  - spec/do_snapshot/command_spec.rb
173
+ - spec/do_snapshot/mail_spec.rb
158
174
  - spec/do_snapshots_spec.rb
159
175
  - spec/fixtures/digitalocean/v1/error_message.json
160
176
  - spec/fixtures/digitalocean/v1/response_event.json