loe-super-ebs-pruner-9000 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/bin/pruner +47 -0
- data/lib/pruner.rb +102 -0
- data/lib/pruner/silence_ssl_warning.rb +8 -0
- data/lib/pruner/version.rb +3 -0
- data/super-ebs-pruner-9000.gemspec +46 -0
- data/test/test_pruner.rb +205 -0
- metadata +71 -0
data/.gitignore
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gemspec|
|
6
|
+
gemspec.name = "super-ebs-pruner-9000"
|
7
|
+
gemspec.summary = "Thins EBS volume snapshots."
|
8
|
+
gemspec.description = "Thins EBS volume snapshots."
|
9
|
+
gemspec.email = "andrew@andrewloe.com"
|
10
|
+
gemspec.homepage = "http://github.com/loe/super-ebs-pruner-9000"
|
11
|
+
gemspec.authors = ["W. Andrew Loe III"]
|
12
|
+
gemspec.add_dependency('right_aws', '>=1.10.0')
|
13
|
+
end
|
14
|
+
rescue LoadError
|
15
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
16
|
+
end
|
17
|
+
|
18
|
+
task :default => :test
|
19
|
+
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.test_files = FileList.new('test/**/test_*.rb') do |list|
|
22
|
+
list.exclude 'test/test_helper.rb'
|
23
|
+
end
|
24
|
+
test.libs << 'test'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/bin/pruner
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'optparse'
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/pruner')
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = 'Usage: pruner [options] vol-1 vol-2... providing no volumes will default to all volumes associated with the account.'
|
9
|
+
|
10
|
+
opts.on('-i', '--aws-id ID', 'AWS ID') do |id|
|
11
|
+
options[:aws_id] = id
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on('-k', '--aws-key KEY', 'AWS Secret Key') do |key|
|
15
|
+
options[:aws_key] = key
|
16
|
+
end
|
17
|
+
|
18
|
+
options[:verbose] = true
|
19
|
+
opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
|
20
|
+
options[:verbose] = v
|
21
|
+
end
|
22
|
+
|
23
|
+
options[:live] = false
|
24
|
+
opts.on('-l', '--[no-]live', 'Run live') do |l|
|
25
|
+
options[:live] = l
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
29
|
+
puts "Super Pruner 9000 - #{Pruner::VERSION}"
|
30
|
+
puts opts
|
31
|
+
exit
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
opts.parse!
|
36
|
+
|
37
|
+
raise 'You must provide AWS credentials.' unless options[:aws_id] && options[:aws_key]
|
38
|
+
rescue Exception => e
|
39
|
+
print "ERROR: #{e}\n\n"
|
40
|
+
puts opts
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
options[:volumes] = ARGV
|
46
|
+
|
47
|
+
Pruner.new(options).prune!
|
data/lib/pruner.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'right_aws'
|
2
|
+
require 'activesupport'
|
3
|
+
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/pruner/version')
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/pruner/silence_ssl_warning')
|
6
|
+
|
7
|
+
class Pruner
|
8
|
+
attr_reader :options
|
9
|
+
attr_accessor :ec2, :volumes, :all_snapshots, :old_snapshots
|
10
|
+
|
11
|
+
NOW = Time.now
|
12
|
+
|
13
|
+
HOURLY_AFTER_A_DAY = {:after => NOW - 1.week,
|
14
|
+
:before => NOW - 1.day,
|
15
|
+
:interval => 1.hour,
|
16
|
+
:name => 'Hourly After A Day'}
|
17
|
+
DAILY_AFTER_A_WEEK = {:after => NOW - 1.month,
|
18
|
+
:before => NOW - 1.week,
|
19
|
+
:interval => 24.hours,
|
20
|
+
:name => 'Daily After A Week'}
|
21
|
+
EVERY_OTHER_DAY_AFTER_A_MONTH = {:after => NOW - 3.month,
|
22
|
+
:before => NOW - 1.month,
|
23
|
+
:interval => 48.hours,
|
24
|
+
:name => 'Every Other Day After A Month'}
|
25
|
+
WEEKLY_AFTER_A_QUARTER = {:after => NOW - 2.years,
|
26
|
+
:before => NOW - 3.months,
|
27
|
+
:interval => 1.week,
|
28
|
+
:name => 'Weekly After A Quarter'}
|
29
|
+
EVERY_THREE_WEEKS_AFTER_TWO_YEARS = {:after => NOW - 10.years,
|
30
|
+
:before => NOW - 2.years,
|
31
|
+
:interval => 3.weeks,
|
32
|
+
:name => 'Every Three Weeks After Two Years'}
|
33
|
+
|
34
|
+
RULES = [HOURLY_AFTER_A_DAY, DAILY_AFTER_A_WEEK, EVERY_OTHER_DAY_AFTER_A_MONTH, WEEKLY_AFTER_A_QUARTER, EVERY_THREE_WEEKS_AFTER_TWO_YEARS]
|
35
|
+
|
36
|
+
def initialize(options ={})
|
37
|
+
@options = options
|
38
|
+
@old_snapshots = []
|
39
|
+
end
|
40
|
+
|
41
|
+
def prune!
|
42
|
+
apply_rules
|
43
|
+
remove_snapshots
|
44
|
+
end
|
45
|
+
|
46
|
+
def apply_rules
|
47
|
+
RULES.each do |rule|
|
48
|
+
cached_size = old_snapshots.size if options[:verbose]
|
49
|
+
apply_rule(rule)
|
50
|
+
puts "#{rule[:name]}: #{old_snapshots.size - cached_size}" if options[:verbose]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def apply_rule(rule)
|
55
|
+
volumes.each do |volume|
|
56
|
+
|
57
|
+
# Gather the snapshots that might fall in the rule's time window.
|
58
|
+
vulnerable_snaps = snapshots(volume).select { |snap| snap[:aws_started_at] > rule[:after] && snap[:aws_started_at] < rule[:before]}
|
59
|
+
|
60
|
+
# Step across the rule's time window one interval at a time, keeping the last snapshot in that window.
|
61
|
+
window_start = rule[:before] - rule[:interval]
|
62
|
+
while window_start > rule[:after] do
|
63
|
+
# Gather snaps in the window
|
64
|
+
snaps_in_window = vulnerable_snaps.select { |snap| snap[:aws_started_at] >= window_start && snap[:aws_started_at] < window_start + rule[:interval]}
|
65
|
+
# The first one in the selection survives
|
66
|
+
keeper = snaps_in_window.pop
|
67
|
+
# Send the rest to die.
|
68
|
+
@old_snapshots += snaps_in_window
|
69
|
+
# Shrink the window
|
70
|
+
window_start -= rule[:interval]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
old_snapshots
|
75
|
+
end
|
76
|
+
|
77
|
+
def remove_snapshots
|
78
|
+
puts "Removing #{old_snapshots.size} Snapshots:" if options[:verbose]
|
79
|
+
old_snapshots.each do |snap|
|
80
|
+
puts " #{snap[:aws_id]} - #{snap[:aws_started_at]} (#{snap[:aws_volume_id]})" if options[:verbose]
|
81
|
+
ec2.delete_snapshot(snap[:aws_id]) if options[:live]
|
82
|
+
end
|
83
|
+
|
84
|
+
old_snapshots
|
85
|
+
end
|
86
|
+
|
87
|
+
def ec2
|
88
|
+
@ec2 ||= RightAws::Ec2.new(options[:aws_id], options[:aws_key])
|
89
|
+
end
|
90
|
+
|
91
|
+
def volumes
|
92
|
+
@volumes ||= options[:volumes].empty? ? ec2.describe_volumes.map {|vol| vol[:aws_id] } : options[:volumes]
|
93
|
+
end
|
94
|
+
|
95
|
+
def all_snapshots
|
96
|
+
@all_snapshots ||= ec2.describe_snapshots
|
97
|
+
end
|
98
|
+
|
99
|
+
def snapshots(volume)
|
100
|
+
all_snapshots.select { |snap| volume == snap[:aws_volume_id] }
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{super-ebs-pruner-9000}
|
5
|
+
s.version = "1.0.0"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["W. Andrew Loe III"]
|
9
|
+
s.date = %q{2009-07-24}
|
10
|
+
s.default_executable = %q{pruner}
|
11
|
+
s.description = %q{Thins EBS volume snapshots.}
|
12
|
+
s.email = %q{andrew@andrewloe.com}
|
13
|
+
s.executables = ["pruner"]
|
14
|
+
s.files = [
|
15
|
+
".gitignore",
|
16
|
+
"Rakefile",
|
17
|
+
"VERSION",
|
18
|
+
"bin/pruner",
|
19
|
+
"lib/pruner.rb",
|
20
|
+
"lib/pruner/silence_ssl_warning.rb",
|
21
|
+
"lib/pruner/version.rb",
|
22
|
+
"super-ebs-pruner-9000.gemspec",
|
23
|
+
"test/test_pruner.rb"
|
24
|
+
]
|
25
|
+
s.homepage = %q{http://github.com/loe/super-ebs-pruner-9000}
|
26
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
s.rubygems_version = %q{1.3.4}
|
29
|
+
s.summary = %q{Thins EBS volume snapshots.}
|
30
|
+
s.test_files = [
|
31
|
+
"test/test_pruner.rb"
|
32
|
+
]
|
33
|
+
|
34
|
+
if s.respond_to? :specification_version then
|
35
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
36
|
+
s.specification_version = 3
|
37
|
+
|
38
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
39
|
+
s.add_runtime_dependency(%q<right_aws>, ["= 1.10.0"])
|
40
|
+
else
|
41
|
+
s.add_dependency(%q<right_aws>, ["= 1.10.0"])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
s.add_dependency(%q<right_aws>, ["= 1.10.0"])
|
45
|
+
end
|
46
|
+
end
|
data/test/test_pruner.rb
ADDED
@@ -0,0 +1,205 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'mocha'
|
4
|
+
require 'pruner'
|
5
|
+
|
6
|
+
class TestPruner < Test::Unit::TestCase
|
7
|
+
|
8
|
+
NOW = Time.now
|
9
|
+
|
10
|
+
# From RightAws::Ec2#describe_instances documentation.
|
11
|
+
def volumes_array
|
12
|
+
[{:aws_id => "vol-foo"},
|
13
|
+
{:aws_id => "vol-bar"},
|
14
|
+
{:aws_id => "vol-baz"}]
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generate twice hourly for yesterday
|
18
|
+
# Should result in 24 deleted snapshots.
|
19
|
+
def twice_hourly_yesterday(vol)
|
20
|
+
yesterday = NOW - 1.day
|
21
|
+
(1..48).map do |i|
|
22
|
+
{:aws_progress => "100%",
|
23
|
+
:aws_status => "completed",
|
24
|
+
:aws_id => "snap-yesterday-#{i}-#{vol}",
|
25
|
+
:aws_volume_id => vol,
|
26
|
+
:aws_started_at => yesterday - i * 30.minutes}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Generate 2 times daily for last week.
|
31
|
+
# Should result in 7 deleted snapshots.
|
32
|
+
def twice_daily_last_week(vol)
|
33
|
+
last_week = NOW - 1.week
|
34
|
+
(1..14).map do |i|
|
35
|
+
{:aws_progress => "100%",
|
36
|
+
:aws_status => "completed",
|
37
|
+
:aws_id => "snap-last-week-#{i}-#{vol}",
|
38
|
+
:aws_volume_id => vol,
|
39
|
+
:aws_started_at => last_week - i * 12.hours}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Generate daily for last month.
|
44
|
+
# Should result in 15 deleted snapshots
|
45
|
+
def daily_last_month(vol)
|
46
|
+
last_month = NOW - 1.month
|
47
|
+
(1..30).map do |i|
|
48
|
+
{:aws_progress => "100%",
|
49
|
+
:aws_status => "completed",
|
50
|
+
:aws_id => "snap-last-month-#{i}-#{vol}",
|
51
|
+
:aws_volume_id => vol,
|
52
|
+
:aws_started_at => last_month - i * 1.day}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Generate 2 weekly for last quarter.
|
57
|
+
# Should result in 6 deleted snapshots.
|
58
|
+
def twice_weekly_last_quarter(vol)
|
59
|
+
last_quarter = NOW - 3.months
|
60
|
+
(1..12).map do |i|
|
61
|
+
{:aws_progress => "100%",
|
62
|
+
:aws_status => "completed",
|
63
|
+
:aws_id => "snap-last-quarter-#{i}-#{vol}",
|
64
|
+
:aws_volume_id => vol,
|
65
|
+
:aws_started_at => last_quarter - i * 3.days}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Generate weekly for last two years.
|
70
|
+
# Should result in 16 deleted snapshots.
|
71
|
+
def weekly_two_years_ago(vol)
|
72
|
+
two_years_ago = NOW - 2.years
|
73
|
+
(1..48).map do |i|
|
74
|
+
{:aws_progress => "100%",
|
75
|
+
:aws_status => "completed",
|
76
|
+
:aws_id => "snap-two-years-ago-#{i}-#{vol}",
|
77
|
+
:aws_volume_id => vol,
|
78
|
+
:aws_started_at => two_years_ago - i * 1.week}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Generate a set that we can prune from with known results.
|
83
|
+
# RULES = [HOURLY_AFTER_A_DAY, DAILY_AFTER_A_WEEK, EVERY_OTHER_DAY_AFTER_A_MONTH, WEEKLY_AFTER_A_QUARTER, EVERY_THREE_WEEKS_AFTER_TWO_YEARS]
|
84
|
+
def snapshots_array_foo
|
85
|
+
twice_hourly_yesterday('vol-foo') + twice_daily_last_week('vol-foo') + daily_last_month('vol-foo') + twice_weekly_last_quarter('vol-foo') + weekly_two_years_ago('vol-foo')
|
86
|
+
end
|
87
|
+
|
88
|
+
def snapshots_array_bar
|
89
|
+
twice_hourly_yesterday('vol-bar') + twice_daily_last_week('vol-bar') + daily_last_month('vol-bar') + twice_weekly_last_quarter('vol-bar') + weekly_two_years_ago('vol-bar')
|
90
|
+
end
|
91
|
+
|
92
|
+
def snapshots_array_baz
|
93
|
+
twice_hourly_yesterday('vol-baz') + twice_daily_last_week('vol-baz') + daily_last_month('vol-baz') + twice_weekly_last_quarter('vol-baz') + weekly_two_years_ago('vol-baz')
|
94
|
+
end
|
95
|
+
|
96
|
+
def mock_aws
|
97
|
+
@mock_ec2 = mock()
|
98
|
+
RightAws::Ec2.stubs(:new).returns(@mock_ec2)
|
99
|
+
end
|
100
|
+
|
101
|
+
def new_pruner
|
102
|
+
@pruner = Pruner.new({:volumes => [], :verbose => true, :live => true})
|
103
|
+
end
|
104
|
+
|
105
|
+
def setup
|
106
|
+
mock_aws
|
107
|
+
new_pruner
|
108
|
+
end
|
109
|
+
|
110
|
+
def teardown
|
111
|
+
@pruner = nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_no_window_overlap
|
115
|
+
windows = [twice_hourly_yesterday('vol-foo'), twice_daily_last_week('vol-foo'), daily_last_month('vol-foo'), twice_weekly_last_quarter('vol-foo'), weekly_two_years_ago('vol-foo')]
|
116
|
+
windows.each do |window|
|
117
|
+
assert_equal window & (windows.flatten - window), []
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_version
|
122
|
+
assert_not_nil Pruner::VERSION
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_ec2
|
126
|
+
assert_not_nil @pruner.ec2
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_volumes
|
130
|
+
@mock_ec2.expects(:describe_volumes).returns(volumes_array).once
|
131
|
+
assert_equal @pruner.volumes, ['vol-foo', 'vol-bar', 'vol-baz']
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_snapshots
|
135
|
+
@mock_ec2.expects(:describe_snapshots).returns(snapshots_array_foo).once
|
136
|
+
assert_equal @pruner.snapshots('vol-foo'), snapshots_array_foo
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_apply_rule_HOURLY_AFTER_A_DAY
|
140
|
+
@pruner.volumes = ['vol-foo']
|
141
|
+
@mock_ec2.expects(:describe_snapshots).returns(twice_hourly_yesterday('vol-foo'))
|
142
|
+
@pruner.apply_rule(Pruner::HOURLY_AFTER_A_DAY)
|
143
|
+
assert_equal @pruner.old_snapshots.size, 24
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_apply_rule_DAILY_AFTER_A_WEEK
|
147
|
+
@pruner.volumes = ['vol-foo']
|
148
|
+
@mock_ec2.expects(:describe_snapshots).returns(twice_daily_last_week('vol-foo'))
|
149
|
+
@pruner.apply_rule(Pruner::DAILY_AFTER_A_WEEK)
|
150
|
+
assert_equal @pruner.old_snapshots.size, 7
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_apply_rule_EVERY_OTHER_DAY_AFTER_A_MONTH
|
154
|
+
@pruner.volumes = ['vol-foo']
|
155
|
+
@mock_ec2.expects(:describe_snapshots).returns(daily_last_month('vol-foo'))
|
156
|
+
@pruner.apply_rule(Pruner::EVERY_OTHER_DAY_AFTER_A_MONTH)
|
157
|
+
assert_equal @pruner.old_snapshots.size, 15
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_apply_rule_WEEKLY_AFTER_A_QUARTER
|
161
|
+
@pruner.volumes = ['vol-foo']
|
162
|
+
@mock_ec2.expects(:describe_snapshots).returns(twice_weekly_last_quarter('vol-foo'))
|
163
|
+
@pruner.apply_rule(Pruner::WEEKLY_AFTER_A_QUARTER)
|
164
|
+
assert_equal @pruner.old_snapshots.size, 6
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_apply_rule_EVERY_THREE_WEEKS_AFTER_TWO_YEARS
|
168
|
+
@pruner.volumes = ['vol-foo']
|
169
|
+
@mock_ec2.expects(:describe_snapshots).returns(weekly_two_years_ago('vol-foo'))
|
170
|
+
@pruner.apply_rule(Pruner::EVERY_THREE_WEEKS_AFTER_TWO_YEARS)
|
171
|
+
assert_equal @pruner.old_snapshots.size, 32
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_apply_rules
|
175
|
+
@pruner.volumes = ['vol-foo']
|
176
|
+
@mock_ec2.expects(:describe_snapshots).returns(snapshots_array_foo)
|
177
|
+
@pruner.apply_rules
|
178
|
+
assert_equal @pruner.old_snapshots.size, 24 + 7 + 15 + 6 + 32
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_remove_snapshots
|
182
|
+
dead_snaps = 24 + 7 + 15 + 6 + 32
|
183
|
+
@pruner.volumes = ['vol-foo']
|
184
|
+
@mock_ec2.expects(:describe_snapshots).returns(snapshots_array_foo)
|
185
|
+
@mock_ec2.expects(:delete_snapshot).times(dead_snaps)
|
186
|
+
@pruner.apply_rules
|
187
|
+
@pruner.remove_snapshots
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_one_volume_prune!
|
191
|
+
dead_snaps = 24 + 7 + 15 + 6 + 32
|
192
|
+
@mock_ec2.expects(:describe_volumes).returns([{:aws_id => "vol-foo"}]).once
|
193
|
+
@mock_ec2.expects(:describe_snapshots).returns(snapshots_array_foo).once
|
194
|
+
@mock_ec2.expects(:delete_snapshot).times(dead_snaps)
|
195
|
+
@pruner.prune!
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_multiple_volumes_prune!
|
199
|
+
dead_snaps = (24 + 7 + 15 + 6 + 32) * 3 # one for each array!
|
200
|
+
@mock_ec2.expects(:describe_volumes).returns(volumes_array).once
|
201
|
+
@mock_ec2.expects(:describe_snapshots).returns(snapshots_array_foo + snapshots_array_bar + snapshots_array_baz).once
|
202
|
+
@mock_ec2.expects(:delete_snapshot).times(dead_snaps)
|
203
|
+
@pruner.prune!
|
204
|
+
end
|
205
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: loe-super-ebs-pruner-9000
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- W. Andrew Loe III
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-24 00:00:00 -07:00
|
13
|
+
default_executable: pruner
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: right_aws
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - "="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.10.0
|
24
|
+
version:
|
25
|
+
description: Thins EBS volume snapshots.
|
26
|
+
email: andrew@andrewloe.com
|
27
|
+
executables:
|
28
|
+
- pruner
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- Rakefile
|
36
|
+
- VERSION
|
37
|
+
- bin/pruner
|
38
|
+
- lib/pruner.rb
|
39
|
+
- lib/pruner/silence_ssl_warning.rb
|
40
|
+
- lib/pruner/version.rb
|
41
|
+
- super-ebs-pruner-9000.gemspec
|
42
|
+
- test/test_pruner.rb
|
43
|
+
has_rdoc: false
|
44
|
+
homepage: http://github.com/loe/super-ebs-pruner-9000
|
45
|
+
licenses:
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options:
|
48
|
+
- --charset=UTF-8
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Thins EBS volume snapshots.
|
70
|
+
test_files:
|
71
|
+
- test/test_pruner.rb
|