rds-rotate-db-snapshots 0.5.1 → 0.5.2
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 +4 -4
- data/.github/workflows/ci.yml +33 -13
- data/.rubocop.yml +93 -0
- data/.rubocop_todo.yml +127 -0
- data/Gemfile +3 -2
- data/README.md +6 -1
- data/Rakefile +4 -4
- data/VERSION +1 -1
- data/bin/rds-rotate-db-snapshots +16 -19
- data/lib/rds_rotate_db_snapshots/action_wrappers.rb +3 -3
- data/lib/rds_rotate_db_snapshots/actions.rb +71 -64
- data/lib/rds_rotate_db_snapshots/options_parser/options.rb +80 -0
- data/lib/rds_rotate_db_snapshots/options_parser.rb +23 -75
- data/lib/rds_rotate_db_snapshots.rb +6 -5
- data/rds-rotate-db-snapshots.gemspec +15 -20
- data/spec/helper.rb +1 -1
- data/spec/lib/rds_rotate_db_snapshots/action_wrappers_spec.rb +3 -3
- data/spec/lib/rds_rotate_db_snapshots/actions_spec.rb +80 -60
- data/spec/lib/rds_rotate_db_snapshots/options_parser_spec.rb +6 -9
- data/spec/lib/rds_rotate_db_snapshots/rds_client_spec.rb +11 -9
- data/spec/lib/rds_rotate_db_snapshots_spec.rb +6 -5
- metadata +35 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 867b60671bdab535228d9730a2b7fbee3e1b9e44568f07215cc0c2eee6881a4b
|
4
|
+
data.tar.gz: f204ef40c89395f6fc652d049854fd04cf10759e915907c9b04172873b1a0772
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85ff15bc60ddf07b213671d9449005135428cb477b9c6bc51ee570d459ce238b4672dac8945e14ec5dc543fb8d538b52dad742bfd5e342c6901573bda390309e
|
7
|
+
data.tar.gz: 8b01afd618121cf7f6f8e237f81fadd782f056f6a1ab20eb1d9d7e469e0fb2e49c6872ed2a2fe7ecbfb008b418a0db2967ff281bfa358b0fafa372dea5f294ca
|
data/.github/workflows/ci.yml
CHANGED
@@ -6,38 +6,58 @@ on:
|
|
6
6
|
pull_request:
|
7
7
|
branches: ["main"]
|
8
8
|
|
9
|
+
env:
|
10
|
+
RUBY_MAIN_VERSION: '3.2'
|
11
|
+
|
9
12
|
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
|
+
|
10
30
|
test:
|
11
31
|
runs-on: ubuntu-20.04
|
12
32
|
strategy:
|
13
33
|
matrix:
|
14
|
-
ruby_version: [2.7, 3.0, 3.1]
|
34
|
+
ruby_version: ['2.7', '3.0', '3.1', '3.2']
|
15
35
|
steps:
|
16
36
|
- name: Checkout code
|
17
37
|
uses: actions/checkout@v3
|
18
38
|
- name: Install Ruby and gems
|
19
|
-
uses: ruby/setup-ruby@
|
39
|
+
uses: ruby/setup-ruby@319066216501fbd5e2d568f14b7d68c19fb67a5d #v1.133.1
|
20
40
|
with:
|
21
41
|
bundler-cache: true
|
22
42
|
ruby-version: ${{ matrix.ruby_version }}
|
23
43
|
- name: Install Bundler
|
24
44
|
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
|
25
51
|
- name: Bundle Install
|
26
52
|
run: bundle install
|
27
53
|
- name: Test
|
28
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}}
|
29
59
|
- name: Coveralls Parallel
|
60
|
+
if: ${{ matrix.ruby_version == env.RUBY_MAIN_VERSION }}
|
30
61
|
uses: coverallsapp/github-action@master
|
31
62
|
with:
|
32
63
|
github-token: ${{ secrets.github_token }}
|
33
|
-
flag-name: run-${{ matrix.ruby_version }}
|
34
|
-
parallel: true
|
35
|
-
finish:
|
36
|
-
needs: test
|
37
|
-
runs-on: ubuntu-latest
|
38
|
-
steps:
|
39
|
-
- name: Coveralls Finished
|
40
|
-
uses: coverallsapp/github-action@master
|
41
|
-
with:
|
42
|
-
github-token: ${{ secrets.github_token }}
|
43
|
-
parallel-finished: true
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
inherit_from: .rubocop_todo.yml
|
2
|
+
|
3
|
+
require:
|
4
|
+
- rubocop-rspec
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
NewCops: enable
|
8
|
+
TargetRubyVersion: 3.2.0
|
9
|
+
Exclude:
|
10
|
+
- 'bin/{bundle,rails,rake}'
|
11
|
+
- vendor/**/*
|
12
|
+
|
13
|
+
Layout/LineLength:
|
14
|
+
Max: 120
|
15
|
+
|
16
|
+
Bundler/OrderedGems:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Lint/RescueException:
|
20
|
+
Enabled: true
|
21
|
+
|
22
|
+
Style/EmptyElse:
|
23
|
+
EnforcedStyle: empty
|
24
|
+
|
25
|
+
Style/FrozenStringLiteralComment:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
Style/RescueStandardError:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/StringLiterals:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Layout/SpaceInLambdaLiteral:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Style/Lambda:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Style/NumericLiteralPrefix:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/EmptyMethod:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Style/ParallelAssignment:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Layout/EmptyLinesAroundExceptionHandlingKeywords:
|
50
|
+
Enabled: false
|
51
|
+
|
52
|
+
Layout/FirstHashElementIndentation:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Layout/ParameterAlignment:
|
56
|
+
Enabled: false
|
57
|
+
|
58
|
+
Naming/RescuedExceptionsVariableName:
|
59
|
+
Enabled: false
|
60
|
+
|
61
|
+
Style/Documentation:
|
62
|
+
Enabled: false
|
63
|
+
|
64
|
+
Lint/DuplicateRegexpCharacterClassElement: # (new in 1.1)
|
65
|
+
Enabled: true
|
66
|
+
Lint/EmptyBlock: # (new in 1.1)
|
67
|
+
Enabled: true
|
68
|
+
Lint/NoReturnInBeginEndBlocks: # (new in 1.2)
|
69
|
+
Enabled: true
|
70
|
+
Lint/ToEnumArguments: # (new in 1.1)
|
71
|
+
Enabled: true
|
72
|
+
Lint/UnmodifiedReduceAccumulator: # (new in 1.1)
|
73
|
+
Enabled: true
|
74
|
+
Style/ArgumentsForwarding: # (new in 1.1)
|
75
|
+
Enabled: true
|
76
|
+
Style/CollectionCompact: # (new in 1.2)
|
77
|
+
Enabled: true
|
78
|
+
Style/DocumentDynamicEvalDefinition: # (new in 1.1)
|
79
|
+
Enabled: true
|
80
|
+
Style/NegatedIfElseCondition: # (new in 1.2)
|
81
|
+
Enabled: true
|
82
|
+
Style/SwapValues: # (new in 1.1)
|
83
|
+
Enabled: true
|
84
|
+
|
85
|
+
Metrics/BlockLength:
|
86
|
+
Exclude:
|
87
|
+
- 'spec/**/*' # Swagger specs require large blocks
|
88
|
+
|
89
|
+
Style/HashSyntax:
|
90
|
+
EnforcedShorthandSyntax: never
|
91
|
+
|
92
|
+
RSpec/MultipleMemoizedHelpers:
|
93
|
+
Enabled: false
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2023-01-10 16:06:29 UTC using RuboCop version 1.43.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Configuration parameters: Severity, Include.
|
11
|
+
# Include: **/*.gemspec
|
12
|
+
Gemspec/RequiredRubyVersion:
|
13
|
+
Exclude:
|
14
|
+
- 'rds-rotate-db-snapshots.gemspec'
|
15
|
+
|
16
|
+
# Offense count: 3
|
17
|
+
# This cop supports safe autocorrection (--autocorrect).
|
18
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, IgnoredPatterns.
|
19
|
+
# URISchemes: http, https
|
20
|
+
Layout/LineLength:
|
21
|
+
Max: 146
|
22
|
+
|
23
|
+
# Offense count: 1
|
24
|
+
Lint/UnreachableCode:
|
25
|
+
Exclude:
|
26
|
+
- 'lib/rds_rotate_db_snapshots/options_parser.rb'
|
27
|
+
|
28
|
+
# Offense count: 4
|
29
|
+
Lint/UselessAssignment:
|
30
|
+
Exclude:
|
31
|
+
- 'bin/rds-rotate-db-snapshots'
|
32
|
+
- 'lib/rds_rotate_db_snapshots/actions.rb'
|
33
|
+
|
34
|
+
# Offense count: 5
|
35
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods, CountRepeatedAttributes.
|
36
|
+
Metrics/AbcSize:
|
37
|
+
Max: 56
|
38
|
+
|
39
|
+
# Offense count: 2
|
40
|
+
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods, inherit_mode.
|
41
|
+
# AllowedMethods: refine
|
42
|
+
Metrics/BlockLength:
|
43
|
+
Max: 42
|
44
|
+
|
45
|
+
# Offense count: 1
|
46
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods.
|
47
|
+
Metrics/CyclomaticComplexity:
|
48
|
+
Max: 15
|
49
|
+
|
50
|
+
# Offense count: 6
|
51
|
+
# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, AllowedMethods, AllowedPatterns, IgnoredMethods.
|
52
|
+
Metrics/MethodLength:
|
53
|
+
Max: 44
|
54
|
+
|
55
|
+
# Offense count: 1
|
56
|
+
# Configuration parameters: AllowedMethods, AllowedPatterns, IgnoredMethods.
|
57
|
+
Metrics/PerceivedComplexity:
|
58
|
+
Max: 16
|
59
|
+
|
60
|
+
# Offense count: 1
|
61
|
+
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
|
62
|
+
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
|
63
|
+
Naming/MemoizedInstanceVariableName:
|
64
|
+
Exclude:
|
65
|
+
- 'lib/rds_rotate_db_snapshots/options_parser.rb'
|
66
|
+
|
67
|
+
# Offense count: 1
|
68
|
+
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
69
|
+
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
70
|
+
Naming/MethodParameterName:
|
71
|
+
Exclude:
|
72
|
+
- 'lib/rds_rotate_db_snapshots/options_parser.rb'
|
73
|
+
|
74
|
+
# Offense count: 3
|
75
|
+
# Configuration parameters: CountAsOne.
|
76
|
+
RSpec/ExampleLength:
|
77
|
+
Max: 9
|
78
|
+
|
79
|
+
# Offense count: 10
|
80
|
+
# Configuration parameters: .
|
81
|
+
# SupportedStyles: have_received, receive
|
82
|
+
RSpec/MessageSpies:
|
83
|
+
EnforcedStyle: receive
|
84
|
+
|
85
|
+
# Offense count: 6
|
86
|
+
RSpec/MultipleExpectations:
|
87
|
+
Max: 6
|
88
|
+
|
89
|
+
# Offense count: 17
|
90
|
+
# Configuration parameters: EnforcedStyle, IgnoreSharedExamples.
|
91
|
+
# SupportedStyles: always, named_only
|
92
|
+
RSpec/NamedSubject:
|
93
|
+
Exclude:
|
94
|
+
- 'spec/lib/rds_rotate_db_snapshots/action_wrappers_spec.rb'
|
95
|
+
- 'spec/lib/rds_rotate_db_snapshots/options_parser_spec.rb'
|
96
|
+
- 'spec/lib/rds_rotate_db_snapshots_spec.rb'
|
97
|
+
|
98
|
+
# Offense count: 1
|
99
|
+
RSpec/StubbedMock:
|
100
|
+
Exclude:
|
101
|
+
- 'spec/lib/rds_rotate_db_snapshots/actions_spec.rb'
|
102
|
+
|
103
|
+
# Offense count: 6
|
104
|
+
RSpec/SubjectStub:
|
105
|
+
Exclude:
|
106
|
+
- 'spec/lib/rds_rotate_db_snapshots/action_wrappers_spec.rb'
|
107
|
+
- 'spec/lib/rds_rotate_db_snapshots/actions_spec.rb'
|
108
|
+
- 'spec/lib/rds_rotate_db_snapshots_spec.rb'
|
109
|
+
|
110
|
+
# Offense count: 1
|
111
|
+
# Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
|
112
|
+
RSpec/VerifiedDoubles:
|
113
|
+
Exclude:
|
114
|
+
- 'spec/lib/rds_rotate_db_snapshots/actions_spec.rb'
|
115
|
+
|
116
|
+
# Offense count: 1
|
117
|
+
# Configuration parameters: AllowedVariables.
|
118
|
+
Style/GlobalVars:
|
119
|
+
Exclude:
|
120
|
+
- 'spec/helper.rb'
|
121
|
+
|
122
|
+
# Offense count: 3
|
123
|
+
# This cop supports safe autocorrection (--autocorrect).
|
124
|
+
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, IgnoredPatterns.
|
125
|
+
# URISchemes: http, https
|
126
|
+
Layout/LineLength:
|
127
|
+
Max: 146
|
data/Gemfile
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
|
3
3
|
gem 'aws-sdk-rds', '~> 1'
|
4
|
-
gem "rake"
|
5
4
|
|
6
5
|
group :development do
|
6
|
+
gem "rake"
|
7
7
|
gem 'juwelier'
|
8
8
|
gem "pry"
|
9
9
|
gem "pry-byebug"
|
10
|
+
gem "rubocop"
|
11
|
+
gem "rubocop-rspec"
|
10
12
|
end
|
11
13
|
|
12
14
|
group :test do
|
13
15
|
gem "rspec", ">= 3.2"
|
14
16
|
gem "rspec-mocks", ">= 3"
|
15
|
-
gem "rubocop", "~> 0.50.0"
|
16
17
|
gem "simplecov", ">= 0.13"
|
17
18
|
gem 'simplecov-lcov', '~> 0.8.0'
|
18
19
|
gem "webmock"
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
[<img src="https://badge.fury.io/rb/rds-rotate-db-snapshots.svg" alt="Gem
|
4
4
|
Version" />](https://badge.fury.io/rb/rds-rotate-db-snapshots) [](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush) [](https://github.com/serg-kovalev/rds-rotate-db-snapshots/actions/workflows/codeql.yml?query=branch%3Amain+event%3Apush)
|
5
|
+
[](https://codeclimate.com/github/serg-kovalev/rds-rotate-db-snapshots/maintainability)
|
6
|
+
[](https://codeclimate.com/github/serg-kovalev/rds-rotate-db-snapshots/test_coverage)
|
5
7
|
|
6
8
|
Provides a simple way to rotate db snapshots in Amazon Relational Database
|
7
9
|
Service (RDS).
|
@@ -9,6 +11,7 @@ Service (RDS).
|
|
9
11
|
## Tested on Rubies
|
10
12
|
|
11
13
|
- 2.7
|
14
|
+
- 3.0
|
12
15
|
- 3.1
|
13
16
|
- 3.2
|
14
17
|
|
@@ -32,18 +35,20 @@ Add this script to CRON (let's say it will run this script every X hours) and it
|
|
32
35
|
#/usr/bin/bash
|
33
36
|
AWS_ACCESS_KEY='xxxxxxxxxxxxxxxxxxxx'
|
34
37
|
AWS_SECRET_ACCESS_KEY='yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy'
|
38
|
+
AWS_SESSION_TOKEN='session_token_goes_here'
|
35
39
|
AWS_REGION='eu-west-1'
|
36
40
|
DESCRIPTION_PREFIX='automatic-backup-'
|
37
41
|
RDS_ROTATOR=/here/is/the/path/to/rds-rotate-db-snapshots
|
38
42
|
DB_NAME='db_name_here'
|
39
43
|
|
40
|
-
$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
|
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
45
|
```
|
42
46
|
|
43
47
|
## Options
|
44
48
|
|
45
49
|
- `--aws-access-key ACCESS_KEY` "AWS Access Key"
|
46
50
|
- `--aws-secret-access-key SECRET_KEY` "AWS Secret Access Key"
|
51
|
+
- `--aws-session-token $AWS_SESSION_TOKEN` "AWS Session Token"
|
47
52
|
- `--aws-region REGION` "AWS Region"
|
48
53
|
- `--pattern STRING` "Snapshots without this string in the description will be ignored"
|
49
54
|
- `--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."
|
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
|
-
|
7
|
-
|
6
|
+
warn e.message
|
7
|
+
warn "Run `bundle install` to install missing gems"
|
8
8
|
exit e.status_code
|
9
9
|
end
|
10
10
|
require 'rake'
|
@@ -14,8 +14,8 @@ 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 = %
|
18
|
-
gem.description = %
|
17
|
+
gem.summary = %(Amazon RDS DB snapshot rotator)
|
18
|
+
gem.description = %(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') : ""
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.2
|
data/bin/rds-rotate-db-snapshots
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
|
3
3
|
require_relative '../lib/rds_rotate_db_snapshots'
|
4
4
|
|
5
|
-
rrds = RdsRotateDbSnapshots.new(script_name: File.basename($
|
5
|
+
rrds = RdsRotateDbSnapshots.new(script_name: File.basename($PROGRAM_NAME), cli: true)
|
6
6
|
|
7
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
|
8
|
+
puts "You must specify your Amazon credentials via --aws-access-key and --aws-secret_access-key and " \
|
9
|
+
"--aws-session-token"
|
9
10
|
exit 1
|
10
11
|
end
|
11
12
|
|
@@ -14,7 +15,7 @@ if rrds.options[:aws_region].nil?
|
|
14
15
|
exit 1
|
15
16
|
end
|
16
17
|
|
17
|
-
if ARGV.empty?
|
18
|
+
if ARGV.empty? && rrds.options[:by_tags].nil?
|
18
19
|
puts "You must provide at least one DB Indentifier when not rotating by tags"
|
19
20
|
exit 1
|
20
21
|
end
|
@@ -23,40 +24,36 @@ if rrds.options[:by_tags].nil?
|
|
23
24
|
db_indentifier_ids = ARGV
|
24
25
|
|
25
26
|
db_indentifier_ids.each do |db_id|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
31
32
|
end
|
32
33
|
else
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
if rrds.options[:by_tags].length == 0
|
34
|
+
puts "Ignoring supplied db_indentifier_ids because we're rotating by tags." unless ARGV.empty?
|
35
|
+
if rrds.options[:by_tags].empty?
|
37
36
|
puts "Rotating by tags but no tags specified? Refusing to rotate all snapshots!"
|
38
37
|
exit 1
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
if rrds.options[:backoff_limit]
|
41
|
+
if rrds.options[:backoff_limit].negative?
|
43
42
|
puts "A negative backoff limit doesn't make much sense."
|
44
43
|
exit 1
|
45
44
|
end
|
46
45
|
|
47
|
-
if rrds.options[:create_snapshot]
|
48
|
-
rrds.create_snapshot(rrds.options[:create_snapshot], db_indentifier_ids)
|
49
|
-
end
|
46
|
+
rrds.create_snapshot(rrds.options[:create_snapshot], db_indentifier_ids) if rrds.options[:create_snapshot]
|
50
47
|
|
51
48
|
all_snapshots = []
|
52
49
|
if rrds.options[:by_tags]
|
53
50
|
rrds.rotate_by_tags
|
54
51
|
else
|
55
|
-
snapshots = rrds.get_db_snapshots(snapshot_type: 'manual').delete_if{ |e| e[:status] != 'available' }
|
52
|
+
snapshots = rrds.get_db_snapshots(snapshot_type: 'manual').delete_if { |e| e[:status] != 'available' }
|
56
53
|
db_indentifier_ids.each do |db_id|
|
57
54
|
rrds.rotate_em(
|
58
|
-
snapshots.select {|ss| ss[:db_instance_identifier] == db_id }
|
59
|
-
sort {|a,b| a[:snapshot_create_time] <=> b[:snapshot_create_time] }
|
55
|
+
snapshots.select { |ss| ss[:db_instance_identifier] == db_id }
|
56
|
+
.sort { |a, b| a[:snapshot_create_time] <=> b[:snapshot_create_time] }
|
60
57
|
)
|
61
58
|
end
|
62
59
|
end
|
@@ -8,18 +8,18 @@ class RdsRotateDbSnapshots
|
|
8
8
|
define_method(m) do |*args|
|
9
9
|
reset_backoff
|
10
10
|
begin
|
11
|
-
super
|
11
|
+
super(*args)
|
12
12
|
rescue Aws::RDS::Errors::ServiceError => e
|
13
13
|
raise if e.is_a? Aws::RDS::Errors::ExpiredToken
|
14
|
+
|
14
15
|
# TODO: re-work
|
15
16
|
puts "Error: #{e}"
|
16
17
|
backoff
|
17
18
|
retry
|
18
19
|
end
|
19
|
-
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
prepend wrapper
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -1,82 +1,41 @@
|
|
1
1
|
class RdsRotateDbSnapshots
|
2
2
|
module Actions
|
3
3
|
def rotate_em(snapshots)
|
4
|
-
# poor man's way to get a deep copy of our time_periods definition hash
|
5
|
-
periods = Marshal.load(Marshal.dump(time_periods))
|
6
|
-
|
7
4
|
snapshots.each do |snapshot|
|
8
5
|
time = snapshot[:snapshot_create_time]
|
9
|
-
db_id = snapshot[:db_instance_identifier]
|
10
6
|
snapshot_id = snapshot[:db_snapshot_identifier]
|
11
7
|
description = snapshot_id
|
12
|
-
|
13
|
-
|
8
|
+
|
14
9
|
if options[:pattern] && description !~ /#{options[:pattern]}/
|
15
10
|
puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Skipping snapshot with description #{description}"
|
16
11
|
next
|
17
12
|
end
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
keeping = period_info[:keeping]
|
23
|
-
|
24
|
-
time_string = time.strftime period_info[:format]
|
25
|
-
if Time.now - time < keep * period_info[:seconds]
|
26
|
-
if !keeping.key?(time_string) && keeping.length < keep
|
27
|
-
keep_reason = period
|
28
|
-
keeping[time_string] = snapshot
|
29
|
-
end
|
30
|
-
break
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
if keep_reason.nil? && snapshot == snapshots.last && options[:keep_last]
|
35
|
-
keep_reason = 'last snapshot'
|
36
|
-
end
|
37
|
-
|
38
|
-
if !keep_reason.nil?
|
39
|
-
puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Keeping for #{keep_reason}"
|
40
|
-
else
|
41
|
-
puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Deleting"
|
42
|
-
begin
|
43
|
-
client.delete_db_snapshot(db_snapshot_identifier: snapshot_id) unless options[:dry_run]
|
44
|
-
rescue Aws::RDS::Errors => e
|
45
|
-
backoff
|
46
|
-
retry
|
47
|
-
end
|
48
|
-
end
|
13
|
+
|
14
|
+
keep_reason = rotate_period_based_decision_with(time, snapshot)
|
15
|
+
keep_reason = 'last snapshot' if keep_reason.nil? && snapshot == snapshots.last && options[:keep_last]
|
16
|
+
rotate_or_keep_snapshot(keep_reason, time, snapshot_id)
|
49
17
|
end
|
50
18
|
end
|
51
|
-
|
19
|
+
|
52
20
|
def create_snapshot(name, db_indentifier_ids)
|
53
|
-
if
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
rescue Aws::RDS::Errors::InvalidDBInstanceStateFault => e
|
62
|
-
backoff
|
63
|
-
retry
|
64
|
-
end
|
65
|
-
end
|
66
|
-
else
|
67
|
-
puts "invalid snapshot name format - #{name}"
|
68
|
-
exit 1
|
69
|
-
end
|
21
|
+
return if name.nil?
|
22
|
+
|
23
|
+
name = name.gsub(/[^a-zA-Z0-9-]/, '')
|
24
|
+
if name.size.positive?
|
25
|
+
create_db_snapshots(name: name, db_indentifier_ids: db_indentifier_ids)
|
26
|
+
else
|
27
|
+
puts "invalid snapshot name format - #{name}"
|
28
|
+
exit 1
|
70
29
|
end
|
71
30
|
end
|
72
|
-
|
31
|
+
|
73
32
|
def get_db_snapshots(options)
|
74
33
|
snapshots = []
|
75
34
|
response = client.describe_db_snapshots(options)
|
76
|
-
|
35
|
+
loop do
|
77
36
|
snapshots += response.db_snapshots
|
78
37
|
break unless response[:marker]
|
79
|
-
|
38
|
+
|
80
39
|
response = client.describe_db_snapshots(options.merge(marker: response[:marker]))
|
81
40
|
end
|
82
41
|
snapshots
|
@@ -86,20 +45,68 @@ class RdsRotateDbSnapshots
|
|
86
45
|
snapshots = []
|
87
46
|
options[:by_tags].each do |tag, value|
|
88
47
|
snapshots = rrds.client.describe_tags(
|
89
|
-
|
90
|
-
|
48
|
+
snapshot_type: 'manual', filters: { 'resource-type' => "snapshot", 'key' => tag, 'value' => value }
|
49
|
+
).delete_if { |e| e.status != 'available' }
|
91
50
|
# TODO: re-work
|
92
|
-
if snapshots.
|
51
|
+
if snapshots.empty?
|
93
52
|
puts "(tag,value)=(#{tag},#{value}) found no snapshots; nothing to rotate!"
|
94
53
|
exit 0
|
95
54
|
end
|
96
55
|
end
|
97
56
|
|
98
|
-
snapshots = get_db_snapshots(db_instance_identifier: snapshots.map(&:db_instance_identifier).uniq)
|
99
|
-
|
100
|
-
|
57
|
+
snapshots = get_db_snapshots(db_instance_identifier: snapshots.map(&:db_instance_identifier).uniq)
|
58
|
+
.delete_if { |e| !snapshots.include?(e.db_snapshot_identifier) }
|
59
|
+
.sort { |a, b| a[:snapshot_create_time] <=> b[:snapshot_create_time] }
|
101
60
|
|
102
61
|
rotate_em snapshots
|
103
62
|
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def rotate_period_based_decision_with(time, snapshot)
|
67
|
+
# poor man's way to get a deep copy of our time_periods definition hash
|
68
|
+
periods = Marshal.load(Marshal.dump(time_periods))
|
69
|
+
keep_reason = nil
|
70
|
+
|
71
|
+
periods.keys.sort { |a, b| periods[a][:seconds] <=> periods[b][:seconds] }.each do |period|
|
72
|
+
period_info = periods[period]
|
73
|
+
keep = period_info[:keep]
|
74
|
+
keeping = period_info[:keeping]
|
75
|
+
|
76
|
+
time_string = time.strftime period_info[:format]
|
77
|
+
next unless Time.now - time < keep * period_info[:seconds]
|
78
|
+
|
79
|
+
if !keeping.key?(time_string) && keeping.length < keep
|
80
|
+
keep_reason = period
|
81
|
+
keeping[time_string] = snapshot
|
82
|
+
end
|
83
|
+
break
|
84
|
+
end
|
85
|
+
|
86
|
+
keep_reason
|
87
|
+
end
|
88
|
+
|
89
|
+
def rotate_or_keep_snapshot(keep_reason, time, snapshot_id)
|
90
|
+
if keep_reason.nil?
|
91
|
+
puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Deleting"
|
92
|
+
client.delete_db_snapshot(db_snapshot_identifier: snapshot_id) unless options[:dry_run]
|
93
|
+
else
|
94
|
+
puts " #{time.strftime '%Y-%m-%d %H:%M:%S'} #{snapshot_id} Keeping for #{keep_reason}"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_db_snapshots(name:, db_indentifier_ids:)
|
99
|
+
name = "#{name}-#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
100
|
+
db_indentifier_ids.each do |db_id|
|
101
|
+
unless options[:dry_run]
|
102
|
+
client.create_db_snapshot(db_snapshot_identifier: name,
|
103
|
+
db_instance_identifier: db_id)
|
104
|
+
end
|
105
|
+
puts " #{Time.now.strftime '%Y-%m-%d %H:%M:%S'} Creation snapshot #{name} is pending (db: #{db_id})"
|
106
|
+
rescue Aws::RDS::Errors::InvalidDBInstanceStateFault
|
107
|
+
backoff
|
108
|
+
retry
|
109
|
+
end
|
110
|
+
end
|
104
111
|
end
|
105
112
|
end
|