bibliotech 0.2.12 → 0.2.13
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/lib/bibliotech/application.rb +6 -6
- data/lib/bibliotech/backups/scheduler.rb +30 -19
- data/lib/bibliotech/builders/gzip.rb +5 -3
- data/lib/bibliotech/command_generator.rb +6 -2
- data/lib/bibliotech/config.rb +11 -4
- data/lib/bibliotech/rake_lib.rb +8 -5
- data/spec/bibliotech/backup_pruner_spec.rb +5 -1
- data/spec/bibliotech/backup_scheduler_spec.rb +7 -7
- data/spec/bibliotech/command_generator/mysql_spec.rb +2 -2
- data/spec/bibliotech/command_generator/postgres_spec.rb +1 -1
- data/spec/bibliotech/command_generator_spec.rb +1 -1
- data/spec/bibliotech/config_spec.rb +3 -2
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a22ff69ff51f9da65c676de7b84084129f2a9499
|
4
|
+
data.tar.gz: 414d7b654e61ab08ac35e26c3ecebb161761c4dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee5d38a9f9a2a393e9b44d07f15dba07e8285cad1b5a931ad5de2b3ca955e13b15962aec59cc76c699fd1aa494c10460e5ce1a9d26e4ac3e6085fdc6d4cfe8d7
|
7
|
+
data.tar.gz: 490311e700290021309b7991116fb11bc79db31be92b53c87144a355c7527ad3139ff41994f3c72a872bec96c7060998d1cb47c91668531795fdfc661564512b
|
@@ -67,13 +67,13 @@ module BiblioTech
|
|
67
67
|
end
|
68
68
|
|
69
69
|
#pull a dump from a remote
|
70
|
-
def get(options)
|
71
|
-
@shell.run(commands.fetch(options))
|
70
|
+
def get(remote, options)
|
71
|
+
@shell.run(commands.fetch(remote, options))
|
72
72
|
end
|
73
73
|
|
74
74
|
#push a dump to a remote
|
75
|
-
def send(options)
|
76
|
-
@shell.run(commands.push(options))
|
75
|
+
def send(remote, options)
|
76
|
+
@shell.run(commands.push(remote, options))
|
77
77
|
end
|
78
78
|
|
79
79
|
#clean up the DB dumps
|
@@ -86,8 +86,8 @@ module BiblioTech
|
|
86
86
|
pruner(options || {}).most_recent.path
|
87
87
|
end
|
88
88
|
|
89
|
-
def remote_cli(remote, command, options)
|
90
|
-
@shell.run(commands.
|
89
|
+
def remote_cli(remote, command, *options)
|
90
|
+
@shell.run(commands.remote_cli(remote, command, *options))
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
@@ -10,41 +10,52 @@ module BiblioTech
|
|
10
10
|
@limit = nil if limit == "all"
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
13
|
+
def freq_seconds
|
14
|
+
frequency * 60
|
15
|
+
end
|
16
|
+
|
17
|
+
def range
|
18
|
+
freq_seconds / 2
|
16
19
|
end
|
17
20
|
|
18
|
-
|
21
|
+
# The earliest possible time to keep a file in.
|
22
|
+
def compute_earliest_time(file_list)
|
19
23
|
limit_time = Time.at(0)
|
20
24
|
return limit_time if file_list.empty?
|
21
25
|
unless limit.nil?
|
22
|
-
limit_time =
|
26
|
+
limit_time = latest_time(file_list) - limit * freq_seconds
|
23
27
|
end
|
24
|
-
[limit_time, file_list.
|
28
|
+
[limit_time, file_list.last.timestamp - range].max
|
25
29
|
end
|
26
30
|
|
27
|
-
|
28
|
-
|
31
|
+
# The latest possible time to keep a file in.
|
32
|
+
def latest_time(file_list)
|
33
|
+
return Time.at(0) if file_list.empty?
|
34
|
+
file_list.first.timestamp
|
29
35
|
end
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
37
|
+
# Working from the latest time backwards, mark the closest file to the
|
38
|
+
# appropriate frequencies as keepable
|
39
|
+
def mark(original_file_list)
|
40
|
+
file_list = original_file_list.sort_by{|record| -record.timestamp.to_i} #sort from newest to oldest
|
34
41
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
(record.timestamp - time).abs
|
42
|
+
time = latest_time(file_list)
|
43
|
+
earliest_time = compute_earliest_time(file_list)
|
44
|
+
while time > earliest_time do
|
45
|
+
file_list.delete_if do |record|
|
46
|
+
record.timestamp > time
|
41
47
|
end
|
42
|
-
|
48
|
+
|
49
|
+
break if file_list.empty?
|
50
|
+
|
51
|
+
closest = file_list.first
|
52
|
+
|
53
|
+
if (time - closest.timestamp) < freq_seconds
|
43
54
|
closest.keep = true
|
44
55
|
end
|
45
56
|
time -= freq_seconds
|
46
57
|
end
|
47
|
-
return
|
58
|
+
return original_file_list
|
48
59
|
end
|
49
60
|
end
|
50
61
|
end
|
@@ -3,11 +3,13 @@ require 'bibliotech/builders/file'
|
|
3
3
|
module BiblioTech
|
4
4
|
module Builders
|
5
5
|
class GzipExpander < FileInput
|
6
|
-
|
7
|
-
|
6
|
+
PATTERNS = [ /.*\.gz\z/, /.*\.gzip\z/ ]
|
7
|
+
PATTERNS.each do |pattern|
|
8
|
+
register pattern
|
9
|
+
end
|
8
10
|
|
9
11
|
def go(command)
|
10
|
-
command = cmd("gunzip", file) | command
|
12
|
+
command = cmd("gunzip", "-c", file) | command
|
11
13
|
end
|
12
14
|
end
|
13
15
|
|
@@ -31,10 +31,14 @@ module BiblioTech
|
|
31
31
|
|
32
32
|
def fetch(remote, filename, options = nil)
|
33
33
|
options = config.merge(options || {})
|
34
|
-
|
34
|
+
local_path = options.local_file(filename)
|
35
|
+
cmd("mkdir") do |cmd|
|
36
|
+
cmd.options << "--parents"
|
37
|
+
cmd.options << File::dirname(local_path)
|
38
|
+
end & cmd("scp") do |cmd|
|
35
39
|
options.optionally{ cmd.options << "-i #{options.id_file(remote)}" }
|
36
40
|
cmd.options << options.remote_file(remote, filename)
|
37
|
-
cmd.options <<
|
41
|
+
cmd.options << local_path
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
data/lib/bibliotech/config.rb
CHANGED
@@ -5,16 +5,16 @@ module BiblioTech
|
|
5
5
|
CONFIG_STEPS = {
|
6
6
|
:database_config_file => [ "database_config_file" ] ,
|
7
7
|
:database_config_env => [ "database_config_env" ] ,
|
8
|
+
:root_path => [ "path" ] ,
|
8
9
|
:host => [ "host" ] ,
|
9
10
|
:port => [ "port" ] ,
|
10
11
|
:user => [ "user" ] ,
|
11
12
|
:rsa_files => [ "rsa_files" ] ,
|
12
13
|
:ssh_options => [ "ssh_options" ] ,
|
14
|
+
:fetch_dir => [ "fetched_dir" ] ,
|
13
15
|
:file => [ "backups" , "file" ] ,
|
14
16
|
:filename => [ "backups" , "filename" ] ,
|
15
17
|
:backup_path => [ "backups" , "dir" ] ,
|
16
|
-
:root_path => [ "path" ] ,
|
17
|
-
:fetch_dir => [ "fetched_dir" ] ,
|
18
18
|
:compressor => [ "backups" , "compress" ] ,
|
19
19
|
:prune_schedule => [ "backups" , "keep" ] ,
|
20
20
|
:backup_name => [ "backups" , "prefix" ] ,
|
@@ -208,6 +208,13 @@ module BiblioTech
|
|
208
208
|
unless real_frequency % backup_frequency == 0
|
209
209
|
raise "Pruning frequency #{real_frequency}:#{frequency} is not a multiple of backup frequency: #{backup_frequency}:#{local_get(:backup_frequency)}"
|
210
210
|
end
|
211
|
+
limit =
|
212
|
+
case limit
|
213
|
+
when "all"
|
214
|
+
nil
|
215
|
+
else
|
216
|
+
Integer(limit)
|
217
|
+
end
|
211
218
|
[real_frequency, limit]
|
212
219
|
end.sort_by do |frequency, limit|
|
213
220
|
frequency
|
@@ -244,9 +251,9 @@ module BiblioTech
|
|
244
251
|
|
245
252
|
def expander
|
246
253
|
if remote.nil?
|
247
|
-
local_get(:
|
254
|
+
local_get(:compressor)
|
248
255
|
else
|
249
|
-
remote_get(remote, :
|
256
|
+
remote_get(remote, :compressor)
|
250
257
|
end
|
251
258
|
end
|
252
259
|
|
data/lib/bibliotech/rake_lib.rb
CHANGED
@@ -74,16 +74,19 @@ module BiblioTech
|
|
74
74
|
namespace :remote_sync do
|
75
75
|
desc "Pull the latest DB dump from the remote server into our local DB"
|
76
76
|
task :down do
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
result = app.remote_cli(remote, "latest")
|
78
|
+
result.must_succeed!
|
79
|
+
filename = result.stdout.chomp
|
80
|
+
|
81
|
+
app.get(remote, filename).must_succeed!
|
82
|
+
app.import(:backups => { :file => app.config.local_file(filename)}).must_succeed!
|
80
83
|
end
|
81
84
|
|
82
85
|
desc "Push the latest local DB dump to the remote server's DB"
|
83
86
|
task :up do
|
84
87
|
filename = app.latest
|
85
|
-
app.send(remote, filename)
|
86
|
-
app.remote_cli(remote, "load", filename)
|
88
|
+
app.send(remote, filename).must_succeed!
|
89
|
+
app.remote_cli(remote, "load", filename).must_succeed!
|
87
90
|
end
|
88
91
|
end
|
89
92
|
end
|
@@ -13,11 +13,15 @@ module BiblioTech
|
|
13
13
|
App.new
|
14
14
|
end
|
15
15
|
|
16
|
+
let :schedule do
|
17
|
+
{:daily => 100}
|
18
|
+
end
|
19
|
+
|
16
20
|
let :pruner do
|
17
21
|
app.pruner({:backups => {
|
18
22
|
:frequency => "daily",
|
19
23
|
:prefix => "testing",
|
20
|
-
:keep =>
|
24
|
+
:keep => schedule,
|
21
25
|
:dir => "db_backups"
|
22
26
|
}})
|
23
27
|
end
|
@@ -5,7 +5,7 @@ module BiblioTech::Backups
|
|
5
5
|
let(:test_jitter){ 0 }
|
6
6
|
|
7
7
|
let :unfiltered_files do
|
8
|
-
(0..interval).step(frequency).map do |seconds| #every 15 seconds for 8 hours
|
8
|
+
(0..interval).step(frequency).map do |seconds| #e.g. every 15 seconds for 8 hours
|
9
9
|
seconds = seconds - test_jitter/2 + rand(test_jitter)
|
10
10
|
FileRecord.new("", Time.now - seconds)
|
11
11
|
end
|
@@ -27,12 +27,12 @@ module BiblioTech::Backups
|
|
27
27
|
end
|
28
28
|
|
29
29
|
context "when there's more than enough backups" do
|
30
|
-
let(:interval){ 60*60*12 -
|
30
|
+
let(:interval){ 60*60*12 - test_jitter}
|
31
31
|
let(:frequency) { 15 }
|
32
32
|
let(:test_jitter){ 60 }
|
33
33
|
|
34
34
|
it "should mark 8 files kept" do
|
35
|
-
expect(kept_files.count).to eql
|
35
|
+
expect(kept_files.count).to eql 12
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -43,7 +43,7 @@ module BiblioTech::Backups
|
|
43
43
|
end
|
44
44
|
|
45
45
|
context "when there's just enough backups" do
|
46
|
-
let(:interval){ 60*60*8 -
|
46
|
+
let(:interval){ 60*60*8 - test_jitter }
|
47
47
|
let(:frequency){ 60*8 }
|
48
48
|
let(:test_jitter){ 60 }
|
49
49
|
|
@@ -85,12 +85,12 @@ module BiblioTech::Backups
|
|
85
85
|
end
|
86
86
|
|
87
87
|
context "when there are too few backups" do
|
88
|
-
let(:interval){ 60*60*4 -
|
88
|
+
let(:interval){ 60*60*4 - test_jitter }
|
89
89
|
let(:frequency){ 60*8 }
|
90
90
|
let(:test_jitter){ 60 }
|
91
91
|
|
92
|
-
it "should mark
|
93
|
-
expect(kept_files.count).to eql
|
92
|
+
it "should mark 4 files kept" do
|
93
|
+
expect(kept_files.count).to eql 4
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -18,7 +18,7 @@ module BiblioTech
|
|
18
18
|
let( :filename ) { "export.sql" }
|
19
19
|
let( :path ) { "/some/path" }
|
20
20
|
|
21
|
-
|
21
|
+
let :base_config_hash do
|
22
22
|
{ "database_config" => {
|
23
23
|
"adapter" => :mysql,
|
24
24
|
"database" => db_name,
|
@@ -158,7 +158,7 @@ module BiblioTech
|
|
158
158
|
|
159
159
|
it { expect(command).to be_a(Caliph::PipelineChain) }
|
160
160
|
it { expect(first_cmd.executable).to eq('gunzip') }
|
161
|
-
it { expect(first_cmd.options).to eq(["#{path}/#{filename}.gz"]) }
|
161
|
+
it { expect(first_cmd.options).to eq(["-c", "#{path}/#{filename}.gz"]) }
|
162
162
|
end
|
163
163
|
end
|
164
164
|
end
|
@@ -171,7 +171,7 @@ module BiblioTech
|
|
171
171
|
|
172
172
|
it { expect(command).to be_a(Caliph::PipelineChain) }
|
173
173
|
it { expect(first_cmd.executable).to eq('gunzip') }
|
174
|
-
it { expect(first_cmd.options).to eq(["#{path}/#{filename}.gz"]) }
|
174
|
+
it { expect(first_cmd.options).to eq(["-c", "#{path}/#{filename}.gz"]) }
|
175
175
|
end
|
176
176
|
end
|
177
177
|
end
|
@@ -70,7 +70,7 @@ module BiblioTech
|
|
70
70
|
end
|
71
71
|
|
72
72
|
it "should produce a fetch command" do
|
73
|
-
expect(generator.fetch("staging", "latest.sql.gz").command).to match(
|
73
|
+
expect(generator.fetch("staging", "latest.sql.gz").command).to match(/scp.*@.*latest\.sql\.gz.*latest\.sql\.gz\z/)
|
74
74
|
end
|
75
75
|
|
76
76
|
it "should produce a push command" do
|
@@ -144,12 +144,13 @@ module BiblioTech
|
|
144
144
|
"keep" => {
|
145
145
|
"hourlies" => 24,
|
146
146
|
"daily" => 7,
|
147
|
-
"weeklies" => 4
|
147
|
+
"weeklies" => 4,
|
148
|
+
"monthly" => "all"
|
148
149
|
}}}
|
149
150
|
end
|
150
151
|
|
151
152
|
it "should produce correct schedule" do
|
152
|
-
expect(schedule_array).to contain_exactly([60, 24], [60*24, 7], [60*24*7, 4])
|
153
|
+
expect(schedule_array).to contain_exactly([60, 24], [60*24, 7], [60*24*7, 4], [60*24*30, nil])
|
153
154
|
end
|
154
155
|
end
|
155
156
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bibliotech
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Dorn
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: caliph
|
@@ -31,14 +31,14 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ~>
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 0.
|
34
|
+
version: 0.9.0
|
35
35
|
type: :runtime
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - ~>
|
40
40
|
- !ruby/object:Gem::Version
|
41
|
-
version: 0.
|
41
|
+
version: 0.9.0
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: valise
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,7 +128,7 @@ rdoc_options:
|
|
128
128
|
- --main
|
129
129
|
- doc/README
|
130
130
|
- --title
|
131
|
-
- bibliotech-0.2.
|
131
|
+
- bibliotech-0.2.13 Documentation
|
132
132
|
require_paths:
|
133
133
|
- lib/
|
134
134
|
required_ruby_version: !ruby/object:Gem::Requirement
|