data_keeper 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -11
- data/data_keeper.gemspec +1 -2
- data/lib/data_keeper/s3_storage.rb +103 -0
- data/lib/data_keeper/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 268e784853f728ad8c4cefd36ca8cc2f09b2892ab8751f1eb0f16dc17bc72900
|
4
|
+
data.tar.gz: 62ea9b6a3bf57ae952417db4fd149365f56f4baf63f67839bde26d3d2f352464
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ea7c0182fb8698c7d9c2be973cf7d3def1845222027feb90107adda8d333488ef01318268f8ae1356c2bd45d89419cb908443b5a9037df359cf5fc63376fca7
|
7
|
+
data.tar.gz: 7110186baac099fe5ce341186b25594c4ad730a811bc4270c4cd8e1d14d3cf4858bce5eb8bed0e621152da6d5729223c4d47c4f74b8e558c9539bb5bfcecd0c1
|
data/README.md
CHANGED
@@ -36,23 +36,37 @@ order to download these dumps later. Ex:
|
|
36
36
|
DataKeeper.storage = DataKeeper::LocalStorage.new(
|
37
37
|
local_store_dir: "/users/fredy/backups/...",
|
38
38
|
remote_access: {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
user: "fredy"
|
39
|
+
host: "10.10.10.10",
|
40
|
+
port: "22",
|
41
|
+
user: "user"
|
43
42
|
}
|
44
43
|
)
|
45
44
|
```
|
46
45
|
|
47
|
-
|
48
|
-
If you want to do your own, you can assign as an storage whatever object that responds to:
|
46
|
+
There's also support for storing the dumps in s3, using `DataKeeper::S3Storage` like in this example:
|
49
47
|
|
50
|
-
|
51
|
-
|
48
|
+
```ruby
|
49
|
+
DataKeeper.storage = DataKeeper::S3Storage.new(
|
50
|
+
bucket: 'bucket-name',
|
51
|
+
store_dir: 'dumps/',
|
52
|
+
acl: "private",
|
53
|
+
remote_access: {
|
54
|
+
access_key_id: Rails.application.credentials.access_key_id,
|
55
|
+
secret_access_key: Rails.application.credentials.secret_access_key,
|
56
|
+
region: 'eu-central-1'
|
57
|
+
}
|
58
|
+
)
|
59
|
+
```
|
60
|
+
|
61
|
+
|
62
|
+
Other storages can be implemented. An storage can be any object that responds to those two methods:
|
63
|
+
|
64
|
+
- `#save(file, filename, dump_name)`, where file is a File object and filename and dump_name are strings.
|
65
|
+
This method should save the given dump file in the store.
|
52
66
|
|
53
67
|
- `#retrieve(dump_name) { |file| (...) }`, which should retrieve the latest stored dump with the given dump_name.
|
54
|
-
It should yield the given block passing the File object pointing to the retrieved dump
|
55
|
-
which is expected to be cleaned up on block termination.
|
68
|
+
It should yield the given block passing the `File` or `Tempfile` object pointing to the retrieved dump
|
69
|
+
file in the local filesystem, which is expected to be cleaned up on block termination.
|
56
70
|
|
57
71
|
|
58
72
|
Then, declare some dumps to work with:
|
@@ -101,7 +115,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
101
115
|
|
102
116
|
## Contributing
|
103
117
|
|
104
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
118
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rogercampos/data_keeper.
|
105
119
|
|
106
120
|
|
107
121
|
## License
|
data/data_keeper.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = %q{Easy management of database dumps for dev env}
|
11
11
|
spec.homepage = "https://github.com/rogercampos/data_keeper"
|
12
12
|
spec.license = "MIT"
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
14
14
|
|
15
15
|
spec.metadata["homepage_uri"] = spec.homepage
|
16
16
|
|
@@ -27,5 +27,4 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_dependency "terrapin", ">= 0.5.0"
|
28
28
|
spec.add_dependency "sshkit", ">= 1.20.0"
|
29
29
|
spec.add_dependency "rails", ">= 5.0.0"
|
30
|
-
|
31
30
|
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
begin
|
2
|
+
require 'aws-sdk-s3'
|
3
|
+
rescue LoadError
|
4
|
+
raise "You must include the 'aws-sdk-s3' gem in your Gemfile in order to use this s3 storage."
|
5
|
+
end
|
6
|
+
|
7
|
+
module DataKeeper
|
8
|
+
class S3Storage
|
9
|
+
class Client
|
10
|
+
NoSuchKey = Class.new(StandardError)
|
11
|
+
|
12
|
+
def initialize(client_options:, bucket: nil)
|
13
|
+
@client_options = client_options
|
14
|
+
@client = Aws::S3::Client.new(client_options)
|
15
|
+
@bucket = bucket
|
16
|
+
end
|
17
|
+
|
18
|
+
def delete_files(file_paths)
|
19
|
+
@client.delete_objects(
|
20
|
+
bucket: @bucket,
|
21
|
+
delete: {
|
22
|
+
objects: file_paths.map { |key| { key: key } }
|
23
|
+
}
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def list_contents(prefix = '')
|
28
|
+
@client.list_objects(bucket: @bucket, prefix: prefix).contents
|
29
|
+
rescue Aws::S3::Errors::NoSuchKey
|
30
|
+
raise NoSuchKey, prefix
|
31
|
+
end
|
32
|
+
|
33
|
+
# Streams all contents from `path` into the provided io object, calling #write to it.
|
34
|
+
# io can be a File, or any other IO-like object.
|
35
|
+
def stream_to_io(path, io, opts = {})
|
36
|
+
@client.get_object(opts.merge(
|
37
|
+
bucket: @bucket,
|
38
|
+
key: path
|
39
|
+
), target: io)
|
40
|
+
rescue Aws::S3::Errors::NoSuchKey
|
41
|
+
raise NoSuchKey, path
|
42
|
+
end
|
43
|
+
|
44
|
+
# Uploads the given file into the target_path in the s3 bucket.
|
45
|
+
# `file` must be a file stored locally. Can be either a raw string (path),
|
46
|
+
# or a File/Tempfile object (close is up to you).
|
47
|
+
def put_file(target_path, file, options = {})
|
48
|
+
file.rewind if file.respond_to?(:rewind)
|
49
|
+
|
50
|
+
s3 = Aws::S3::Resource.new(@client_options)
|
51
|
+
obj = s3.bucket(@bucket).object(target_path)
|
52
|
+
obj.upload_file(file, options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize(bucket:, store_dir:, remote_access:, acl: "public-read", keep_amount: 3)
|
57
|
+
@bucket = bucket
|
58
|
+
@store_dir = store_dir
|
59
|
+
@remote_access = remote_access
|
60
|
+
@acl = acl
|
61
|
+
@keep_amount = keep_amount
|
62
|
+
end
|
63
|
+
|
64
|
+
def save(file, filename, dump_name)
|
65
|
+
path = dump_path(dump_name, filename)
|
66
|
+
|
67
|
+
s3_client.put_file(path, file, acl: @acl)
|
68
|
+
|
69
|
+
prefix = "#{@store_dir}#{dump_name.to_s}"
|
70
|
+
|
71
|
+
keys_to_delete = s3_client.list_contents(prefix).sort_by(&:last_modified).reverse[@keep_amount..-1]
|
72
|
+
|
73
|
+
return unless keys_to_delete
|
74
|
+
|
75
|
+
s3_client.delete_files(keys_to_delete.map(&:key))
|
76
|
+
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def retrieve(dump_name)
|
81
|
+
prefix = "#{@store_dir}#{dump_name.to_s}"
|
82
|
+
last_dump = s3_client.list_contents(prefix).sort_by(&:last_modified).reverse.first
|
83
|
+
|
84
|
+
Tempfile.create do |tmp_file|
|
85
|
+
tmp_file.binmode
|
86
|
+
s3_client.stream_to_io(last_dump.key, tmp_file)
|
87
|
+
tmp_file.flush
|
88
|
+
|
89
|
+
yield(tmp_file)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def s3_client
|
96
|
+
@s3_client ||= Client.new(bucket: @bucket, client_options: @remote_access)
|
97
|
+
end
|
98
|
+
|
99
|
+
def dump_path(dump_name, filename)
|
100
|
+
File.join(@store_dir, dump_name.to_s, "#{SecureRandom.alphanumeric(40)}-#{filename}")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/data_keeper/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: data_keeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roger Campos
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- lib/data_keeper/loader.rb
|
92
92
|
- lib/data_keeper/local_storage.rb
|
93
93
|
- lib/data_keeper/railtie.rb
|
94
|
+
- lib/data_keeper/s3_storage.rb
|
94
95
|
- lib/data_keeper/tasks/data_keeper.rake
|
95
96
|
- lib/data_keeper/version.rb
|
96
97
|
- todo.md
|
@@ -107,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
108
|
requirements:
|
108
109
|
- - ">="
|
109
110
|
- !ruby/object:Gem::Version
|
110
|
-
version: 2.
|
111
|
+
version: 2.5.0
|
111
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
113
|
requirements:
|
113
114
|
- - ">="
|