s3_rotate 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +55 -0
- data/LICENSE +21 -0
- data/README.md +241 -0
- data/examples/example.rb +7 -0
- data/lib/s3_rotate.rb +4 -0
- data/lib/s3_rotate/aws/s3_client.rb +93 -0
- data/lib/s3_rotate/core/backup_manager.rb +62 -0
- data/lib/s3_rotate/core/backup_rotator.rb +239 -0
- data/lib/s3_rotate/core/backup_uploader.rb +60 -0
- data/lib/s3_rotate/utils/file_utils.rb +65 -0
- data/s3_rotate.gemspec +15 -0
- data/spec/s3_rotate/aws/s3_client_spec.rb +128 -0
- data/spec/s3_rotate/core/backup_manager_spec.rb +56 -0
- data/spec/s3_rotate/core/backup_rotator_spec.rb +681 -0
- data/spec/s3_rotate/core/backup_uploader_spec.rb +145 -0
- data/spec/s3_rotate/utils/file_utils_spec.rb +61 -0
- data/spec/s3_rotate/utils/mock/backup-2020-01-02.test +0 -0
- data/spec/s3_rotate/utils/mock/backup-2020-01-03.test +0 -0
- data/spec/s3_rotate/utils/mock/backup-2020-02-01.test +0 -0
- data/spec/s3_rotate/utils/mock/backup-2021-01-01.test +0 -0
- data/spec/spec_helper.rb +15 -0
- metadata +76 -0
@@ -0,0 +1,145 @@
|
|
1
|
+
# standard
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
# 3rd part
|
5
|
+
require 'fog-aws'
|
6
|
+
|
7
|
+
# s3_rotate
|
8
|
+
require File.expand_path("../../../../lib/s3_rotate/core/backup_uploader", __FILE__)
|
9
|
+
require File.expand_path("../../../../lib/s3_rotate/utils/file_utils", __FILE__)
|
10
|
+
|
11
|
+
describe S3Rotate::BackupUploader do
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
@client = S3Rotate::S3Client.new('key', 'secret', 'bucket', 'region')
|
15
|
+
@uploader = S3Rotate::BackupUploader.new(@client)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#initialize' do
|
19
|
+
|
20
|
+
it 'sets the client' do
|
21
|
+
expect(@uploader.s3_client).not_to eq nil
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#upload' do
|
27
|
+
|
28
|
+
it 'uploads all the new files until reaching an already uploaded file' do
|
29
|
+
# mock
|
30
|
+
@client.connection.directories.get('bucket').files.create(key: '/backup_name/daily/2020-01-02.tgz', body: 'some data')
|
31
|
+
@client.connection.directories.get('bucket').files.create(key: '/backup_name/daily/2020-01-03.tgz', body: 'some data')
|
32
|
+
@client.connection.directories.get('bucket').files.create(key: '/backup_name/daily/2020-01-04.tgz', body: 'some data')
|
33
|
+
@client.connection.directories.get('bucket').files.create(key: '/backup_name/weekly/2020-01-05.tgz', body: 'some data')
|
34
|
+
@client.connection.directories.get('bucket').files.create(key: '/backup_name/monthly/2020-01-06.tgz', body: 'some data')
|
35
|
+
@client.connection.directories.get('bucket').files.create(key: '/other_backup_name/daily/2020-01-07.tgz', body: 'some data')
|
36
|
+
|
37
|
+
allow(S3Rotate::FileUtils).to receive(:date_from_filename).and_call_original
|
38
|
+
allow(S3Rotate::FileUtils).to receive(:extension_from_filename).and_call_original
|
39
|
+
allow(S3Rotate::FileUtils).to receive(:files_in_directory).with('/path/to/dir').and_return([
|
40
|
+
'some-backup-2020-01-01.tgz',
|
41
|
+
'some-backup-2020-01-02.tgz',
|
42
|
+
'some-backup-2020-01-03.tgz',
|
43
|
+
'some-backup-2020-01-04.tgz',
|
44
|
+
'some-backup-2020-01-05.tgz',
|
45
|
+
'some-backup-2020-01-06.tgz',
|
46
|
+
'some-backup-2020-01-07.tgz'
|
47
|
+
])
|
48
|
+
allow(@client).to receive(:upload_local_backup_to_s3).and_return nil
|
49
|
+
allow(File).to receive(:open).and_return "raw_data"
|
50
|
+
|
51
|
+
# perform test
|
52
|
+
@uploader.upload('backup_name', '/path/to/dir')
|
53
|
+
|
54
|
+
# verify result
|
55
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).exactly(3)
|
56
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 7), 'daily', '.tgz', 'raw_data')
|
57
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 6), 'daily', '.tgz', 'raw_data')
|
58
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 5), 'daily', '.tgz', 'raw_data')
|
59
|
+
|
60
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).exactly(4)
|
61
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-07.tgz', /\d{4}-\d{2}-\d{2}/)
|
62
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-06.tgz', /\d{4}-\d{2}-\d{2}/)
|
63
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-05.tgz', /\d{4}-\d{2}-\d{2}/)
|
64
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-04.tgz', /\d{4}-\d{2}-\d{2}/)
|
65
|
+
|
66
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).exactly(4)
|
67
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-07.tgz')
|
68
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-06.tgz')
|
69
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-05.tgz')
|
70
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-04.tgz')
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'uploads files without extensions' do
|
74
|
+
# mock
|
75
|
+
allow(S3Rotate::FileUtils).to receive(:date_from_filename).and_call_original
|
76
|
+
allow(S3Rotate::FileUtils).to receive(:extension_from_filename).and_return nil
|
77
|
+
allow(S3Rotate::FileUtils).to receive(:files_in_directory).with('/path/to/dir').and_return([
|
78
|
+
'some-backup-2020-01-01.tgz',
|
79
|
+
'some-backup-2020-01-02.tgz',
|
80
|
+
'some-backup-2020-01-03.tgz',
|
81
|
+
])
|
82
|
+
allow(@client).to receive(:upload_local_backup_to_s3).and_return nil
|
83
|
+
allow(File).to receive(:open).and_return "raw_data"
|
84
|
+
|
85
|
+
# perform test
|
86
|
+
@uploader.upload('backup_name', '/path/to/dir')
|
87
|
+
|
88
|
+
# verify result
|
89
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).exactly(3)
|
90
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 3), 'daily', nil, 'raw_data')
|
91
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 2), 'daily', nil, 'raw_data')
|
92
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 1), 'daily', nil, 'raw_data')
|
93
|
+
|
94
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).exactly(3)
|
95
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-03.tgz', /\d{4}-\d{2}-\d{2}/)
|
96
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-02.tgz', /\d{4}-\d{2}-\d{2}/)
|
97
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-01.tgz', /\d{4}-\d{2}-\d{2}/)
|
98
|
+
|
99
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).exactly(3)
|
100
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-03.tgz')
|
101
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-02.tgz')
|
102
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-01.tgz')
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'does not upload files with broken date' do
|
106
|
+
# mock
|
107
|
+
original_date_from_filename = S3Rotate::FileUtils.method(:date_from_filename)
|
108
|
+
allow(S3Rotate::FileUtils).to receive(:date_from_filename) do |filename, date_regex|
|
109
|
+
if filename == 'some-backup-2020-01-02.tgz'
|
110
|
+
nil
|
111
|
+
else
|
112
|
+
original_date_from_filename.call(filename, date_regex)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
allow(S3Rotate::FileUtils).to receive(:extension_from_filename).and_call_original
|
116
|
+
allow(S3Rotate::FileUtils).to receive(:files_in_directory).with('/path/to/dir').and_return([
|
117
|
+
'some-backup-2020-01-01.tgz',
|
118
|
+
'some-backup-2020-01-02.tgz',
|
119
|
+
'some-backup-2020-01-03.tgz',
|
120
|
+
])
|
121
|
+
allow(@client).to receive(:upload_local_backup_to_s3).and_return nil
|
122
|
+
allow(File).to receive(:open).and_return "raw_data"
|
123
|
+
|
124
|
+
# perform test
|
125
|
+
@uploader.upload('backup_name', '/path/to/dir')
|
126
|
+
|
127
|
+
# verify result
|
128
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).exactly(2)
|
129
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 3), 'daily', '.tgz', 'raw_data')
|
130
|
+
expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 1), 'daily', '.tgz', 'raw_data')
|
131
|
+
|
132
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).exactly(3)
|
133
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-03.tgz', /\d{4}-\d{2}-\d{2}/)
|
134
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-02.tgz', /\d{4}-\d{2}-\d{2}/)
|
135
|
+
expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-01.tgz', /\d{4}-\d{2}-\d{2}/)
|
136
|
+
|
137
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).exactly(3)
|
138
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-03.tgz')
|
139
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-02.tgz')
|
140
|
+
expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-01.tgz')
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# standard
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
# s3_rotate
|
5
|
+
require File.expand_path("../../../../lib/s3_rotate/utils/file_utils", __FILE__)
|
6
|
+
|
7
|
+
describe S3Rotate::FileUtils do
|
8
|
+
|
9
|
+
describe '#date_from_filename' do
|
10
|
+
|
11
|
+
it 'parses Date.parse formats' do
|
12
|
+
expect(S3Rotate::FileUtils::date_from_filename("/path/to/file-2020-12-13-backup.tar.gz")).to eq Date.new(2020, 12, 13)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'parses timestamp formats' do
|
16
|
+
expect(S3Rotate::FileUtils::date_from_filename("/path/to/file-1580098737-backup.tar.gz", /file-(\d+)-backup.tar.gz/)).to eq Date.new(2020, 1, 27)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'raises if the regex matched nothing' do
|
20
|
+
expect{ S3Rotate::FileUtils::date_from_filename("/path/to/file-1580098737-backup.tar.gz") }.to raise_error(RuntimeError, "Invalid date_regex or filename format")
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises if the regex matched nothing' do
|
24
|
+
expect{ S3Rotate::FileUtils::date_from_filename("/path/to/file-1580098737-backup.tar.gz", /file-\d+-backup.tar.gz/) }.to raise_error(RuntimeError, "Date format not supported")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#extension_from_filename' do
|
30
|
+
|
31
|
+
it 'handles no extension' do
|
32
|
+
expect(S3Rotate::FileUtils::extension_from_filename("backup")).to eq nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'handles short extension' do
|
36
|
+
expect(S3Rotate::FileUtils::extension_from_filename("backup.tgz")).to eq '.tgz'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'handles long extension' do
|
40
|
+
expect(S3Rotate::FileUtils::extension_from_filename("backup.tar.gz.1")).to eq '.tar.gz.1'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'handles absolute paths' do
|
44
|
+
expect(S3Rotate::FileUtils::extension_from_filename("/path/to.file/backup.tar.gz.1")).to eq '.tar.gz.1'
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'files_in_directory' do
|
50
|
+
|
51
|
+
it 'returns the directory files ordered ASC' do
|
52
|
+
expect(S3Rotate::FileUtils::files_in_directory("#{__dir__}/mock")).to eq [ "backup-2020-01-02.test", "backup-2020-01-03.test", "backup-2020-02-01.test", "backup-2021-01-01.test" ]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'raises for invalid directories' do
|
56
|
+
expect{ S3Rotate::FileUtils::files_in_directory("/invalid/path") }.to raise_error(RuntimeError, "Invalid directory /invalid/path")
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
RSpec.configure do |c|
|
2
|
+
|
3
|
+
c.before :each do
|
4
|
+
Fog.mock!
|
5
|
+
|
6
|
+
fog = Fog::Storage.new(aws_access_key_id: 'key', aws_secret_access_key: 'secret', provider: 'AWS', region: 'region')
|
7
|
+
fog.directories.create(key: 'bucket')
|
8
|
+
end
|
9
|
+
|
10
|
+
c.after :each do
|
11
|
+
Fog::Mock.reset
|
12
|
+
Fog.unmock!
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: s3_rotate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simon Ninon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-01-27 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: AWS S3 upload with rotation mechanism
|
14
|
+
email: simon.ninon@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- ".gitignore"
|
20
|
+
- ".rspec"
|
21
|
+
- Gemfile
|
22
|
+
- Gemfile.lock
|
23
|
+
- LICENSE
|
24
|
+
- README.md
|
25
|
+
- examples/example.rb
|
26
|
+
- lib/s3_rotate.rb
|
27
|
+
- lib/s3_rotate/aws/s3_client.rb
|
28
|
+
- lib/s3_rotate/core/backup_manager.rb
|
29
|
+
- lib/s3_rotate/core/backup_rotator.rb
|
30
|
+
- lib/s3_rotate/core/backup_uploader.rb
|
31
|
+
- lib/s3_rotate/utils/file_utils.rb
|
32
|
+
- s3_rotate.gemspec
|
33
|
+
- spec/s3_rotate/aws/s3_client_spec.rb
|
34
|
+
- spec/s3_rotate/core/backup_manager_spec.rb
|
35
|
+
- spec/s3_rotate/core/backup_rotator_spec.rb
|
36
|
+
- spec/s3_rotate/core/backup_uploader_spec.rb
|
37
|
+
- spec/s3_rotate/utils/file_utils_spec.rb
|
38
|
+
- spec/s3_rotate/utils/mock/backup-2020-01-02.test
|
39
|
+
- spec/s3_rotate/utils/mock/backup-2020-01-03.test
|
40
|
+
- spec/s3_rotate/utils/mock/backup-2020-02-01.test
|
41
|
+
- spec/s3_rotate/utils/mock/backup-2021-01-01.test
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
homepage: https://github.com/Whova/s3_rotate
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubygems_version: 3.0.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: AWS S3 upload with rotation mechanism
|
66
|
+
test_files:
|
67
|
+
- spec/s3_rotate/aws/s3_client_spec.rb
|
68
|
+
- spec/s3_rotate/core/backup_manager_spec.rb
|
69
|
+
- spec/s3_rotate/core/backup_rotator_spec.rb
|
70
|
+
- spec/s3_rotate/core/backup_uploader_spec.rb
|
71
|
+
- spec/s3_rotate/utils/file_utils_spec.rb
|
72
|
+
- spec/s3_rotate/utils/mock/backup-2020-01-02.test
|
73
|
+
- spec/s3_rotate/utils/mock/backup-2020-01-03.test
|
74
|
+
- spec/s3_rotate/utils/mock/backup-2020-02-01.test
|
75
|
+
- spec/s3_rotate/utils/mock/backup-2021-01-01.test
|
76
|
+
- spec/spec_helper.rb
|