do_snapshot 0.0.1
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 +7 -0
- data/.gitignore +25 -0
- data/.rubocop.yml +11 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/do_snapshot +12 -0
- data/do_snapshot.gemspec +27 -0
- data/lib/do_snapshot.rb +46 -0
- data/lib/do_snapshot/cli.rb +73 -0
- data/lib/do_snapshot/command.rb +166 -0
- data/lib/do_snapshot/core_ext/hash.rb +36 -0
- data/lib/do_snapshot/version.rb +5 -0
- data/test/.keep +0 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7053ccac28ae155fac055356c0e2ef2e95373ffb
|
4
|
+
data.tar.gz: d315d1e4faa88f2b6562b64ab79d8480e01e25c5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 77ca8773db485352055ca4118661451bcf1c55a538e248de7e7ed3eb44e6e8e5d6314ebb66645ed54f57f4fb31c76a21993000b1f97cc0f01223195cb3daeb80
|
7
|
+
data.tar.gz: 7d91bb1e124c979af67c26aed36c31e4d3e1d0f958b1ac01ca1f8e122fe8dba8e8e9e2585c1cd4d4973855e572470df7c7ea1a047b5b8e54c2fa754a3e80612a
|
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
.idea
|
24
|
+
.irb_history
|
25
|
+
|
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Alexander Merkulov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# DoSnapshot
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'do_snapshot'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install do_snapshot
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/[my-github-username]/do_snapshot/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/do_snapshot
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# resolve bin path, ignoring symlinks
|
4
|
+
require 'pathname'
|
5
|
+
bin_file = Pathname.new(__FILE__).realpath
|
6
|
+
|
7
|
+
# add self to libpath
|
8
|
+
$:.unshift File.expand_path('../../lib', bin_file)
|
9
|
+
|
10
|
+
require 'do_snapshot/cli'
|
11
|
+
|
12
|
+
DoSnapshot::CLI.start(ARGV)
|
data/do_snapshot.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'do_snapshot/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'do_snapshot'
|
8
|
+
spec.version = DoSnapshot::VERSION
|
9
|
+
spec.authors = ['Alexander Merkulov']
|
10
|
+
spec.email = ['sasha@merqlove.ru']
|
11
|
+
spec.summary = %q{Snapshot runner for Digital Ocean droplets. Use it with Cron or other tools.}
|
12
|
+
spec.description = %q{Snapshot runner for Digital Ocean droplets. Use it with Cron or other tools.}
|
13
|
+
spec.homepage = 'http://github.com/merqlove/do_snapshot'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_dependency 'digitalocean', '~> 1.2'
|
22
|
+
spec.add_dependency 'thor'
|
23
|
+
spec.add_dependency 'pony'
|
24
|
+
|
25
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
|
+
end
|
data/lib/do_snapshot.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'do_snapshot/version'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
|
5
|
+
# Used primary for creating snapshot's as backups for DigitalOcean
|
6
|
+
#
|
7
|
+
module DoSnapshot
|
8
|
+
# Shared logger
|
9
|
+
#
|
10
|
+
class Log
|
11
|
+
class << self
|
12
|
+
attr_accessor :logger
|
13
|
+
attr_accessor :thor_log
|
14
|
+
|
15
|
+
def log(type, message)
|
16
|
+
logger.send(type, message) if logger
|
17
|
+
end
|
18
|
+
|
19
|
+
def info(message)
|
20
|
+
log :info, message
|
21
|
+
say message, :green
|
22
|
+
end
|
23
|
+
|
24
|
+
def warning(message)
|
25
|
+
log :warn, message
|
26
|
+
say message, :yellow
|
27
|
+
end
|
28
|
+
|
29
|
+
def error(message)
|
30
|
+
log :error, message
|
31
|
+
say message, :red
|
32
|
+
end
|
33
|
+
|
34
|
+
def debug(message)
|
35
|
+
log :debug, message
|
36
|
+
say message, :white if logger && logger.level == Logger::DEBUG
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def say(message, color)
|
42
|
+
thor_log.say message, color if thor_log
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'do_snapshot'
|
2
|
+
require 'do_snapshot/command'
|
3
|
+
require 'thor'
|
4
|
+
|
5
|
+
module DoSnapshot
|
6
|
+
# CLI is here
|
7
|
+
#
|
8
|
+
class CLI < Thor
|
9
|
+
default_task :create
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
if options.include? 'log'
|
14
|
+
Log.logger = Logger.new(options['log'])
|
15
|
+
Log.thor_log = Thor::Shell::Color.new
|
16
|
+
Log.logger.level = options.include?('trace') ? Logger::DEBUG : Logger::INFO
|
17
|
+
end
|
18
|
+
try_keys_first
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'create', 'create and cleanup snapshot\'s'
|
22
|
+
long_desc <<-LONGDESC
|
23
|
+
`do_snapshot create` will create and cleanup snapshots on your droplets.
|
24
|
+
|
25
|
+
You can optionally specify parameters to select or exclude some droplets.
|
26
|
+
|
27
|
+
Advanced options example for MAIL feature:
|
28
|
+
|
29
|
+
--mail to:mail@somehost.com from:from@host.com --smtp address:smtp.gmail.com user_name:someuser password:somepassword
|
30
|
+
|
31
|
+
For more details look here: https://github.com/benprew/pony
|
32
|
+
|
33
|
+
Example:
|
34
|
+
|
35
|
+
> $ do_snapshot --keep 5
|
36
|
+
|
37
|
+
> $ do_snapshot --only 123456 1234567 --store 3
|
38
|
+
|
39
|
+
> $ do_snapshot --exclude 123456 123457
|
40
|
+
|
41
|
+
> $ do_snapshot --keep 10 --stop true --mail to:yourmail@example.com
|
42
|
+
LONGDESC
|
43
|
+
option :only, type: :array, default: [], aliases: ['-o'], banner: '123456 123456 123456', desc: 'Use only selected droplets.'
|
44
|
+
option :exclude, type: :array, default: [], aliases: ['-e'], banner: '123456 123456 123456', desc: 'Except some droplets.'
|
45
|
+
option :keep, type: :numeric, default: 10, aliases: ['-k'], banner: '5', desc: 'How much snapshots you want to keep?'
|
46
|
+
option :stop, type: :boolean, aliases: ['-s'], banner: 'true', desc: 'Stop creating snapshots if maximum is reached.'
|
47
|
+
option :mail, type: :hash, default: {}, aliases: ['-m'], banner: 'to:yourmail@example.com', desc: 'Receive mail if maximum is reached.'
|
48
|
+
option :smtp, type: :hash, default: {}, aliases: ['-t'], banner: 'user_name:yourmail@example.com password:password', desc: 'SMTP options.'
|
49
|
+
option :log, type: :string, aliases: ['-l'], banner: '/Users/someone/.do_snapshot/main.log', desc: 'Log file path. By default logging is disabled.'
|
50
|
+
option :trace, type: :boolean, aliases: ['-d'], desc: 'Debug mode. Not implented now. Switched only log mode.'
|
51
|
+
def create
|
52
|
+
DoSnapshot::Command.execute options, %w( log trace )
|
53
|
+
rescue => e
|
54
|
+
Log.error e.message
|
55
|
+
backtrace(e) if options.include? 'trace'
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def backtrace(e)
|
61
|
+
e.backtrace.each do |t|
|
62
|
+
Log.error t
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Check DigitalOcean API keys
|
67
|
+
def try_keys_first
|
68
|
+
Log.debug 'Checking DigitalOcean Id\'s.'
|
69
|
+
fail Thor::Error, 'You must have DIGITAL_OCEAN_CLIENT_ID in environment.' if !ENV['DIGITAL_OCEAN_CLIENT_ID'] || ENV['DIGITAL_OCEAN_CLIENT_ID'].empty?
|
70
|
+
fail Thor::Error, 'You must have DIGITAL_OCEAN_API_KEY in environment.' if !ENV['DIGITAL_OCEAN_API_KEY'] || ENV['DIGITAL_OCEAN_API_KEY'].empty?
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'digitalocean'
|
2
|
+
require 'date'
|
3
|
+
require 'pony'
|
4
|
+
require 'core_ext/hash'
|
5
|
+
|
6
|
+
module DoSnapshot
|
7
|
+
# Our commands live here :)
|
8
|
+
#
|
9
|
+
class Command
|
10
|
+
class << self
|
11
|
+
def execute(options, skip)
|
12
|
+
return unless options
|
13
|
+
|
14
|
+
options.each_pair do |key, option|
|
15
|
+
send("#{key}=", option) unless skip.include? key
|
16
|
+
end
|
17
|
+
|
18
|
+
self.notify = false
|
19
|
+
|
20
|
+
work_droplets
|
21
|
+
email_message if notify && mail
|
22
|
+
|
23
|
+
Log.info 'All snapshots requested'
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
attr_accessor :droplets
|
29
|
+
attr_accessor :exclude
|
30
|
+
attr_accessor :only
|
31
|
+
attr_accessor :keep
|
32
|
+
attr_accessor :mail
|
33
|
+
attr_accessor :smtp
|
34
|
+
attr_accessor :stop
|
35
|
+
attr_accessor :notify
|
36
|
+
|
37
|
+
# Getting droplets list from API.
|
38
|
+
# And store into object.
|
39
|
+
#
|
40
|
+
def load_droplets
|
41
|
+
set_id
|
42
|
+
Log.debug 'Loading list of DigitalOcean droplets'
|
43
|
+
droplets = Digitalocean::Droplet.all
|
44
|
+
fail droplets.message unless droplets.status == 'OK'
|
45
|
+
self.droplets = droplets.droplets
|
46
|
+
end
|
47
|
+
|
48
|
+
# Working with received list of droplets.
|
49
|
+
#
|
50
|
+
def work_droplets
|
51
|
+
load_droplets
|
52
|
+
Log.debug 'Working with list of DigitalOcean droplets'
|
53
|
+
droplets.each do |droplet|
|
54
|
+
id = droplet.id.to_s
|
55
|
+
next if exclude.include? id
|
56
|
+
next if !only.empty? && !only.include?(id)
|
57
|
+
|
58
|
+
instance = Digitalocean::Droplet.find(id)
|
59
|
+
fail instance.message unless instance.status == 'OK'
|
60
|
+
|
61
|
+
prepare_instance instance.droplet
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Preparing instance to take snapshot.
|
66
|
+
# Instance must be powered off first!
|
67
|
+
#
|
68
|
+
def prepare_instance(instance)
|
69
|
+
return unless instance
|
70
|
+
Log.debug "Preparing droplet id: #{instance.id} name: #{instance.name} to snapshot."
|
71
|
+
|
72
|
+
warning_size = "For droplet with id: #{instance.id} and name: #{instance.name} the maximum #{keep} is reached."
|
73
|
+
|
74
|
+
if instance.snapshots.size >= keep && stop
|
75
|
+
Log.warning warning_size
|
76
|
+
self.notify = true
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
# Stopping instance.
|
81
|
+
Log.debug 'Shutting down droplet.'
|
82
|
+
unless instance.status.include? 'off'
|
83
|
+
event = Digitalocean::Droplet.power_off(instance.id)
|
84
|
+
if event.status.include? 'OK'
|
85
|
+
sleep 1.3 until get_event_status(event.event_id)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Create snapshot.
|
90
|
+
create_snapshot instance, warning_size
|
91
|
+
end
|
92
|
+
|
93
|
+
# Trying to create a snapshot.
|
94
|
+
#
|
95
|
+
def create_snapshot(instance, warning_size)
|
96
|
+
Log.debug "Start creating snapshot for droplet id: #{instance.id} name: #{instance.name}."
|
97
|
+
|
98
|
+
today = DateTime.now
|
99
|
+
name = "#{instance.name}_#{today.strftime('%Y_%m_%d')}"
|
100
|
+
event = Digitalocean::Droplet.snapshot(instance.id, name: name)
|
101
|
+
snapshot_size = instance.snapshots.size
|
102
|
+
|
103
|
+
if !event
|
104
|
+
fail 'Something wrong with DigitalOcean or with your connection :)'
|
105
|
+
elsif event && !event.status.include?('OK')
|
106
|
+
fail event.message
|
107
|
+
end
|
108
|
+
|
109
|
+
Log.debug 'Wait until snapshot will be created.'
|
110
|
+
|
111
|
+
sleep 10 until get_event_status(event.event_id)
|
112
|
+
|
113
|
+
snapshot_size += 1
|
114
|
+
|
115
|
+
Log.info "Snapshot name: #{name} created successfully."
|
116
|
+
Log.info "Droplet id: #{instance.id} name: #{instance.name} snapshots: #{snapshot_size}."
|
117
|
+
|
118
|
+
if snapshot_size > keep
|
119
|
+
Log.warning warning_size if snapshot_size > keep
|
120
|
+
self.notify = true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Looking for event status.
|
125
|
+
#
|
126
|
+
# Before snapshot we to know that machine has powered off.
|
127
|
+
#
|
128
|
+
def get_event_status(id)
|
129
|
+
event = Digitalocean::Event.find(id)
|
130
|
+
fail event.message unless event.status.include?('OK')
|
131
|
+
event.event.percentage && event.event.percentage.include?('100') ? true : false
|
132
|
+
end
|
133
|
+
|
134
|
+
# Sending message via Hash params.
|
135
|
+
#
|
136
|
+
# Options:: -m to:mail@somehost.com from:from@host.com -t address:smtp.gmail.com user_name:someuser password:somepassword
|
137
|
+
#
|
138
|
+
def email_message
|
139
|
+
mail.symbolize_keys!
|
140
|
+
smtp.symbolize_keys!
|
141
|
+
|
142
|
+
mail[:subject] = 'DigitalOcean Snapshot maximum is reached.' unless mail[:subject]
|
143
|
+
mail[:body] = "Please cleanup your Digital Ocean account. \nSnapshot maximum is reached." unless mail[:body]
|
144
|
+
mail[:from] = 'noreply@someonelse.com' unless mail[:from]
|
145
|
+
mail[:via] = :smtp unless mail[:via]
|
146
|
+
|
147
|
+
smtp[:domain] = 'localhost.localdomain' unless smtp[:domain]
|
148
|
+
smtp[:port] = '25' unless smtp[:port]
|
149
|
+
|
150
|
+
mail[:via_options] = smtp
|
151
|
+
|
152
|
+
Log.debug 'Sending e-mail notification.'
|
153
|
+
# Look into your inbox :)
|
154
|
+
Pony.mail(mail)
|
155
|
+
end
|
156
|
+
|
157
|
+
# Set id's of Digital Ocean API.
|
158
|
+
#
|
159
|
+
def set_id
|
160
|
+
Log.debug 'Setting DigitalOcean Id\'s.'
|
161
|
+
Digitalocean.client_id = ENV['DIGITAL_OCEAN_CLIENT_ID']
|
162
|
+
Digitalocean.api_key = ENV['DIGITAL_OCEAN_API_KEY']
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Rails symbolize keys methods for Hash
|
2
|
+
#
|
3
|
+
class Hash
|
4
|
+
# Returns a new hash with all keys converted using the block operation.
|
5
|
+
#
|
6
|
+
# hash = { name: 'Rob', age: '28' }
|
7
|
+
#
|
8
|
+
# hash.transform_keys{ |key| key.to_s.upcase }
|
9
|
+
# # => {"NAME"=>"Rob", "AGE"=>"28"}
|
10
|
+
def transform_keys
|
11
|
+
result = {}
|
12
|
+
each_key do |key|
|
13
|
+
result[yield(key)] = self[key]
|
14
|
+
end
|
15
|
+
result
|
16
|
+
end
|
17
|
+
|
18
|
+
# Destructively convert all keys using the block operations.
|
19
|
+
# Same as transform_keys but modifies +self+.
|
20
|
+
def transform_keys!
|
21
|
+
keys.each do |key|
|
22
|
+
self[yield(key)] = delete(key)
|
23
|
+
end
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
def symbolize_keys
|
28
|
+
transform_keys { |key| key.to_sym rescue key }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Destructively convert all keys to symbols, as long as they respond
|
32
|
+
# to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
|
33
|
+
def symbolize_keys!
|
34
|
+
transform_keys! { |key| key.to_sym rescue key }
|
35
|
+
end
|
36
|
+
end
|
data/test/.keep
ADDED
File without changes
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: do_snapshot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Alexander Merkulov
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-07-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: digitalocean
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: thor
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pony
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.6'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.6'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Snapshot runner for Digital Ocean droplets. Use it with Cron or other
|
84
|
+
tools.
|
85
|
+
email:
|
86
|
+
- sasha@merqlove.ru
|
87
|
+
executables:
|
88
|
+
- do_snapshot
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rubocop.yml"
|
94
|
+
- ".ruby-version"
|
95
|
+
- Gemfile
|
96
|
+
- LICENSE.txt
|
97
|
+
- README.md
|
98
|
+
- Rakefile
|
99
|
+
- bin/do_snapshot
|
100
|
+
- do_snapshot.gemspec
|
101
|
+
- lib/do_snapshot.rb
|
102
|
+
- lib/do_snapshot/cli.rb
|
103
|
+
- lib/do_snapshot/command.rb
|
104
|
+
- lib/do_snapshot/core_ext/hash.rb
|
105
|
+
- lib/do_snapshot/version.rb
|
106
|
+
- test/.keep
|
107
|
+
homepage: http://github.com/merqlove/do_snapshot
|
108
|
+
licenses:
|
109
|
+
- MIT
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 2.2.2
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: Snapshot runner for Digital Ocean droplets. Use it with Cron or other tools.
|
131
|
+
test_files:
|
132
|
+
- test/.keep
|