ebs_prune_snapshot 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ebs_prune_snapshot.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Dusty Doris
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.txt ADDED
@@ -0,0 +1,60 @@
1
+ # EbsPruneSnapshot
2
+
3
+ Manage your EBS snapshots on a daily, weekly, and monthly rotation schedule.
4
+
5
+ Features
6
+ - Keep at least one snapshot of each volume, regardless of the rotation schedule.
7
+ - Saves the youngest snapshot of a particular day as a daily snapshot.
8
+ - Saves the oldest snapshot of any week as a weekly snapshot (Sundays).
9
+ - Saves the oldest snapshot of any 4 week period as a monthly snapshot (Sunday).
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'ebs_prune_snapshot'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install ebs_prune_snapshot
24
+
25
+ ## Usage
26
+
27
+ AWS Access Key and AWS Secret Access Key are required. These options can be
28
+ provided through the command line or they may be stored in the environmental
29
+ variables of AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY. Any options
30
+ provided through the command line will override the environmental variables.
31
+
32
+ A daily, weekly, and monthly rotation are also required. The monthly rotation
33
+ is every 4 weeks, so provide 13 to go back a full year.
34
+
35
+ If you only want to see what would happen if you ran the schedule, then pass
36
+ the --dry-run (-n) argument.
37
+
38
+ Usage: ebs_prune_snapshot [options]
39
+ eg: ebs_snapshot -d 7 -w 12 -m 14
40
+
41
+ Required rotation configuration
42
+ -d, --daily DAILY Number of daily snapshots to keep
43
+ -w, --weekly WEEKLY Number of weekly snapshots to keep
44
+ -m, --monthly MONTHLY Number of monthly snapshots to keep
45
+
46
+ AWS Identifications, required unless environmental variables set
47
+ -k, --key KEY AWS Access Key (AMAZON_ACCESS_KEY_ID)
48
+ -s, --secret SECRET AWS Secret Access Key (AMAZON_SECRET_ACCESS_KEY)
49
+
50
+ Informational arguments
51
+ -n, --dry-run Describe what would be done (SAFE)
52
+ -h, --help Show Command Help
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ desc "Run tests"
5
+ task :test do
6
+ sh "bundle exec test/test_ebs_prune_snapshot.rb"
7
+ end
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+ require 'ebs_prune_snapshot'
3
+ require 'optparse'
4
+
5
+ def send_error(message)
6
+ puts @opts
7
+ puts ""
8
+ puts "ERROR: #{message}"
9
+ puts ""
10
+ exit(1)
11
+ end
12
+
13
+ @options = {}
14
+ @opts = OptionParser.new
15
+
16
+ @opts.banner = <<-EOD
17
+ EbsPruneSnapshot
18
+
19
+ Manage your EBS snapshots on a daily, weekly, and monthly rotation schedule.
20
+
21
+ AWS Access Key and AWS Secret Access Key are required. These options can be
22
+ provided through the command line or they may be stored in the environmental
23
+ variables of AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY. Any options
24
+ provided through the command line will override the environmental variables.
25
+
26
+ A daily, weekly, and monthly rotation are also required. The monthly rotation
27
+ is every 4 weeks, so provide 13 to go back a full year.
28
+
29
+ If you only want to see what would happen if you ran the schedule, then pass
30
+ the --dry-run (-n) argument.
31
+
32
+ Usage: ebs_prune_snapshot [options]
33
+ eg: ebs_snapshot -d 7 -w 12 -m 13"
34
+ EOD
35
+
36
+ @opts.separator ""
37
+ @opts.separator "Required rotation configuration"
38
+
39
+ @opts.on(
40
+ "-d", "--daily DAILY", "Number of daily snapshots to keep"
41
+ ) { |value| @options[:daily]= value }
42
+
43
+ @opts.on(
44
+ "-w", "--weekly WEEKLY", "Number of weekly snapshots to keep"
45
+ ) { |value| @options[:weekly] = value }
46
+
47
+ @opts.on(
48
+ '-m', "--monthly MONTHLY", "Number of monthly snapshots to keep"
49
+ ) { |value| @options[:monthly] = value }
50
+
51
+ @opts.separator ""
52
+ @opts.separator "AWS Identifications, required unless environmental variables set"
53
+
54
+ @opts.on(
55
+ "-k", "--key KEY", "AWS Access Key (AMAZON_ACCESS_KEY_ID)"
56
+ ) { |value| @options[:access_key] = value }
57
+
58
+ @opts.on(
59
+ "-s", "--secret SECRET", "AWS Secret Access Key (AMAZON_SECRET_ACCESS_KEY)"
60
+ ) { |value| @options[:secret_key] = value }
61
+
62
+ @opts.separator ""
63
+ @opts.separator "Informational arguments"
64
+
65
+ @opts.on(
66
+ "-n", "--dry-run", "Describe what would be done (DOES NOT delete snapshots)"
67
+ ) { |value| @options[:verbose] = true }
68
+
69
+ @opts.on_tail("-h", "--help", "Show Command Help") do
70
+ puts @opts
71
+ puts ""
72
+ exit(1)
73
+ end
74
+
75
+ begin
76
+ @opts.parse!
77
+ rescue StandardError => e
78
+ send_error e.message
79
+ end
80
+
81
+ @options[:access_key] ||= ENV['AMAZON_ACCESS_KEY_ID']
82
+ @options[:secret_key] ||= ENV['AMAZON_SECRET_ACCESS_KEY']
83
+
84
+ unless @options[:access_key] && @options[:secret_key]
85
+ send_error "Missing Arguments: --key and --secret are required
86
+ NOTE: AMAZON_ACCESS_KEY_ID and AMAZON_SECRET_ACCESS_KEY env variables are accepted"
87
+ end
88
+
89
+ unless @options[:daily] && @options[:weekly] && @options[:monthly]
90
+ send_error "Missing Arguments: --daily, --weekly and --monthly are required"
91
+ end
92
+
93
+ ebs = EbsPruneSnapshot::Base.new(
94
+ :aws => {
95
+ :access_key => @options[:access_key],
96
+ :secret_key => @options[:secret_key]
97
+ },
98
+ :rotation => {
99
+ :daily => @options[:daily].to_i,
100
+ :weekly => @options[:weekly].to_i,
101
+ :monthly => @options[:monthly].to_i
102
+ }
103
+ )
104
+
105
+ if @options[:verbose]
106
+ ebs.describe
107
+ else
108
+ ebs.prune
109
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/ebs_prune_snapshot/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Dusty Doris"]
6
+ gem.email = ["dusty@doris.name"]
7
+ gem.description = %q{Prune EBS snapshots}
8
+ gem.summary = %q{Prune EBS snapshots on a daily, weekly, and monthly rotation}
9
+ gem.homepage = "https://github.com/dusty/ebs_prune_snapshot"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "ebs_prune_snapshot"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = EbsPruneSnapshot::VERSION
17
+
18
+ gem.add_runtime_dependency('amazon-ec2')
19
+ end
@@ -0,0 +1,249 @@
1
+ require "ebs_prune_snapshot/version"
2
+ require 'AWS'
3
+
4
+ module EbsPruneSnapshot
5
+ class Base
6
+
7
+ attr_reader :rotation, :aws
8
+
9
+ def initialize(args={})
10
+ @aws = Aws.new(args[:aws])
11
+ @rotation = Rotation.new(args[:rotation])
12
+ end
13
+
14
+ def volumes
15
+ @volumes ||= begin
16
+ volumes = {}
17
+ aws.snapshots.each do |snapshot|
18
+ _snapshot = Snapshot.new(snapshot)
19
+ volumes[_snapshot.volume_id] ||= []
20
+ volumes[_snapshot.volume_id].push(_snapshot)
21
+ end
22
+ volumes
23
+ end
24
+ end
25
+
26
+ def volume(volume_id)
27
+ volumes[volume_id]
28
+ end
29
+
30
+ def describe
31
+ puts rotation
32
+ volumes.keys.each { |volume_id| describe_volume(volume_id) }
33
+ end
34
+
35
+ def prune
36
+ volumes.keys.each { |volume_id| prune_volume(volume_id) }
37
+ end
38
+
39
+ def describe_volume(volume_id)
40
+ analyzer = SnapshotAnalyzer.new(volume(volume_id), rotation)
41
+ puts "VOLUME: #{volume_id}"
42
+ analyzer.to_skip.each {|snapshot| puts " SKIP: #{snapshot.snapshot_id} : #{snapshot.date}"}
43
+ analyzer.to_save.each {|snapshot| puts " KEEP: #{snapshot.snapshot_id} : #{snapshot.date}"}
44
+ analyzer.to_delete.each {|snapshot| puts " DELE: #{snapshot.snapshot_id} : #{snapshot.date}"}
45
+ end
46
+
47
+ def prune_volume(volume_id)
48
+ analyzer = SnapshotAnalyzer.new(volume(volume_id), rotation)
49
+ analyzer.to_delete.each { |snapshot| aws.delete(snapshot) }
50
+ end
51
+
52
+ end
53
+
54
+
55
+ class Aws
56
+
57
+ attr_reader :access_key, :secret_key
58
+
59
+ def initialize(args={})
60
+ args ||= {}
61
+ @access_key = args[:access_key] || ENV['AMAZON_ACCESS_KEY_ID']
62
+ @secret_key = args[:secret_key] || ENV['AMAZON_SECRET_ACCESS_KEY']
63
+ end
64
+
65
+ def connection
66
+ @aws ||= ::AWS::EC2::Base.new(
67
+ :access_key_id => access_key, :secret_access_key => secret_key
68
+ )
69
+ end
70
+
71
+ def snapshots
72
+ snapshots = connection.describe_snapshots(:owner => 'self')['snapshotSet']
73
+ snapshots ? snapshots["item"] : []
74
+ end
75
+
76
+ def delete(snapshot)
77
+ connection.delete_snapshot(:snapshot_id => snapshot.snapshot_id)
78
+ end
79
+
80
+ end
81
+
82
+ class SnapshotAnalyzer
83
+
84
+ attr_reader :snapshots, :rotation, :to_skip
85
+
86
+ def initialize(snapshots, rotation)
87
+ @snapshots = snapshots.sort
88
+ @rotation = rotation
89
+ @to_skip = []
90
+ @to_delete = []
91
+ @to_save = {}
92
+ analyze_snapshots
93
+ end
94
+
95
+ def to_save
96
+ @to_save.empty? ? [snapshots[-1]] : @to_save.values
97
+ end
98
+
99
+ def to_delete
100
+ snapshots - to_save - to_skip
101
+ end
102
+
103
+ def now
104
+ @now ||= Time.now.utc
105
+ end
106
+
107
+ protected
108
+
109
+ def save_newest_snapshot(snapshot, day)
110
+ @to_save[day_key(day)] = snapshot
111
+ end
112
+
113
+ def save_oldest_snapshot(snapshot, day)
114
+ @to_save[day_key(day)] ||= snapshot
115
+ end
116
+
117
+ def skip_snapshot(snapshot)
118
+ @to_skip.push(snapshot) unless @to_skip.include?(snapshot)
119
+ end
120
+
121
+ def analyze_snapshots
122
+ snapshots.each do |snapshot|
123
+ if snapshot.completed?
124
+ prune_daily(snapshot) || prune_weekly(snapshot) || prune_monthly(snapshot)
125
+ else
126
+ skip_snapshot(snapshot)
127
+ end
128
+ end
129
+ to_save.sort!
130
+ to_skip.sort!
131
+ to_delete.sort!
132
+ end
133
+
134
+ ## Save newest snapshot on a day
135
+ def prune_daily(snapshot)
136
+ catch :found do
137
+ (0..rotation.daily - 1).each do |count|
138
+ day = in_days(count)
139
+ if day_key(snapshot.created_at) == day_key(day)
140
+ save_newest_snapshot(snapshot, day)
141
+ throw :found, true
142
+ end
143
+ end
144
+ false
145
+ end
146
+ end
147
+
148
+ ## Save oldest snapshot on a week
149
+ def prune_weekly(snapshot)
150
+ catch :found do
151
+ (0..rotation.weekly - 1).each do |count|
152
+ week_beg = beginning_of_week(in_weeks(count))
153
+ week_end = end_of_week(in_weeks(count))
154
+ if snapshot.created_at >= week_beg && snapshot.created_at <= week_end
155
+ save_oldest_snapshot(snapshot, week_beg)
156
+ throw :found, true
157
+ end
158
+ end
159
+ false
160
+ end
161
+ end
162
+
163
+ ## Save oldest snapshot of every 4 weeks
164
+ def prune_monthly(snapshot)
165
+ catch :found do
166
+ (0..rotation.monthly - 1).each do |count|
167
+ month_beg = beginning_of_week(in_months(count))
168
+ month_end = end_of_week(in_months(count))
169
+ if snapshot.created_at >= month_beg && snapshot.created_at <= month_end
170
+ save_oldest_snapshot(snapshot, month_beg)
171
+ throw :found, true
172
+ end
173
+ end
174
+ false
175
+ end
176
+ end
177
+
178
+ def in_months(months)
179
+ in_weeks(months * 4)
180
+ end
181
+
182
+ def in_weeks(weeks)
183
+ in_days(weeks * 7)
184
+ end
185
+
186
+ def in_days(days)
187
+ now - (86400 * days)
188
+ end
189
+
190
+ def beginning_of_week(date)
191
+ days_from_sunday = date.wday
192
+ bow = (date - (86400 * days_from_sunday))
193
+ Time.utc(bow.year, bow.month, bow.day, 0, 0, 0)
194
+ end
195
+
196
+ def end_of_week(date)
197
+ days_till_saturday = (6 - date.wday)
198
+ eow = (date + (86400 * days_till_saturday))
199
+ Time.utc(eow.year, eow.month, eow.day, 23, 59, 59)
200
+ end
201
+
202
+ def day_key(day)
203
+ day.strftime("%Y%m%d")
204
+ end
205
+
206
+ end
207
+
208
+ class Snapshot
209
+
210
+ attr_reader :snapshot_id, :volume_id, :status, :created_at
211
+
212
+ def initialize(params={})
213
+ @snapshot_id = params['snapshotId']
214
+ @volume_id = params['volumeId']
215
+ @status = params['status']
216
+ @created_at = Time.parse(params['startTime']).utc
217
+ end
218
+
219
+ def completed?
220
+ status == 'completed'
221
+ end
222
+
223
+ def <=>(other)
224
+ created_at <=> other.created_at
225
+ end
226
+
227
+ def date
228
+ created_at.strftime("%Y%m%d")
229
+ end
230
+
231
+ end
232
+
233
+ class Rotation
234
+
235
+ attr_reader :daily, :weekly, :monthly
236
+
237
+ def initialize(args={})
238
+ @daily = args[:daily] ? args[:daily].to_i : 7
239
+ @weekly = args[:weekly] ? args[:weekly].to_i : 12
240
+ @monthly = args[:monthly] ? args[:monthly].to_i : 14
241
+ end
242
+
243
+ def to_s
244
+ "Rotation: Daily #{daily}, Weekly #{weekly}, Monthly #{monthly}"
245
+ end
246
+
247
+ end
248
+
249
+ end
@@ -0,0 +1,3 @@
1
+ module EbsPruneSnapshot
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #require 'time'
4
+ require 'ebs_prune_snapshot'
5
+ require 'minitest/autorun'
6
+
7
+ ##
8
+ # Generates snapshots that simulate amazon-ec describe snapshots
9
+ # - 400 daily completed snapshots for 2 different volumes
10
+ # - 1 daily pending snapshot for 2 volumes
11
+ # - 1 really old single snapshot for a 3rd volume
12
+ module EbsPruneSnapshot
13
+ class Tester
14
+
15
+ def self.snapshots
16
+ @snapshots ||= new.snapshots
17
+ end
18
+
19
+ def self.now
20
+ Time.utc(2012,5,1)
21
+ end
22
+
23
+ def generate_snapshot(snapshot_id, volume_id, start_time)
24
+ {
25
+ "snapshotId" => snapshot_id,
26
+ "volumeId" => volume_id,
27
+ "status" => 'completed',
28
+ "startTime" => start_time.xmlschema,
29
+ "progress" => '100%',
30
+ "ownerId" => '00000000',
31
+ "volumeSize" => '1',
32
+ "description" => "test #{snapshot_id}"
33
+ }
34
+ end
35
+
36
+ def initialize
37
+ @volumes = ['vol-000000', 'vol-000001']
38
+ @now = Tester.now
39
+ @days = 400
40
+ end
41
+
42
+ def snapshots
43
+ @items ||= begin
44
+ items = []
45
+ count = 0
46
+ # generate snapshots for each day for the previous 400 days for each volume
47
+ @volumes[0..1].each do |volume_id|
48
+ (0..@days - 1).each do |day|
49
+ snapshot_id = "%06d" % count
50
+ start_time = @now - (86400 * day)
51
+ items << generate_snapshot(snapshot_id, volume_id, start_time)
52
+ count += 1
53
+ end
54
+ end
55
+ # add pending snapshots
56
+ items << generate_snapshot("111111", @volumes[0], @now - 86400).update("status" => "pending")
57
+ items << generate_snapshot("222222", @volumes[1], @now - 86400).update("status" => "pending")
58
+
59
+ # add 2 really old snapshots under another volume
60
+ items << generate_snapshot("333333", @volumes[3], @now - 86400 * 7 * 60)
61
+ items << generate_snapshot("444444", @volumes[3], @now - 86400 * 7 * 90)
62
+ end
63
+ end
64
+
65
+ # Starting on 5/1/12, assuming a snapshot taken every day, with a 7/12/13 rotation
66
+ def self.expectations
67
+ day = [
68
+ Time.utc(2012,5,1), Time.utc(2012,4,30), Time.utc(2012,4,29), Time.utc(2012,4,28), Time.utc(2012,4,27),
69
+ Time.utc(2012,4,26), Time.utc(2012,4,25)
70
+ ]
71
+ week = [
72
+ Time.utc(2012,4,29), Time.utc(2012,4,22), Time.utc(2012,4,15), Time.utc(2012,4,8), Time.utc(2012,4,1),
73
+ Time.utc(2012,3,25), Time.utc(2012,3,18), Time.utc(2012,3,11), Time.utc(2012,3,4), Time.utc(2012,2,26),
74
+ Time.utc(2012,2,19), Time.utc(2012,2,12)
75
+ ]
76
+ month = [
77
+ Time.utc(2012,4,29), Time.utc(2012,4,1), Time.utc(2012,3,4), Time.utc(2012,2,5), Time.utc(2012,1,8),
78
+ Time.utc(2011,12,11), Time.utc(2011,11,13), Time.utc(2011,10,16), Time.utc(2011,9,18), Time.utc(2011,8,21),
79
+ Time.utc(2011,7,24), Time.utc(2011,6,26), Time.utc(2011,5,29), Time.utc(2011,5,1)
80
+ ]
81
+ (day + week + month).uniq.sort
82
+ end
83
+ end
84
+ end
85
+
86
+ ##
87
+ # Stub snapshots
88
+ class EbsPruneSnapshot::Aws
89
+ def snapshots
90
+ EbsPruneSnapshot::Tester.snapshots
91
+ end
92
+ def delete(snapshot)
93
+ puts "running delete on #{snapshot.snapshot_id}"
94
+ end
95
+ end
96
+ class EbsPruneSnapshot::SnapshotAnalyzer
97
+ def now
98
+ EbsPruneSnapshot::Tester.now
99
+ end
100
+ end
101
+
102
+
103
+ class TestEbsPruneSnapshot < MiniTest::Unit::TestCase
104
+ def self.ebs
105
+ @ebs ||= EbsPruneSnapshot::Base.new(:rotation => {:daily => 7, :weekly => 12, :monthly => 14})
106
+ end
107
+
108
+ def setup
109
+ @ebs = self.class.ebs
110
+ end
111
+
112
+ def self.now
113
+ Time.utc(2012,5,1)
114
+ end
115
+
116
+ def in_days(days)
117
+ self.class.now - (86400 * days)
118
+ end
119
+
120
+ def test_sort_by_volume
121
+ assert_equal self.class.ebs.volumes.count, 3
122
+ end
123
+
124
+ def test_volume_analyzer
125
+ vol1 = @ebs.volumes[@ebs.volumes.keys[0]]
126
+ vol2 = @ebs.volumes[@ebs.volumes.keys[1]]
127
+ [vol1, vol2].each do |snapshots|
128
+ analyzer = EbsPruneSnapshot::SnapshotAnalyzer.new(snapshots, @ebs.rotation)
129
+ assert_equal analyzer.to_save.count, 29
130
+ assert_equal analyzer.to_skip.count, 1
131
+ assert_equal analyzer.to_delete.count, 371
132
+ end
133
+ end
134
+
135
+ def test_safety_mechanism
136
+ snapshots = @ebs.volumes[@ebs.volumes.keys[2]]
137
+ analyzer = EbsPruneSnapshot::SnapshotAnalyzer.new(snapshots, @ebs.rotation)
138
+ assert_equal analyzer.to_save.count, 1
139
+ assert_equal analyzer.to_skip.count, 0
140
+ assert_equal analyzer.to_delete.count, 1
141
+ assert_equal analyzer.to_save.first.snapshot_id, "333333"
142
+ end
143
+
144
+ def test_actual_expected_dates
145
+ vol1 = @ebs.volumes[@ebs.volumes.keys[0]]
146
+ vol2 = @ebs.volumes[@ebs.volumes.keys[1]]
147
+ [vol1, vol2].each do |snapshots|
148
+ analyzer = EbsPruneSnapshot::SnapshotAnalyzer.new(snapshots, @ebs.rotation)
149
+ assert_equal analyzer.to_save.map {|s| s.created_at} , EbsPruneSnapshot::Tester.expectations
150
+ end
151
+ end
152
+
153
+ def test_describe
154
+ skip
155
+ @ebs.describe
156
+ end
157
+
158
+ def test_prune
159
+ skip
160
+ @ebs.prune
161
+ end
162
+
163
+ end
164
+
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ebs_prune_snapshot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dusty Doris
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: amazon-ec2
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: Prune EBS snapshots
31
+ email:
32
+ - dusty@doris.name
33
+ executables:
34
+ - ebs_prune_snapshot
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - Gemfile
40
+ - LICENSE
41
+ - README.txt
42
+ - Rakefile
43
+ - bin/ebs_prune_snapshot
44
+ - ebs_prune_snapshot.gemspec
45
+ - lib/ebs_prune_snapshot.rb
46
+ - lib/ebs_prune_snapshot/version.rb
47
+ - test/test_ebs_prune_snapshot.rb
48
+ homepage: https://github.com/dusty/ebs_prune_snapshot
49
+ licenses: []
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ required_rubygems_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.22
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: Prune EBS snapshots on a daily, weekly, and monthly rotation
72
+ test_files:
73
+ - test/test_ebs_prune_snapshot.rb