rds-rotate-db-snapshots 0.5.2 → 1.0.0

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 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