do_snapshot 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|