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 +4 -4
- data/README.md +85 -52
- data/do_snapshot.gemspec +2 -2
- data/lib/do_snapshot/cli.rb +70 -31
- data/lib/do_snapshot/command.rb +75 -51
- data/lib/do_snapshot/version.rb +1 -1
- data/lib/do_snapshot.rb +83 -7
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33604b56b4b901f20645dd6a6ac8f6530bb3c3b7
|
4
|
+
data.tar.gz: 57b7c547a40af585b4d28314a274d759ffad9559
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
-
|
9
|
-
-
|
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
|
-
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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/
|
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
|
12
|
-
spec.description = %q{Snapshot creator for Digital Ocean droplets. Multi-threading inside.
|
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
|
|
data/lib/do_snapshot/cli.rb
CHANGED
@@ -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 :
|
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
|
-
|
15
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
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', '
|
33
|
+
desc 'c / s / snap / create', 'DEFAULT. Create and cleanup snapshot\'s'
|
30
34
|
long_desc <<-LONGDESC
|
31
|
-
`do_snapshot
|
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
|
-
|
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
|
-
|
59
|
+
Keep latest 5 snapshots, not create new if we have more, send mail notification instead:
|
44
60
|
|
45
|
-
|
61
|
+
$ do_snapshot --keep 10 --stop --mail to:yourmail@example.com
|
46
62
|
|
47
|
-
|
63
|
+
### Cron example
|
48
64
|
|
49
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
data/lib/do_snapshot/command.rb
CHANGED
@@ -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
|
-
|
20
|
-
self.threads = []
|
21
|
-
|
16
|
+
Log.info 'Start performing operations'
|
22
17
|
work_droplets
|
23
|
-
|
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
|
-
|
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 :
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
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
|
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.
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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.
|
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
|
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
|
data/lib/do_snapshot/version.rb
CHANGED
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 :
|
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
|
-
|
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
|
41
|
-
|
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
|
+
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
|
-
|
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
|
131
|
-
|
130
|
+
summary: Snapshot creator for Digital Ocean droplets. Multi-threading. Auto-cleanup.
|
131
|
+
Cron optimized.
|
132
132
|
test_files:
|
133
133
|
- test/.keep
|