rds-rotate-db-snapshots 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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) [![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)
|
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
|