trashman 0.1.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 +7 -0
- data/.gitignore +8 -0
- data/.rspec +2 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +65 -0
- data/Rakefile +10 -0
- data/bin/trashman +9 -0
- data/lib/trashman/cli.rb +46 -0
- data/lib/trashman/manager.rb +49 -0
- data/lib/trashman/version_number.rb +18 -0
- data/lib/trashman.rb +5 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/trashman/cli_spec.rb +11 -0
- data/spec/trashman/manager_spec.rb +63 -0
- data/spec/trashman_spec.rb +7 -0
- data/trashman.gemspec +28 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9d5a7113f4f529dd666222dbed4816841d66e97d
|
4
|
+
data.tar.gz: 7ad829a02a4b986b99a4333cabc5612b3d047b6c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff9ea4453ea673b1e35883da5d29855da00cd374335f02d2a122bf1f453b11edfe83bdd20f6c812d4cf372e422af57bad94f9504897a0f55412d77bbbdfefc7d
|
7
|
+
data.tar.gz: cb60bbbf0a9c0db585952964315bdc7f47ccd0396f0e8e62208f2a27f0673e9e433b1a934d4fbf54f7b743aa6dbc5412b5dae03b4bd6df7304315872ca32b0da
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Ideal Project Group
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# TrashMan
|
2
|
+
|
3
|
+
Removes outdated periodic backup files from your cloud storage bucket.
|
4
|
+
|
5
|
+
## Install
|
6
|
+
|
7
|
+
Into Gemfile from rubygems.org:
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install trashman
|
11
|
+
```
|
12
|
+
|
13
|
+
## Note
|
14
|
+
|
15
|
+
This gem assumes your filenames include a date and time e.g. backup.2015-07-07T10-32-01.tar.gz.
|
16
|
+
|
17
|
+
```
|
18
|
+
backup.$(date +'\%Y-\%m-\%dT\%H-\%M-\%S').tar.gz
|
19
|
+
```
|
20
|
+
|
21
|
+
Please use the `--dry-run` option to test your configuration before using trashman.
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
trashman is best used as a cronjob. It assumes you have a cloud storage bucket where you store periodic backups with conventional filenames including date and time.
|
26
|
+
|
27
|
+
To destroy outdated backups:
|
28
|
+
|
29
|
+
```
|
30
|
+
trashman prune --provider <FOG PROVIDER> --keep <NUMBER OF FILES TO KEEP> --container <CONTAINER/BUCKET> --credentials username:<USERNAME> password:<PASSWORD>
|
31
|
+
|
32
|
+
trashman prune --provider rackspace --keep 100 --container "Test Container" --credentials rackspace_api_key:abc123 rackspace_username:example rackspace_region:ord
|
33
|
+
|
34
|
+
trashman help prune
|
35
|
+
|
36
|
+
Usage:
|
37
|
+
trashman prune --credentials=key:value -P, --provider=PROVIDER -c, --container=CONTAINER
|
38
|
+
|
39
|
+
Options:
|
40
|
+
-P, --provider=PROVIDER # A valid fog provider e.g. rackspace, aws, etc.
|
41
|
+
-c, --container=CONTAINER # Container or bucket on fog provider.
|
42
|
+
-k, [--keep=N] # Number of files to keep.
|
43
|
+
# Default: 100
|
44
|
+
--credentials=key:value # Credentials for your fog provider (depends on fog provider).
|
45
|
+
[--dry-run], [--no-dry-run] # As normal, but it does not destroy old backups.
|
46
|
+
```
|
47
|
+
|
48
|
+
## Contributors
|
49
|
+
|
50
|
+
Many thanks to:
|
51
|
+
|
52
|
+
- [Bruno Sutic](https://github.com/bruno-)
|
53
|
+
|
54
|
+
## How to contribute
|
55
|
+
|
56
|
+
1. Fork it
|
57
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
58
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
59
|
+
4. Write your tests and check everything passes
|
60
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
6. Create new Pull Request (into the master branch)
|
62
|
+
|
63
|
+
## License
|
64
|
+
|
65
|
+
Please refer to [LICENSE.md](https://github.com/idealprojectgroup/trashman/blob/master/LICENSE).
|
data/Rakefile
ADDED
data/bin/trashman
ADDED
data/lib/trashman/cli.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'trashman'
|
3
|
+
require 'trashman/manager'
|
4
|
+
|
5
|
+
module TrashMan
|
6
|
+
class CLI < ::Thor
|
7
|
+
|
8
|
+
desc "prune", "Prunes old backups."
|
9
|
+
method_option :provider, type: :string, aliases: %w(-P),
|
10
|
+
required: true,
|
11
|
+
desc: "A valid fog provider e.g. rackspace, aws, etc."
|
12
|
+
method_option :container, type: :string, aliases: %w(-c),
|
13
|
+
required: true,
|
14
|
+
desc: "Container or bucket on fog provider."
|
15
|
+
method_option :keep, type: :numeric, aliases: %w(-k),
|
16
|
+
default: 100,
|
17
|
+
desc: "Number of files to keep."
|
18
|
+
method_option :credentials, type: :hash, required: true,
|
19
|
+
desc: "Credentials for your fog provider (depends on fog provider)."
|
20
|
+
method_option :dry_run, type: :boolean, default: false,
|
21
|
+
desc: "As normal, but it does not destroy old backups."
|
22
|
+
def prune
|
23
|
+
if options.dry_run
|
24
|
+
say "This is a dry-run. No files will be deleted."
|
25
|
+
end
|
26
|
+
|
27
|
+
manager = TrashMan::Manager.new(options.provider, options)
|
28
|
+
count = manager.cleanup! do |file|
|
29
|
+
say " -- deleting #{file.key}", :yellow
|
30
|
+
end
|
31
|
+
|
32
|
+
if options.dry_run
|
33
|
+
say "This was a dry-run. No files were deleted."
|
34
|
+
else
|
35
|
+
say "#{count} file(s) deleted.", :green
|
36
|
+
end
|
37
|
+
# This seems dirty.
|
38
|
+
# However, if the Fog::Storage provider throws any error,
|
39
|
+
# the user will be notified. Errors can be related to
|
40
|
+
# authentication, nonexistent bucket, etc.
|
41
|
+
rescue => e
|
42
|
+
say e.message
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'fog'
|
2
|
+
require 'trashman'
|
3
|
+
|
4
|
+
module TrashMan
|
5
|
+
class Manager
|
6
|
+
def initialize(provider, options = {})
|
7
|
+
@options = options
|
8
|
+
|
9
|
+
@connection = Fog::Storage.new(
|
10
|
+
{ provider: provider }.merge(options[:credentials])
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def cleanup!(&block)
|
15
|
+
queued_files.each do |file|
|
16
|
+
yield(file) if block
|
17
|
+
|
18
|
+
if !options[:dry_run]
|
19
|
+
file.destroy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
queued_files.count
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def options
|
29
|
+
@options
|
30
|
+
end
|
31
|
+
|
32
|
+
def connection
|
33
|
+
@connection
|
34
|
+
end
|
35
|
+
|
36
|
+
def container
|
37
|
+
@container ||= connection.directories.get(options[:container])
|
38
|
+
end
|
39
|
+
|
40
|
+
def files
|
41
|
+
@files ||= container.files.sort_by { |file| file.key }
|
42
|
+
end
|
43
|
+
|
44
|
+
def queued_files
|
45
|
+
files[0...(- options[:keep])]
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/trashman.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'trashman'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.expect_with :rspec do |expectations|
|
6
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
7
|
+
end
|
8
|
+
|
9
|
+
config.mock_with :rspec do |mocks|
|
10
|
+
mocks.verify_partial_doubles = true
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'trashman/manager'
|
3
|
+
|
4
|
+
class MockFogFile < Struct.new(:key)
|
5
|
+
def destroy
|
6
|
+
true
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class MockFogContainer
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
def files
|
14
|
+
@files ||= [
|
15
|
+
MockFogFile.new("backup.2015-01-01T10-00-01.tar.gz"),
|
16
|
+
MockFogFile.new("backup.2015-01-02T10-00-01.tar.gz"),
|
17
|
+
MockFogFile.new("backup.2015-01-03T10-00-01.tar.gz"),
|
18
|
+
MockFogFile.new("backup.2015-01-04T10-00-01.tar.gz"),
|
19
|
+
MockFogFile.new("backup.2015-01-05T10-00-01.tar.gz"),
|
20
|
+
]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class MockFogDirectories
|
25
|
+
def get(container)
|
26
|
+
MockFogContainer.instance
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class MockFogConnection
|
31
|
+
def directories
|
32
|
+
MockFogDirectories.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe TrashMan::Manager do
|
37
|
+
describe "#cleanup!" do
|
38
|
+
before do
|
39
|
+
# Provide a mock fog connection
|
40
|
+
allow(Fog::Storage).to receive(:new).with(
|
41
|
+
{ provider: "rackspace" }
|
42
|
+
).and_return(MockFogConnection.new)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "yields to block" do
|
46
|
+
expect { |b| TrashMan::Manager.new("rackspace", { credentials: {}, keep: 4 }).cleanup!(&b) }.to yield_with_args(MockFogContainer.instance.files.first)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "destroys correct number of files based on the keep setting" do
|
50
|
+
expect(MockFogContainer.instance.files[0]).to receive(:destroy)
|
51
|
+
expect(MockFogContainer.instance.files[1]).to receive(:destroy)
|
52
|
+
|
53
|
+
count = TrashMan::Manager.new("rackspace", { credentials: {}, keep: 3 }).cleanup!
|
54
|
+
expect(count).to eq 2
|
55
|
+
end
|
56
|
+
|
57
|
+
it "skips destruction if dry_run is enabled" do
|
58
|
+
expect_any_instance_of(MockFogFile).to_not receive(:destroy)
|
59
|
+
|
60
|
+
TrashMan::Manager.new("rackspace", { credentials: {}, keep: 3, dry_run: true }).cleanup!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/trashman.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'trashman/version_number'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'trashman'
|
6
|
+
s.version = TrashMan.version
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.summary = "Removes outdated periodic backup files from your cloud storage bucket"
|
9
|
+
s.description = s.summary
|
10
|
+
s.authors = ["Derek Hopper"]
|
11
|
+
s.email = 'hopper.derek@gmail.com'
|
12
|
+
s.homepage = 'http://github.com/idealprojectgroup/trashman'
|
13
|
+
s.license = 'MIT'
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
|
20
|
+
s.required_rubygems_version = '>= 1.3.6'
|
21
|
+
s.required_ruby_version = '>= 1.9'
|
22
|
+
|
23
|
+
s.add_dependency('thor', '~> 0.19')
|
24
|
+
s.add_dependency('fog', '~> 1.34')
|
25
|
+
|
26
|
+
s.add_development_dependency('rspec', '~> 3.0')
|
27
|
+
s.add_development_dependency('rake')
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: trashman
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Derek Hopper
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.19'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.19'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: fog
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.34'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.34'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Removes outdated periodic backup files from your cloud storage bucket
|
70
|
+
email: hopper.derek@gmail.com
|
71
|
+
executables:
|
72
|
+
- trashman
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".rspec"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- bin/trashman
|
83
|
+
- lib/trashman.rb
|
84
|
+
- lib/trashman/cli.rb
|
85
|
+
- lib/trashman/manager.rb
|
86
|
+
- lib/trashman/version_number.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
- spec/trashman/cli_spec.rb
|
89
|
+
- spec/trashman/manager_spec.rb
|
90
|
+
- spec/trashman_spec.rb
|
91
|
+
- trashman.gemspec
|
92
|
+
homepage: http://github.com/idealprojectgroup/trashman
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '1.9'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.6
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.2.2
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Removes outdated periodic backup files from your cloud storage bucket
|
116
|
+
test_files:
|
117
|
+
- spec/spec_helper.rb
|
118
|
+
- spec/trashman/cli_spec.rb
|
119
|
+
- spec/trashman/manager_spec.rb
|
120
|
+
- spec/trashman_spec.rb
|
121
|
+
has_rdoc:
|