rds-rotate-db-snapshots 0.5.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 867b60671bdab535228d9730a2b7fbee3e1b9e44568f07215cc0c2eee6881a4b
4
- data.tar.gz: f204ef40c89395f6fc652d049854fd04cf10759e915907c9b04172873b1a0772
3
+ metadata.gz: 1f21f380e6c4adfe878d359b84cf4842cc143225c81656e10e77a8e7f1d5efa0
4
+ data.tar.gz: e9e43b9f8fc687a263a3f5cf49f5bfecd3b5fcb69200546adbcb75856f7348ce
5
5
  SHA512:
6
- metadata.gz: 85ff15bc60ddf07b213671d9449005135428cb477b9c6bc51ee570d459ce238b4672dac8945e14ec5dc543fb8d538b52dad742bfd5e342c6901573bda390309e
7
- data.tar.gz: 8b01afd618121cf7f6f8e237f81fadd782f056f6a1ab20eb1d9d7e469e0fb2e49c6872ed2a2fe7ecbfb008b418a0db2967ff281bfa358b0fafa372dea5f294ca
6
+ metadata.gz: 0d0a8ef6a1b168e0bac4d93b4b13ba2b7907bdbe7fd6307a596c739d36247dc252af8d665faf728a50402edb7e69940ee9c568b3601b4e3c219308861596b9c8
7
+ data.tar.gz: '09a5010edb7bad75fc94e4c64c0c523e0acf3e547224cfe33e107a0616cdc5eb8920ccf0fe91aafd25073216f1460f767996fdcc952228ca9d92daa4527491f3'
@@ -2,62 +2,27 @@ name: "CI"
2
2
 
3
3
  on:
4
4
  push:
5
- branches: ["main"]
5
+ branches: ["master"]
6
6
  pull_request:
7
- branches: ["main"]
8
-
9
- env:
10
- RUBY_MAIN_VERSION: '3.2'
7
+ branches: ["master"]
11
8
 
12
9
  jobs:
13
- rubocop:
14
- runs-on: ubuntu-20.04
15
- steps:
16
- - name: Checkout code
17
- uses: actions/checkout@v3
18
- - name: Install Ruby and gems
19
- uses: ruby/setup-ruby@319066216501fbd5e2d568f14b7d68c19fb67a5d #v1.133.1
20
- with:
21
- bundler-cache: true
22
- ruby-version: ${{ env.RUBY_MAIN_VERSION }}.0
23
- - name: Install Bundler
24
- run: gem install bundler
25
- - name: Bundle Install
26
- run: bundle install
27
- - name: Rubocop
28
- run: bundle exec rubocop
29
-
30
10
  test:
31
11
  runs-on: ubuntu-20.04
32
12
  strategy:
33
13
  matrix:
34
- ruby_version: ['2.7', '3.0', '3.1', '3.2']
14
+ ruby_version: [2.7, 3.0, 3.1, 'jruby']
35
15
  steps:
36
16
  - name: Checkout code
37
17
  uses: actions/checkout@v3
38
18
  - name: Install Ruby and gems
39
- uses: ruby/setup-ruby@319066216501fbd5e2d568f14b7d68c19fb67a5d #v1.133.1
19
+ uses: ruby/setup-ruby@03b78bdda287ae04217ee12e4b64996630a03542 #v1.131.0
40
20
  with:
41
21
  bundler-cache: true
42
22
  ruby-version: ${{ matrix.ruby_version }}
43
23
  - name: Install Bundler
44
24
  run: gem install bundler
45
- - name: Setup Code Climate test-reporter
46
- if: ${{ matrix.ruby_version == env.RUBY_MAIN_VERSION }}
47
- run: |
48
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
49
- chmod +x ./cc-test-reporter
50
- ./cc-test-reporter before-build
51
25
  - name: Bundle Install
52
26
  run: bundle install
53
27
  - name: Test
54
- run: bundle exec rspec
55
- - name: Publish Codeclimate Code Coverage
56
- if: ${{ matrix.ruby_version == env.RUBY_MAIN_VERSION }}
57
- run: |
58
- ./cc-test-reporter after-build -r ${{secrets.CC_TEST_REPORTER_ID}}
59
- - name: Coveralls Parallel
60
- if: ${{ matrix.ruby_version == env.RUBY_MAIN_VERSION }}
61
- uses: coverallsapp/github-action@master
62
- with:
63
- github-token: ${{ secrets.github_token }}
28
+ run: bundle exec rake test
@@ -13,10 +13,10 @@ name: "CodeQL"
13
13
 
14
14
  on:
15
15
  push:
16
- branches: [ "main" ]
16
+ branches: [ "master" ]
17
17
  pull_request:
18
18
  # The branches below must be a subset of the branches above
19
- branches: [ "main" ]
19
+ branches: [ "master" ]
20
20
  schedule:
21
21
  - cron: '22 4 * * 2'
22
22
 
data/Gemfile CHANGED
@@ -2,19 +2,19 @@ source "https://rubygems.org"
2
2
 
3
3
  gem 'aws-sdk-rds', '~> 1'
4
4
 
5
+ # Add dependencies to develop your gem here.
6
+ # Include everything needed to run rake, tests, features, etc.
7
+ group :development, :test do
8
+ gem 'bundler'
9
+ gem 'simplecov'
10
+ end
11
+
5
12
  group :development do
6
- gem "rake"
7
13
  gem 'juwelier'
8
- gem "pry"
9
- gem "pry-byebug"
10
- gem "rubocop"
11
- gem "rubocop-rspec"
12
14
  end
13
15
 
14
16
  group :test do
15
- gem "rspec", ">= 3.2"
16
- gem "rspec-mocks", ">= 3"
17
- gem "simplecov", ">= 0.13"
18
- gem 'simplecov-lcov', '~> 0.8.0'
19
- gem "webmock"
17
+ gem 'rake'
18
+ gem 'shoulda'
19
+ gem 'minitest'
20
20
  end
data/README.md CHANGED
@@ -1,9 +1,7 @@
1
1
  # rds-rotate-db-snapshots
2
2
 
3
3
  [<img src="https://badge.fury.io/rb/rds-rotate-db-snapshots.svg" alt="Gem
4
- Version" />](https://badge.fury.io/rb/rds-rotate-db-snapshots) [![CI](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/ci.yml/badge.svg?query=branch%3Amain+event%3Apush)](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush) [![CodeQL](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/codeql.yml/badge.svg?query=branch%3Amain+event%3Apush)](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/codeql.yml?query=branch%3Amain+event%3Apush)
5
- [![Maintainability](https://api.codeclimate.com/v1/badges/45bfe7dc4f21ac1403cb/maintainability)](https://codeclimate.com/github/serg-kovalev/rds-rotate-db-snapshots/maintainability)
6
- [![Test Coverage](https://api.codeclimate.com/v1/badges/45bfe7dc4f21ac1403cb/test_coverage)](https://codeclimate.com/github/serg-kovalev/rds-rotate-db-snapshots/test_coverage)
4
+ Version" />](https://badge.fury.io/rb/rds-rotate-db-snapshots) [![CI](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/ci.yml/badge.svg?query=branch%3Amaster+event%3Apush)](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/ci.yml?query=branch%3Amaster+event%3Apush) [![CodeQL](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/codeql.yml/badge.svg?query=branch%3Amaster+event%3Apush)](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/codeql.yml?query=branch%3Amaster+event%3Apush)
7
5
 
8
6
  Provides a simple way to rotate db snapshots in Amazon Relational Database
9
7
  Service (RDS).
@@ -11,9 +9,9 @@ Service (RDS).
11
9
  ## Tested on Rubies
12
10
 
13
11
  - 2.7
14
- - 3.0
15
12
  - 3.1
16
13
  - 3.2
14
+ - jruby
17
15
 
18
16
  ## Usage
19
17
 
@@ -35,20 +33,18 @@ Add this script to CRON (let's say it will run this script every X hours) and it
35
33
  #/usr/bin/bash
36
34
  AWS_ACCESS_KEY='xxxxxxxxxxxxxxxxxxxx'
37
35
  AWS_SECRET_ACCESS_KEY='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
38
- AWS_SESSION_TOKEN='session_token_goes_here'
39
36
  AWS_REGION='eu-west-1'
40
37
  DESCRIPTION_PREFIX='automatic-backup-'
41
38
  RDS_ROTATOR=/here/is/the/path/to/rds-rotate-db-snapshots
42
39
  DB_NAME='db_name_here'
43
40
 
44
- $RDS_ROTATOR --aws-region $AWS_REGION --aws-access-key $AWS_ACCESS_KEY --aws-secret-access-key $AWS_SECRET_ACCESS_KEY --aws-session-token $AWS_SESSION_TOKEN --pattern $DESCRIPTION_PREFIX --keep-hourly 24 --keep-daily 7 --keep-weekly 4 --keep-monthly 1 --keep-yearly 0 --create-snapshot $DESCRIPTION_PREFIX$DB_NAME $DB_NAME
41
+ $RDS_ROTATOR --aws-region $AWS_REGION --aws-access-key $AWS_ACCESS_KEY --aws-secret-access-key $AWS_SECRET_ACCESS_KEY --pattern $DESCRIPTION_PREFIX --keep-hourly 24 --keep-daily 7 --keep-weekly 4 --keep-monthly 1 --keep-yearly 0 --create-snapshot $DESCRIPTION_PREFIX$DB_NAME $DB_NAME
45
42
  ```
46
43
 
47
44
  ## Options
48
45
 
49
46
  - `--aws-access-key ACCESS_KEY` "AWS Access Key"
50
47
  - `--aws-secret-access-key SECRET_KEY` "AWS Secret Access Key"
51
- - `--aws-session-token $AWS_SESSION_TOKEN` "AWS Session Token"
52
48
  - `--aws-region REGION` "AWS Region"
53
49
  - `--pattern STRING` "Snapshots without this string in the description will be ignored"
54
50
  - `--by-tags TAG=VALUE,TAG=VALUE` "Instead of rotating specific snapshots, rotate over all the snapshots having the intersection of all given TAG=VALUE pairs."
@@ -69,7 +65,7 @@ show the messages.
69
65
 
70
66
  ## Contributing to rds-rotate-db-snapshots
71
67
 
72
- - Check out the latest main to make sure the feature hasn't been
68
+ - Check out the latest master to make sure the feature hasn't been
73
69
  implemented or the bug hasn't been fixed yet
74
70
  - Check out the issue tracker to make sure someone already hasn't requested
75
71
  it and/or contributed it
data/Rakefile CHANGED
@@ -3,8 +3,8 @@ require 'bundler'
3
3
  begin
4
4
  Bundler.setup(:default, :development)
5
5
  rescue Bundler::BundlerError => e
6
- warn e.message
7
- warn "Run `bundle install` to install missing gems"
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
8
  exit e.status_code
9
9
  end
10
10
  require 'rake'
@@ -14,14 +14,29 @@ Juwelier::Tasks.new do |gem|
14
14
  gem.name = "rds-rotate-db-snapshots"
15
15
  gem.homepage = "http://github.com/serg-kovalev/rds-rotate-db-snapshots"
16
16
  gem.license = "MIT"
17
- gem.summary = %(Amazon RDS DB snapshot rotator)
18
- gem.description = %(Provides a simple way to rotate RDS DB snapshots with configurable retention periods.)
17
+ gem.summary = %Q{Amazon RDS DB snapshot rotator}
18
+ gem.description = %Q{Provides a simple way to rotate RDS DB snapshots with configurable retention periods.}
19
19
  gem.email = "kovserg@gmail.com"
20
20
  gem.authors = ["Siarhei Kavaliou"]
21
21
  gem.version = File.exist?('VERSION') ? File.read('VERSION') : ""
22
22
  end
23
23
  Juwelier::RubygemsDotOrgTasks.new
24
24
 
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.pattern = 'test/**/test_*.rb'
28
+ test.verbose = true
29
+ end
30
+
31
+ # require 'simplecov'
32
+ # Rcov::RcovTask.new do |test|
33
+ # test.libs << 'test'
34
+ # test.pattern = 'test/**/test_*.rb'
35
+ # test.verbose = true
36
+ # end
37
+
38
+ task :default => :test
39
+
25
40
  require 'rdoc/task'
26
41
  Rake::RDocTask.new do |rdoc|
27
42
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.2
1
+ 0.4.3
@@ -1,59 +1,291 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require_relative '../lib/rds_rotate_db_snapshots'
3
+ require 'rubygems'
4
+ require 'aws-sdk-rds'
5
+ require 'optparse'
4
6
 
5
- rrds = RdsRotateDbSnapshots.new(script_name: File.basename($PROGRAM_NAME), cli: true)
7
+ $opts = {
8
+ :aws_access_key => ENV["AWS_ACCESS_KEY_ID"],
9
+ :aws_secret_access_key => ENV["AWS_SECRET_ACCESS_KEY"],
10
+ :aws_session_token => ENV["AWS_SESSION_TOKEN"],
11
+ :aws_region => ENV["AWS_REGION"],
12
+ :pattern => nil,
13
+ :by_tags => nil,
14
+ :dry_run => false,
15
+ :backoff_limit => 15,
16
+ :create_snapshot => nil
17
+ }
6
18
 
7
- if rrds.options[:aws_access_key].nil? || rrds.options[:aws_secret_access_key].nil?
8
- puts "You must specify your Amazon credentials via --aws-access-key and --aws-secret_access-key and " \
9
- "--aws-session-token"
10
- exit 1
19
+ $time_periods = {
20
+ :hourly => { :seconds => 60 * 60, :format => '%Y-%m-%d-%H', :keep => 0, :keeping => {} },
21
+ :daily => { :seconds => 24 * 60 * 60, :format => '%Y-%m-%d', :keep => 0, :keeping => {} },
22
+ :weekly => { :seconds => 7 * 24 * 60 * 60, :format => '%Y-%W', :keep => 0, :keeping => {} },
23
+ :monthly => { :seconds => 30 * 24 * 60 * 60, :format => '%Y-%m', :keep => 0, :keeping => {} },
24
+ :yearly => { :seconds => 12 * 30 * 24 * 60 * 60, :format => '%Y', :keep => 0, :keeping => {} },
25
+ }
26
+ def backoff()
27
+ $backoffed = $backoffed + 1
28
+
29
+ if $opts[:backoff_limit] > 0 && $opts[:backoff_limit] < $backoffed
30
+ puts "Too many backoff attempts. Sorry it didn't work out."
31
+ exit 2
32
+ end
33
+
34
+ naptime = rand(60) * $backoffed
35
+ puts "Backing off for #{naptime} seconds..."
36
+ sleep naptime
11
37
  end
12
38
 
13
- if rrds.options[:aws_region].nil?
14
- puts "You must specify your AWS Region via --aws-region"
39
+ def rotate_em(snapshots)
40
+ # poor man's way to get a deep copy of our time_periods definition hash
41
+ periods = Marshal.load(Marshal.dump($time_periods))
42
+
43
+ snapshots.each do |snapshot|
44
+ time = snapshot[:snapshot_create_time]
45
+ db_id = snapshot[:db_instance_identifier]
46
+ snapshot_id = snapshot[:db_snapshot_identifier]
47
+ description = snapshot_id
48
+ keep_reason = nil
49
+
50
+ if $opts[:pattern] && description !~ /#{$opts[:pattern]}/
51
+ puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Skipping snapshot with description #{description}"
52
+ next
53
+ end
54
+
55
+ periods.keys.sort { |a, b| periods[a][:seconds] <=> periods[b][:seconds] }.each do |period|
56
+ period_info = periods[period]
57
+ keep = period_info[:keep]
58
+ keeping = period_info[:keeping]
59
+
60
+ time_string = time.strftime period_info[:format]
61
+ if Time.now - time < keep * period_info[:seconds]
62
+ if !keeping.key?(time_string) && keeping.length < keep
63
+ keep_reason = period
64
+ keeping[time_string] = snapshot
65
+ end
66
+ break
67
+ end
68
+ end
69
+
70
+ if keep_reason.nil? && snapshot == snapshots.last && $opts[:keep_last]
71
+ keep_reason = 'last snapshot'
72
+ end
73
+
74
+ if !keep_reason.nil?
75
+ puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Keeping for #{keep_reason}"
76
+ else
77
+ puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Deleting"
78
+ begin
79
+ $rds.delete_db_snapshot(db_snapshot_identifier: snapshot_id) unless $opts[:dry_run]
80
+ rescue Aws::RDS::Errors => e
81
+ backoff()
82
+ retry
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ def create_snapshot(name, db_indentifier_ids)
89
+ if !!name
90
+ name = name.gsub(/[^a-zA-Z0-9\-]/, '')
91
+ if name.size > 0
92
+ name = "#{name}-#{Time.now.strftime('%Y%m%d%H%M%S')}"
93
+ db_indentifier_ids.each do |db_id|
94
+ begin
95
+ $rds.create_db_snapshot(db_snapshot_identifier: name, db_instance_identifier: db_id) unless $opts[:dry_run]
96
+ puts " #{Time.now.strftime '%Y-%m-%d %H:%M:%S'} Creation snapshot #{name} is pending (db: #{db_id})"
97
+ rescue Aws::RDS::Errors::InvalidDBInstanceStateFault => e
98
+ backoff()
99
+ retry
100
+ end
101
+ end
102
+ else
103
+ puts "invalid snapshot name format - #{name}"
104
+ exit 1
105
+ end
106
+ end
107
+ end
108
+
109
+ def split_tag(hash,v)
110
+ v.split(',').each do |pair|
111
+ tag, value = pair.split('=',2)
112
+ if value.nil?
113
+ puts "invalid tag=value format"
114
+ exit 1
115
+ end
116
+ hash[tag] = value
117
+ end
118
+ end
119
+
120
+ def get_db_snapshots(options)
121
+ snapshots = []
122
+ response = $rds.describe_db_snapshots(options)
123
+ while true do
124
+ snapshots += response.db_snapshots
125
+ break unless response[:marker]
126
+
127
+ response = $rds.describe_db_snapshots(options.merge(marker: response[:marker]))
128
+ end
129
+ snapshots
130
+ end
131
+
132
+ OptionParser.new do |o|
133
+ script_name = File.basename($0)
134
+ o.banner = "Usage: #{script_name} [options] <db_indentifier>\nUsage: #{script_name} --by-tags <tag=value,...> [other options]"
135
+ o.separator ""
136
+
137
+ o.on("--aws-access-key ACCESS_KEY", "AWS Access Key") do |v|
138
+ $opts[:aws_access_key] = v
139
+ end
140
+
141
+ o.on("--aws-secret-access-key SECRET_KEY", "AWS Secret Access Key") do |v|
142
+ $opts[:aws_secret_access_key] = v
143
+ end
144
+
145
+ o.on("--aws-region REGION", "AWS Region") do |v|
146
+ $opts[:aws_region] = v
147
+ end
148
+
149
+ o.on("--aws-session-token SESSION_TOKEN", "AWS session token") do |v|
150
+ $opts[:aws_session_token] = v
151
+ end
152
+
153
+ o.on("--pattern STRING", "Snapshots without this string in the description will be ignored") do |v|
154
+ $opts[:pattern] = v
155
+ end
156
+
157
+ o.on("--by-tags TAG=VALUE,TAG=VALUE", "Instead of rotating specific snapshots, rotate over all the snapshots having the intersection of all given TAG=VALUE pairs.") do |v|
158
+ $opts[:by_tags] = {}
159
+ puts 'Hey! It\'s not implemented in RDS yet. Who knows, maybe they will add Tagging in RDS later.'
160
+ exit 0
161
+ split_tag($opts[:by_tags],v)
162
+ end
163
+
164
+ o.on("--backoff-limit LIMIT", "Backoff and retry when hitting RDS Error exceptions no more than this many times. Default is 15") do |v|
165
+ $opts[:backoff_limit] = v
166
+ end
167
+
168
+ o.on("--create-snapshot STRING", "Use this option if you want to create a snapshot") do |v|
169
+ $opts[:create_snapshot] = v
170
+ end
171
+
172
+ $time_periods.keys.sort { |a, b| $time_periods[a][:seconds] <=> $time_periods[b][:seconds] }.each do |period|
173
+ o.on("--keep-#{period} NUMBER", Integer, "Number of #{period} snapshots to keep") do |v|
174
+ $time_periods[period][:keep] = v
175
+ end
176
+ end
177
+
178
+ o.on("--keep-last", "Keep the most recent snapshot, regardless of time-based policy") do |v|
179
+ $opts[:keep_last] = true
180
+ end
181
+
182
+ o.on("--dry-run", "Shows what would happen without doing anything") do |v|
183
+ $opts[:dry_run] = true
184
+ end
185
+ end.parse!
186
+
187
+ if $opts[:aws_access_key].nil? || $opts[:aws_secret_access_key].nil?
188
+ puts "You must specify your Amazon credentials via --aws-access-key and --aws-secret_access-key"
15
189
  exit 1
16
190
  end
17
191
 
18
- if ARGV.empty? && rrds.options[:by_tags].nil?
192
+ if ARGV.empty? and $opts[:by_tags].nil?
19
193
  puts "You must provide at least one DB Indentifier when not rotating by tags"
20
194
  exit 1
21
195
  end
22
196
 
23
- if rrds.options[:by_tags].nil?
197
+ if $opts[:by_tags].nil?
24
198
  db_indentifier_ids = ARGV
25
199
 
26
200
  db_indentifier_ids.each do |db_id|
27
- next unless db_id.nil? || db_id.gsub(/\s/, '').empty?
28
-
29
- # sanity check
30
- puts "Invalid db indentifier: #{db_id}"
31
- exit 1
201
+ if db_id.nil? or db_id.gsub(/\s/, '').size < 1
202
+ # sanity check
203
+ puts "Invalid db indentifier: #{db_id}"
204
+ exit 1
205
+ end
32
206
  end
33
207
  else
34
- puts "Ignoring supplied db_indentifier_ids because we're rotating by tags." unless ARGV.empty?
35
- if rrds.options[:by_tags].empty?
208
+ if !ARGV.empty?
209
+ puts "Ignoring supplied db_indentifier_ids because we're rotating by tags."
210
+ end
211
+ if $opts[:by_tags].length == 0
36
212
  puts "Rotating by tags but no tags specified? Refusing to rotate all snapshots!"
37
213
  exit 1
38
214
  end
39
215
  end
40
216
 
41
- if rrds.options[:backoff_limit].negative?
217
+ if $opts[:backoff_limit] < 0
42
218
  puts "A negative backoff limit doesn't make much sense."
43
219
  exit 1
44
220
  end
45
221
 
46
- rrds.create_snapshot(rrds.options[:create_snapshot], db_indentifier_ids) if rrds.options[:create_snapshot]
222
+ $backoffed = 0
223
+ begin
224
+ Aws.config.update(
225
+ access_key_id: $opts[:aws_access_key],
226
+ secret_access_key: $opts[:aws_secret_access_key],
227
+ region: $opts[:aws_region],
228
+ session_token: $opts[:aws_session_token]
229
+ )
230
+ $rds = Aws::RDS::Client.new
231
+ rescue Aws::RDS::Errors => e
232
+ backoff()
233
+ retry
234
+ end
235
+
236
+ if $opts[:create_snapshot]
237
+ create_snapshot($opts[:create_snapshot], db_indentifier_ids)
238
+ end
47
239
 
48
240
  all_snapshots = []
49
- if rrds.options[:by_tags]
50
- rrds.rotate_by_tags
241
+ if $opts[:by_tags]
242
+ $opts[:by_tags].each do |tag, value|
243
+ begin
244
+ these_snapshots = $rds.describe_tags(snapshot_type: 'manual', filters: {'resource-type'=>"snapshot", 'key'=>tag, 'value'=>value}).
245
+ delete_if{ |e| e.status != 'available' }
246
+ rescue Aws::RDS::Errors => e
247
+ backoff()
248
+ retry
249
+ end
250
+ if these_snapshots.length == 0
251
+ puts "(tag,value)=(#{tag},#{value}) found no snapshots; nothing to rotate!"
252
+ exit 0
253
+ end
254
+ if all_snapshots.length == 0
255
+ remaining_snapshots = these_snapshots
256
+ else
257
+ remaining_snapshots = all_snapshots & these_snapshots
258
+ end
259
+ if remaining_snapshots.length == 0
260
+ puts "No remaining snapshots after applying (tag,value)=(#{tag},#{value}) filter; nothing to rotate!"
261
+ exit 0
262
+ end
263
+ all_snapshots = remaining_snapshots
264
+ end
265
+
266
+ begin
267
+ rotate_these = get_db_snapshots(db_instance_identifier: all_snapshots.map(&:db_instance_identifier).uniq).
268
+ delete_if{ |e| !all_snapshots.include?(e.db_snapshot_identifier) }.
269
+ sort {|a,b| a[:snapshot_create_time] <=> b[:snapshot_create_time] }
270
+ rescue Aws::RDS::Errors => e
271
+ backoff()
272
+ retry
273
+ end
274
+
275
+ rotate_em(rotate_these)
51
276
  else
52
- snapshots = rrds.get_db_snapshots(snapshot_type: 'manual').delete_if { |e| e[:status] != 'available' }
277
+ begin
278
+ all_snapshots = get_db_snapshots(snapshot_type: 'manual').
279
+ delete_if{ |e| e[:status] != 'available' }
280
+ rescue Aws::RDS::Errors => e
281
+ backoff()
282
+ retry
283
+ end
284
+
53
285
  db_indentifier_ids.each do |db_id|
54
- rrds.rotate_em(
55
- snapshots.select { |ss| ss[:db_instance_identifier] == db_id }
56
- .sort { |a, b| a[:snapshot_create_time] <=> b[:snapshot_create_time] }
286
+ rotate_em(
287
+ all_snapshots.select {|ss| ss[:db_instance_identifier] == db_id }.
288
+ sort {|a,b| a[:snapshot_create_time] <=> b[:snapshot_create_time] }
57
289
  )
58
290
  end
59
291
  end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: rds-rotate-db-snapshots 0.5.2 ruby lib
5
+ # stub: rds-rotate-db-snapshots 1.0.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "rds-rotate-db-snapshots".freeze
9
- s.version = "0.5.2"
9
+ s.version = "1.0.0".freeze
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["Siarhei Kavaliou".freeze]
14
- s.date = "2023-01-11"
14
+ s.date = "2024-01-02"
15
15
  s.description = "Provides a simple way to rotate RDS DB snapshots with configurable retention periods.".freeze
16
16
  s.email = "kovserg@gmail.com".freeze
17
17
  s.executables = ["rds-rotate-db-snapshots".freeze]
@@ -24,42 +24,27 @@ Gem::Specification.new do |s|
24
24
  ".github/dependabot.yml",
25
25
  ".github/workflows/ci.yml",
26
26
  ".github/workflows/codeql.yml",
27
- ".rspec",
28
- ".rubocop.yml",
29
- ".rubocop_todo.yml",
30
27
  "Gemfile",
31
28
  "LICENSE.txt",
32
29
  "README.md",
33
30
  "Rakefile",
34
31
  "VERSION",
35
32
  "bin/rds-rotate-db-snapshots",
36
- "lib/rds_rotate_db_snapshots.rb",
37
- "lib/rds_rotate_db_snapshots/action_wrappers.rb",
38
- "lib/rds_rotate_db_snapshots/actions.rb",
39
- "lib/rds_rotate_db_snapshots/options_parser.rb",
40
- "lib/rds_rotate_db_snapshots/options_parser/options.rb",
41
- "lib/rds_rotate_db_snapshots/rds_client.rb",
42
- "rds-rotate-db-snapshots.gemspec",
43
- "spec/helper.rb",
44
- "spec/lib/rds_rotate_db_snapshots/action_wrappers_spec.rb",
45
- "spec/lib/rds_rotate_db_snapshots/actions_spec.rb",
46
- "spec/lib/rds_rotate_db_snapshots/options_parser_spec.rb",
47
- "spec/lib/rds_rotate_db_snapshots/rds_client_spec.rb",
48
- "spec/lib/rds_rotate_db_snapshots_spec.rb"
33
+ "rds-rotate-db-snapshots.gemspec"
49
34
  ]
50
35
  s.homepage = "http://github.com/serg-kovalev/rds-rotate-db-snapshots".freeze
51
36
  s.licenses = ["MIT".freeze]
52
- s.rubygems_version = "3.4.1".freeze
37
+ s.rubygems_version = "3.5.3".freeze
53
38
  s.summary = "Amazon RDS DB snapshot rotator".freeze
54
39
 
55
40
  s.specification_version = 4
56
41
 
57
- s.add_runtime_dependency(%q<aws-sdk-rds>.freeze, ["~> 1"])
58
- s.add_development_dependency(%q<rake>.freeze, [">= 0"])
59
- s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
60
- s.add_development_dependency(%q<pry>.freeze, [">= 0"])
61
- s.add_development_dependency(%q<pry-byebug>.freeze, [">= 0"])
62
- s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
63
- s.add_development_dependency(%q<rubocop-rspec>.freeze, [">= 0"])
42
+ s.add_runtime_dependency(%q<aws-sdk-rds>.freeze, ["~> 1".freeze])
43
+ s.add_development_dependency(%q<rake>.freeze, [">= 0".freeze])
44
+ s.add_development_dependency(%q<juwelier>.freeze, [">= 0".freeze])
45
+ s.add_development_dependency(%q<pry>.freeze, [">= 0".freeze])
46
+ s.add_development_dependency(%q<pry-byebug>.freeze, [">= 0".freeze])
47
+ s.add_development_dependency(%q<rubocop>.freeze, [">= 0".freeze])
48
+ s.add_development_dependency(%q<rubocop-rspec>.freeze, [">= 0".freeze])
64
49
  end
65
50
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rds-rotate-db-snapshots
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Siarhei Kavaliou
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-11 00:00:00.000000000 Z
11
+ date: 2024-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-rds
@@ -122,28 +122,13 @@ files:
122
122
  - ".github/dependabot.yml"
123
123
  - ".github/workflows/ci.yml"
124
124
  - ".github/workflows/codeql.yml"
125
- - ".rspec"
126
- - ".rubocop.yml"
127
- - ".rubocop_todo.yml"
128
125
  - Gemfile
129
126
  - LICENSE.txt
130
127
  - README.md
131
128
  - Rakefile
132
129
  - VERSION
133
130
  - bin/rds-rotate-db-snapshots
134
- - lib/rds_rotate_db_snapshots.rb
135
- - lib/rds_rotate_db_snapshots/action_wrappers.rb
136
- - lib/rds_rotate_db_snapshots/actions.rb
137
- - lib/rds_rotate_db_snapshots/options_parser.rb
138
- - lib/rds_rotate_db_snapshots/options_parser/options.rb
139
- - lib/rds_rotate_db_snapshots/rds_client.rb
140
131
  - rds-rotate-db-snapshots.gemspec
141
- - spec/helper.rb
142
- - spec/lib/rds_rotate_db_snapshots/action_wrappers_spec.rb
143
- - spec/lib/rds_rotate_db_snapshots/actions_spec.rb
144
- - spec/lib/rds_rotate_db_snapshots/options_parser_spec.rb
145
- - spec/lib/rds_rotate_db_snapshots/rds_client_spec.rb
146
- - spec/lib/rds_rotate_db_snapshots_spec.rb
147
132
  homepage: http://github.com/serg-kovalev/rds-rotate-db-snapshots
148
133
  licenses:
149
134
  - MIT
@@ -163,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
163
148
  - !ruby/object:Gem::Version
164
149
  version: '0'
165
150
  requirements: []
166
- rubygems_version: 3.4.1
151
+ rubygems_version: 3.5.3
167
152
  signing_key:
168
153
  specification_version: 4
169
154
  summary: Amazon RDS DB snapshot rotator
data/.rspec DELETED
@@ -1 +0,0 @@
1
- -w --color