do_snapshot 0.0.4 → 0.0.5

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: f4c4999ce47e4ce7b2466c14205933af0cbdc961
4
- data.tar.gz: 0403072d2dd494b8f03090e7c4b7624414c9d7b8
3
+ metadata.gz: 33604b56b4b901f20645dd6a6ac8f6530bb3c3b7
4
+ data.tar.gz: 57b7c547a40af585b4d28314a274d759ffad9559
5
5
  SHA512:
6
- metadata.gz: 6c9866805ad171483316b5dd4fbb1e674dff9d779b097e23757167af90f99cb4acd39fd9827b1fbe3d52a5f4a8aae06578c49fa81ad9defea6f535be4183bb26
7
- data.tar.gz: 5ac4d9c275029df7a2300c258ba7b75268657353e906c01cfc375189a12c4d5be64e27253bb49e52df39a5656e67259f126ca28c4659a58a78cc5922837c6eee
6
+ metadata.gz: 72ea4af26a82e76649593595ca079ef18ea651b153344915ac246fc915a2ddbec8330ff7ed42d89a7e23c56828b6644e213eddc3b0aa137045a298687200b41e
7
+ data.tar.gz: b2afa75459cfe9fff4dd52aedb5c1b05ba509532433132f149ac539d311addfea1fe881d5851ab98ae280f5121dd762facffcd571a87ea7d70ae7e26b78b0765
data/README.md CHANGED
@@ -1,16 +1,17 @@
1
1
  # DoSnapshot
2
2
 
3
- You can use this gem to backup's DigitalOcean droplet's via snapshot.
3
+ You can use this gem to backup's DigitalOcean droplet's via snapshot method.
4
4
 
5
5
  Here some features:
6
6
 
7
- - Multiple threads out of the box.
8
- - Binary for cron and command-line.
9
- - Mail notification when maximum of snapshots for droplet reached.
7
+ - Multiple threads out of the box. No matter how much droplet's you have.
8
+ - Auto-cleanup for old snapshots.
9
+ - Binary special for cron and command-line.
10
+ - Mail notifications when fail or maximum of snapshots is reached for one or multiple droplets.
10
11
  - Custom mail settings (You can set [Pony](https://github.com/benprew/pony) mail settings).
11
12
  - Stop mode (when you don't want to create new snapshots when maximum is reached).
12
13
  - Logging into selected directory.
13
- - Trace mode for research.
14
+ - Verbose mode for research.
14
15
  - Quiet mode for silence.
15
16
 
16
17
  There not so much of dependencies:
@@ -35,64 +36,96 @@ Or install it yourself as:
35
36
 
36
37
  ## Usage
37
38
 
38
- First you may need to set DigitalOcean API keys:
39
-
40
-
41
- $ export DIGITAL_OCEAN_CLIENT_ID = "SOMEID"
42
- $ export DIGITAL_OCEAN_API_KEY = "SOMEKEY"
39
+ First you may need to set DigitalOcean API keys:
43
40
 
41
+ $ export DIGITAL_OCEAN_CLIENT_ID="SOMEID"
42
+ $ export DIGITAL_OCEAN_API_KEY="SOMEKEY"
44
43
 
45
- If you want to set keys without environment, than set it via options:
44
+ If you want to set keys without environment, than set it via options when you run do_snapshot:
46
45
 
47
46
  $ do_snapshot --digital-ocean-client-id YOURLONGAPICLIENTID --digital-ocean-api-key YOURLONGAPIKEY
48
47
 
48
+ #### Basic usage
49
+
50
+ Keep latest 5 and cleanup older if maximum is reached.
51
+ Here we `keeping` only 5 `latest` snapshots and `cleanup` older after new one is created.
52
+ **If creation of snapshots failed no one will be deleted.**
53
+
54
+ **By default we `keep` 10 droplets.**
55
+
56
+ $ do_snapshot --keep 5 -c
57
+
58
+ Keep latest 3 from selected droplets:
59
+
60
+ $ do_snapshot --only 123456 1234567 --keep 3
61
+
62
+ Working with all except selected droplets:
63
+
64
+ $ do_snapshot --exclude 123456 123457
65
+
66
+ Keep latest 5 snapshots, send mail notification instead of creating new one:
67
+
68
+ $ do_snapshot --keep 10 --stop --mail to:yourmail@example.com
69
+
49
70
  E-mail notifications disabled out of the box.
50
71
  For working mailer you need to set e-mail settings via run options.
51
72
 
52
- ```shell
53
- Usage:
54
- do_snapshot create
55
-
56
- Options:
57
- -o, [--only=123456 123456 123456] # Use only selected droplets.
58
- -e, [--exclude=123456 123456 123456] # Except some droplets.
59
- -k, [--keep=5] # How much snapshots you want to keep?
60
- # Default: 10
61
- -s, [--stop], [--no-stop] # Stop creating snapshots if maximum is reached.
62
- -m, [--mail=to:yourmail@example.com] # Receive mail if maximum is reached.
63
- -t, [--smtp=user_name:yourmail@example.com password:password] # SMTP options.
64
- -l, [--log=/Users/someone/.do_snapshot/main.log] # Log file path. By default logging is disabled.
65
- -d, [--trace], [--no-trace] # Debug mode.
66
- -q, [--quiet], [--no-quiet] # Quiet mode. If don't need any messages and log's
67
- [--digital-ocean-client-id=YOURLONGAPICLIENTID] # DIGITAL_OCEAN_CLIENT_ID. if you can't use environment.
68
- [--digital-ocean-api-key=YOURLONGAPIKEY] # DIGITAL_OCEAN_API_KEY. if you can't use environment.
69
-
70
- Description:
71
- `do_snapshot create` will create and cleanup snapshots on your droplets.
72
-
73
- You can optionally specify parameters to select or exclude some droplets.
74
-
75
- Advanced options example for MAIL feature:
76
-
77
- --mail to:mail@somehost.com from:from@host.com
78
- --smtp address:smtp.gmail.com user_name:someuser password:somepassword
79
-
80
- For more details look here: [https://github.com/benprew/pony](https://github.com/benprew/pony)
81
-
82
- Example:
83
-
84
- > $ do_snapshot --keep 5 --quiet
85
-
86
- > $ do_snapshot --only 123456 1234567 --store 3
87
-
88
- > $ do_snapshot --exclude 123456 123457
89
-
90
- > $ do_snapshot --keep 10 --stop true --mail to:yourmail@example.com
91
- ```
73
+ --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com port:25 user_name:someuser password:somepassword
74
+
75
+ #### Cron example
76
+
77
+ 0 4 * * 7 /.../bin/do_snapshot -k 5 -m to:TO from:FROM -t address:HOST user_name:LOGIN password:PASSWORD port:2525 -q -c
78
+
79
+ #### Real world example
80
+
81
+ $ bin/do_snapshot --only 123456 -k 3 -c -m to:TO from:FROM -t address:HOST user_name:LOGIN password:PASSWORD port:2525 -v
82
+
83
+ Checking DigitalOcean Id's.
84
+ Start performing operations
85
+ Setting DigitalOcean Id's.
86
+ Loading list of DigitalOcean droplets
87
+ Working with list of DigitalOcean droplets
88
+ Preparing droplet id: 123456 name: mrcr.ru to take snapshot.
89
+ Shutting down droplet.
90
+ Start creating snapshot for droplet id: 123456 name: mrcr.ru.
91
+ Wait until snapshot will be created.
92
+ Snapshot name: mrcr.ru_2014_07_18 created successfully.
93
+ Droplet id: 123456 name: mrcr.ru snapshots: 4.
94
+ For droplet with id: 123456 and name: mrcr.ru the maximum number 3 of snapshots is reached.
95
+ Cleaning up snapshots for droplet id: 123456 name: mrcr.ru.
96
+ Snapshot name: mrcr.ru_2014_07_17 delete requested.
97
+ All operations has been finished.
98
+ Sending e-mail notification.
99
+
100
+ ### All options:
101
+
102
+ > $ do_snapshot c
103
+
104
+ aliases: s, snap, create
105
+
106
+ Options:
107
+ -o, [--only=123456 123456 123456] # Select some droplets.
108
+ -e, [--exclude=123456 123456 123456] # Except some droplets.
109
+ -k, [--keep=5] # How much snapshots you want to keep?
110
+ # Default: 10
111
+ -m, [--mail=to:yourmail@example.com] # Receive mail if fail or maximum is reached.
112
+ -t, [--smtp=user_name:yourmail@example.com password:password] # SMTP options.
113
+ -l, [--log=/Users/someone/.do_snapshot/main.log] # Log file path. By default logging is disabled.
114
+ -c, [--clean], [--no-clean] # Cleanup snapshots after create. If you have more images than you want to `keep`, older will be deleted.
115
+ -s, [--stop], [--no-stop] # Stop creating snapshots if maximum is reached.
116
+ -v, [--trace], [--no-trace] # Verbose mode.
117
+ -q, [--quiet], [--no-quiet] # Quiet mode. If don't need any messages in console.
118
+ [--digital-ocean-client-id=YOURLONGAPICLIENTID] # DIGITAL_OCEAN_CLIENT_ID. if you can't use environment.
119
+ [--digital-ocean-api-key=YOURLONGAPIKEY] # DIGITAL_OCEAN_API_KEY. if you can't use environment.
120
+
121
+ Description:
122
+ `do_snapshot` able to create and cleanup snapshots on your droplets.
123
+
124
+ You can optionally specify parameters to select or exclude some droplets.
92
125
 
93
126
  ## Contributing
94
127
 
95
- 1. Fork it ( https://github.com/[my-github-username]/do_snapshot/fork )
128
+ 1. Fork it ( https://github.com/merqlove/do_snapshot/fork )
96
129
  2. Create your feature branch (`git checkout -b my-new-feature`)
97
130
  3. Commit your changes (`git commit -am 'Add some feature'`)
98
131
  4. Push to the branch (`git push origin my-new-feature`)
data/do_snapshot.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = DoSnapshot::VERSION
9
9
  spec.authors = ['Alexander Merkulov']
10
10
  spec.email = ['sasha@merqlove.ru']
11
- spec.summary = %q{Snapshot creator for Digital Ocean droplets. Multi-threading inside. Use it with Cron or other tools.}
12
- spec.description = %q{Snapshot creator for Digital Ocean droplets. Multi-threading inside. Use it with Cron or other tools.}
11
+ spec.summary = %q{Snapshot creator for Digital Ocean droplets. Multi-threading. Auto-cleanup. Cron optimized.}
12
+ spec.description = %q{Snapshot creator for Digital Ocean droplets. Multi-threading inside. Auto-cleanup feature. No matter how much droplets you have. Cron optimized.}
13
13
  spec.homepage = 'http://github.com/merqlove/do_snapshot'
14
14
  spec.license = 'MIT'
15
15
 
@@ -1,23 +1,27 @@
1
1
  require 'do_snapshot'
2
2
  require 'do_snapshot/command'
3
- require 'thor'
4
3
 
5
4
  module DoSnapshot
6
5
  # CLI is here
7
6
  #
8
7
  class CLI < Thor
9
- default_task :create
8
+ default_task :snap
9
+
10
+ map %w( c s create ) => :snap
11
+ map %w( -V ) => :version
10
12
 
11
13
  def initialize(*args)
12
14
  super
13
15
 
14
- # Use Thor log especially
15
- Log.thor_log = Thor::Shell::Color.new unless options.include?('quiet')
16
+ Log.quiet = options['quiet']
17
+ # Use Thor shell
18
+ Log.shell = shell unless Log.quiet
19
+ Log.verbose = options['trace']
16
20
 
17
- if options.include?('log')
18
- Log.logger = Logger.new(options['log'])
19
- Log.logger.level = options.include?('trace') ? Logger::DEBUG : Logger::INFO
20
- end
21
+ logger if options.include?('log')
22
+
23
+ Log.mail = options['mail']
24
+ Log.smtp = options['smtp']
21
25
 
22
26
  # Check for keys via options
23
27
  ENV['DIGITAL_OCEAN_CLIENT_ID'] = options['digital_ocean_client_id'] if options.include? 'digital_ocean_client_id'
@@ -26,49 +30,84 @@ module DoSnapshot
26
30
  try_keys_first
27
31
  end
28
32
 
29
- desc 'create', 'create and cleanup snapshot\'s'
33
+ desc 'c / s / snap / create', 'DEFAULT. Create and cleanup snapshot\'s'
30
34
  long_desc <<-LONGDESC
31
- `do_snapshot create` will create and cleanup snapshots on your droplets.
35
+ `do_snapshot` able to create and cleanup snapshots on your droplets.
32
36
 
33
37
  You can optionally specify parameters to select or exclude some droplets.
34
38
 
35
- Advanced options example for MAIL feature:
39
+ ### Advanced options example for MAIL feature:
36
40
 
37
- --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
41
+ --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com port:25 user_name:someuser password:somepassword
38
42
 
39
43
  For more details look here: https://github.com/benprew/pony
40
44
 
41
- Example:
45
+ ### Examples
46
+
47
+ Keep latest 5 and cleanup older if maximum is reached:
48
+
49
+ $ do_snapshot --keep 5 -c
50
+
51
+ Keep latest 3 from selected droplets:
52
+
53
+ $ do_snapshot --only 123456 1234567 --keep 3
54
+
55
+ Working with all except selected droplets:
56
+
57
+ $ do_snapshot --exclude 123456 123457
42
58
 
43
- > $ do_snapshot --keep 5
59
+ Keep latest 5 snapshots, not create new if we have more, send mail notification instead:
44
60
 
45
- > $ do_snapshot --only 123456 1234567 --store 3
61
+ $ do_snapshot --keep 10 --stop --mail to:yourmail@example.com
46
62
 
47
- > $ do_snapshot --exclude 123456 123457
63
+ ### Cron example
48
64
 
49
- > $ do_snapshot --keep 10 --stop true --mail to:yourmail@example.com
65
+ 0 4 * * 7 /.../bin/do_snapshot -k 5 -m to:TO from:FROM -t address:HOST user_name:LOGIN password:PASSWORD port:2525 -q -c
66
+
67
+ VERSION: #{DoSnapshot::VERSION}
50
68
  LONGDESC
51
- option :only, type: :array, default: [], aliases: ['-o'], banner: '123456 123456 123456', desc: 'Use only selected droplets.'
52
- option :exclude, type: :array, default: [], aliases: ['-e'], banner: '123456 123456 123456', desc: 'Except some droplets.'
53
- option :keep, type: :numeric, default: 10, aliases: ['-k'], banner: '5', desc: 'How much snapshots you want to keep?'
54
- option :stop, type: :boolean, aliases: ['-s'], desc: 'Stop creating snapshots if maximum is reached.'
55
- option :mail, type: :hash, default: {}, aliases: ['-m'], banner: 'to:yourmail@example.com', desc: 'Receive mail if maximum is reached.'
56
- option :smtp, type: :hash, default: {}, aliases: ['-t'], banner: 'user_name:yourmail@example.com password:password', desc: 'SMTP options.'
57
- option :log, type: :string, aliases: ['-l'], banner: '/Users/someone/.do_snapshot/main.log', desc: 'Log file path. By default logging is disabled.'
58
- option :trace, type: :boolean, aliases: ['-d'], desc: 'Debug mode.'
59
- option :quiet, type: :boolean, aliases: ['-q'], desc: 'Quiet mode. If don\'t need any messages and log\'s'
60
- option :digital_ocean_client_id, type: :string, banner: 'YOURLONGAPICLIENTID', desc: 'DIGITAL_OCEAN_CLIENT_ID. if you can\'t use environment.'
61
- option :digital_ocean_api_key, type: :string, banner: 'YOURLONGAPIKEY', desc: 'DIGITAL_OCEAN_API_KEY. if you can\'t use environment.'
62
-
63
- def create
64
- DoSnapshot::Command.execute options, %w( log trace quiet digital_ocean_client_id digital_ocean_api_key )
69
+
70
+ method_option :only, type: :array, default: [], aliases: %w( -o ), banner: '123456 123456 123456', desc: 'Select some droplets.'
71
+ method_option :exclude, type: :array, default: [], aliases: %w( -e ), banner: '123456 123456 123456', desc: 'Except some droplets.'
72
+ method_option :keep, type: :numeric, default: 10, aliases: %w( -k ), banner: '5', desc: 'How much snapshots you want to keep?'
73
+ method_option :delay, type: :numeric, default: 10, aliases: %w( -d ), banner: '5', desc: 'Delay between snapshot operation status requests.'
74
+ method_option :mail, type: :hash, aliases: %w( -m ), banner: 'to:yourmail@example.com', desc: 'Receive mail if fail or maximum is reached.'
75
+ method_option :smtp, type: :hash, aliases: %w( -t ), banner: 'user_name:yourmail@example.com password:password', desc: 'SMTP options.'
76
+ method_option :log, type: :string, aliases: %w( -l ), banner: '/Users/someone/.do_snapshot/main.log', desc: 'Log file path. By default logging is disabled.'
77
+ method_option :clean, type: :boolean, aliases: %w( -c ), desc: 'Cleanup snapshots after create. If you have more images than you want to `keep`, older will be deleted.'
78
+ method_option :stop, type: :boolean, aliases: %w( -s), desc: 'Stop creating snapshots if maximum is reached.'
79
+ method_option :trace, type: :boolean, aliases: %w( -v ), desc: 'Verbose mode.'
80
+ method_option :quiet, type: :boolean, aliases: %w( -q ), desc: 'Quiet mode. If don\'t need any messages and in console.'
81
+
82
+ method_option :digital_ocean_client_id, type: :string, banner: 'YOURLONGAPICLIENTID', desc: 'DIGITAL_OCEAN_CLIENT_ID. if you can\'t use environment.'
83
+ method_option :digital_ocean_api_key, type: :string, banner: 'YOURLONGAPIKEY', desc: 'DIGITAL_OCEAN_API_KEY. if you can\'t use environment.'
84
+
85
+ def snap
86
+ Command.execute options, %w( log trace digital_ocean_client_id digital_ocean_api_key )
65
87
  rescue => e
88
+
89
+ Command.fail_power_on(e.id) if e && e.class == SnapshotCreateError && e.respond_to?('id')
66
90
  Log.error e.message
67
91
  backtrace(e) if options.include? 'trace'
92
+ if Log.mail
93
+ Log.mail[:subject] = 'Digital Ocean: Error.'
94
+ Log.mail[:body] = 'Please check your droplets.'
95
+ Log.notify
96
+ end
97
+ end
98
+
99
+ desc 'version, -V', 'Shows the version of the currently installed DoSnapshot gem'
100
+ def version
101
+ puts DoSnapshot::VERSION
68
102
  end
69
103
 
70
104
  protected
71
105
 
106
+ def logger
107
+ Log.logger = Logger.new(options['log'])
108
+ Log.logger.level = Log.verbose ? Logger::DEBUG : Logger::INFO
109
+ end
110
+
72
111
  def backtrace(e)
73
112
  e.backtrace.each do |t|
74
113
  Log.error t
@@ -1,7 +1,4 @@
1
1
  require 'digitalocean'
2
- require 'date'
3
- require 'pony'
4
- require 'core_ext/hash'
5
2
  require 'thread'
6
3
 
7
4
  module DoSnapshot
@@ -16,26 +13,41 @@ module DoSnapshot
16
13
  send("#{key}=", option) unless skip.include? key
17
14
  end
18
15
 
19
- self.notify = false
20
- self.threads = []
21
-
16
+ Log.info 'Start performing operations'
22
17
  work_droplets
23
- email_message if notify && mail
18
+ Log.info 'All operations has been finished.'
19
+
20
+ Log.notify if notify && !quiet
21
+ end
22
+
23
+ def fail_power_on(id)
24
+ return unless id
24
25
 
25
- Log.info 'All snapshots requested'
26
+ set_id
27
+ instance = Digitalocean::Droplet.find(id)
28
+ fail instance.message unless instance.status.include? 'OK'
29
+ if instance.droplet.status.include? 'active'
30
+ Log.info "Droplet id: #{id} failed to snapshot. But it still running."
31
+ else
32
+ Digitalocean::Droplet.power_on(id)
33
+ Log.info "Droplet id: #{id} failed to snapshot. POWER ON has been requested."
34
+ end
26
35
  end
27
36
 
28
37
  protected
29
38
 
30
- attr_accessor :droplets
31
- attr_accessor :exclude
32
- attr_accessor :only
33
- attr_accessor :keep
34
- attr_accessor :mail
35
- attr_accessor :smtp
36
- attr_accessor :stop
37
- attr_accessor :notify
38
- attr_accessor :threads
39
+ attr_accessor :droplets, :mail, :smtp, :exclude, :only
40
+ attr_accessor :delay, :keep, :quiet, :stop, :clean
41
+
42
+ attr_writer :notify, :threads
43
+
44
+ def notify
45
+ @notify ||= false
46
+ end
47
+
48
+ def threads
49
+ @threads ||= []
50
+ end
39
51
 
40
52
  # Getting droplets list from API.
41
53
  # And store into object.
@@ -44,7 +56,7 @@ module DoSnapshot
44
56
  set_id
45
57
  Log.debug 'Loading list of DigitalOcean droplets'
46
58
  droplets = Digitalocean::Droplet.all
47
- fail droplets.message unless droplets.status == 'OK'
59
+ fail droplets.message unless droplets.status.include? 'OK'
48
60
  self.droplets = droplets.droplets
49
61
  end
50
62
 
@@ -59,7 +71,7 @@ module DoSnapshot
59
71
  next if !only.empty? && !only.include?(id)
60
72
 
61
73
  instance = Digitalocean::Droplet.find(id)
62
- fail instance.message unless instance.status == 'OK'
74
+ fail instance.message unless instance.status.include? 'OK'
63
75
 
64
76
  prepare_instance instance.droplet
65
77
  end
@@ -69,7 +81,7 @@ module DoSnapshot
69
81
  # Threads review
70
82
  #
71
83
  def thread_chain
72
- threads.each {|t| t.join}
84
+ threads.each { |t| t.join }
73
85
  end
74
86
 
75
87
  # Preparing instance to take snapshot.
@@ -77,9 +89,9 @@ module DoSnapshot
77
89
  #
78
90
  def prepare_instance(instance)
79
91
  return unless instance
80
- Log.debug "Preparing droplet id: #{instance.id} name: #{instance.name} to snapshot."
92
+ Log.info "Preparing droplet id: #{instance.id} name: #{instance.name} to take snapshot."
81
93
 
82
- warning_size = "For droplet with id: #{instance.id} and name: #{instance.name} the maximum #{keep} is reached."
94
+ warning_size = "For droplet with id: #{instance.id} and name: #{instance.name} the maximum number #{keep} of snapshots is reached."
83
95
 
84
96
  if instance.snapshots.size >= keep && stop
85
97
  Log.warning warning_size
@@ -90,11 +102,15 @@ module DoSnapshot
90
102
  # Stopping instance.
91
103
  Log.debug 'Shutting down droplet.'
92
104
  threads << Thread.new do
93
- unless instance.status.include? 'off'
94
- event = Digitalocean::Droplet.power_off(instance.id)
95
- if event.status.include? 'OK'
96
- sleep 1.3 until get_event_status(event.event_id)
105
+ begin
106
+ unless instance.status.include? 'off'
107
+ event = Digitalocean::Droplet.power_off(instance.id)
108
+ if event.status.include? 'OK'
109
+ sleep delay until get_event_status(event.event_id)
110
+ end
97
111
  end
112
+ rescue => e
113
+ raise DropletShutdownError.new(instance.id), e.message, e.backtrace
98
114
  end
99
115
 
100
116
  # Create snapshot.
@@ -105,7 +121,7 @@ module DoSnapshot
105
121
  # Trying to create a snapshot.
106
122
  #
107
123
  def create_snapshot(instance, warning_size)
108
- Log.debug "Start creating snapshot for droplet id: #{instance.id} name: #{instance.name}."
124
+ Log.info "Start creating snapshot for droplet id: #{instance.id} name: #{instance.name}."
109
125
 
110
126
  today = DateTime.now
111
127
  name = "#{instance.name}_#{today.strftime('%Y_%m_%d')}"
@@ -120,7 +136,7 @@ module DoSnapshot
120
136
 
121
137
  Log.debug 'Wait until snapshot will be created.'
122
138
 
123
- sleep 10 until get_event_status(event.event_id)
139
+ sleep delay until get_event_status(event.event_id)
124
140
 
125
141
  snapshot_size += 1
126
142
 
@@ -130,9 +146,40 @@ module DoSnapshot
130
146
  if snapshot_size > keep
131
147
  Log.warning warning_size if snapshot_size > keep
132
148
  self.notify = true
149
+
150
+ # Cleanup snapshots.
151
+ cleanup_snapshots instance, (snapshot_size - keep - 1) if clean
152
+ end
153
+ rescue => e
154
+ case e.class
155
+ when SnapshotCleanupError
156
+ raise
157
+ else
158
+ raise SnapshotCreateError.new(instance.id), e.message, e.backtrace
133
159
  end
134
160
  end
135
161
 
162
+ # Cleanup our snapshots.
163
+ #
164
+ def cleanup_snapshots(instance, size)
165
+ Log.debug "Cleaning up snapshots for droplet id: #{instance.id} name: #{instance.name}."
166
+
167
+ (0..size).each do |i|
168
+ snapshot = instance.snapshots[i]
169
+ event = Digitalocean::Image.destroy(snapshot.id)
170
+
171
+ if !event
172
+ fail 'Something wrong with DigitalOcean or with your connection :)'
173
+ elsif event && !event.status.include?('OK')
174
+ fail event.message
175
+ end
176
+
177
+ Log.info "Snapshot name: #{snapshot.name} delete requested."
178
+ end
179
+ rescue => e
180
+ raise SnapshotCleanupError.new(instance.id), e.message, e.backtrace
181
+ end
182
+
136
183
  # Looking for event status.
137
184
  #
138
185
  # Before snapshot we to know that machine has powered off.
@@ -143,29 +190,6 @@ module DoSnapshot
143
190
  event.event.percentage && event.event.percentage.include?('100') ? true : false
144
191
  end
145
192
 
146
- # Sending message via Hash params.
147
- #
148
- # Options:: -m to:mail@somehost.com from:from@host.com -t address:smtp.gmail.com user_name:someuser password:somepassword
149
- #
150
- def email_message
151
- mail.symbolize_keys!
152
- smtp.symbolize_keys!
153
-
154
- mail[:subject] = 'DigitalOcean Snapshot maximum is reached.' unless mail[:subject]
155
- mail[:body] = "Please cleanup your Digital Ocean account. \nSnapshot maximum is reached." unless mail[:body]
156
- mail[:from] = 'noreply@someonelse.com' unless mail[:from]
157
- mail[:via] = :smtp unless mail[:via]
158
-
159
- smtp[:domain] = 'localhost.localdomain' unless smtp[:domain]
160
- smtp[:port] = '25' unless smtp[:port]
161
-
162
- mail[:via_options] = smtp
163
-
164
- Log.debug 'Sending e-mail notification.'
165
- # Look into your inbox :)
166
- Pony.mail(mail)
167
- end
168
-
169
193
  # Set id's of Digital Ocean API.
170
194
  #
171
195
  def set_id
@@ -1,5 +1,5 @@
1
1
  # Current version
2
2
  #
3
3
  module DoSnapshot
4
- VERSION = '0.0.4'
4
+ VERSION = '0.0.5'
5
5
  end
data/lib/do_snapshot.rb CHANGED
@@ -1,44 +1,120 @@
1
1
  require 'do_snapshot/version'
2
+ require 'thor'
2
3
  require 'logger'
4
+ require 'date'
5
+ require 'pony'
6
+ require 'core_ext/hash'
3
7
 
4
8
  # Used primary for creating snapshot's as backups for DigitalOcean
5
9
  #
6
10
  module DoSnapshot
11
+ # Set multiple Errors with `id` @param
12
+ #
13
+ class DigitalOceanError < StandardError
14
+ attr_reader :id
15
+ # @param [Object] id
16
+ def initialize(id)
17
+ @id = id
18
+ end
19
+ end
20
+ class DropletShutdownError < DigitalOceanError; end
21
+ class SnapshotCreateError < DigitalOceanError; end
22
+ class SnapshotCleanupError < DigitalOceanError; end
23
+
7
24
  # Shared logger
8
25
  #
9
26
  class Log
10
27
  class << self
11
28
  attr_accessor :logger
12
- attr_accessor :thor_log
29
+ attr_accessor :shell
30
+ attr_accessor :mail
31
+ attr_accessor :quiet
32
+ attr_accessor :verbose
33
+ attr_writer :smtp
34
+
35
+ def smtp
36
+ @smtp ||= {}
37
+ end
13
38
 
14
39
  def log(type, message)
40
+ buffer << message
15
41
  logger.send(type, message) if logger
42
+
43
+ say message, color(type) unless type == :debug && !debug?
44
+ end
45
+
46
+ def color(type)
47
+ case type
48
+ when :debug
49
+ :white
50
+ when :error
51
+ :red
52
+ when :warn
53
+ :yellow
54
+ else
55
+ :green
56
+ end
16
57
  end
17
58
 
18
59
  def info(message)
19
60
  log :info, message
20
- say message, :green
21
61
  end
22
62
 
23
63
  def warning(message)
24
64
  log :warn, message
25
- say message, :yellow
26
65
  end
27
66
 
28
67
  def error(message)
29
68
  log :error, message
30
- say message, :red
31
69
  end
32
70
 
33
71
  def debug(message)
34
72
  log :debug, message
35
- say message, :white if logger && logger.level == Logger::DEBUG
73
+ end
74
+
75
+ def say(message, color)
76
+ shell.say message, color if shell
77
+ end
78
+
79
+ def debug?
80
+ logger && logger.level == Logger::DEBUG
81
+ end
82
+
83
+ # Sending message via Hash params.
84
+ #
85
+ # Options:: --mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
86
+ #
87
+ def notify
88
+ return unless mail
89
+
90
+ mail.symbolize_keys!
91
+ smtp.symbolize_keys!
92
+
93
+ notify_init
94
+
95
+ Log.debug 'Sending e-mail notification.'
96
+ # Look into your inbox :)
97
+ Pony.mail(mail)
36
98
  end
37
99
 
38
100
  protected
39
101
 
40
- def say(message, color)
41
- thor_log.say message, color if thor_log
102
+ def notify_init
103
+ mail[:subject] = 'Digital Ocean: maximum snapshots is reached.' unless mail[:subject]
104
+ mail[:body] = "Please cleanup your Digital Ocean account.\nSnapshot maximum is reached." unless mail[:body]
105
+ mail[:from] = 'noreply@someonelse.com' unless mail[:from]
106
+ mail[:to] = 'to@someonelse.com' unless mail[:to]
107
+ mail[:via] = :smtp unless mail[:via]
108
+ mail[:body] = "#{mail[:body]}\n\nTrace: #{DateTime.now}\n#{buffer.join("\n")}"
109
+ smtp[:domain] = 'localhost.localdomain' unless smtp[:domain]
110
+ smtp[:port] = '25' unless smtp[:port]
111
+
112
+ mail[:via_options] = smtp
113
+ end
114
+
115
+ attr_writer :buffer
116
+ def buffer
117
+ @buffer ||= %w()
42
118
  end
43
119
  end
44
120
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: do_snapshot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Merkulov
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  description: Snapshot creator for Digital Ocean droplets. Multi-threading inside.
84
- Use it with Cron or other tools.
84
+ Auto-cleanup feature. No matter how much droplets you have. Cron optimized.
85
85
  email:
86
86
  - sasha@merqlove.ru
87
87
  executables:
@@ -127,7 +127,7 @@ rubyforge_project:
127
127
  rubygems_version: 2.2.2
128
128
  signing_key:
129
129
  specification_version: 4
130
- summary: Snapshot creator for Digital Ocean droplets. Multi-threading inside. Use
131
- it with Cron or other tools.
130
+ summary: Snapshot creator for Digital Ocean droplets. Multi-threading. Auto-cleanup.
131
+ Cron optimized.
132
132
  test_files:
133
133
  - test/.keep