bibliotech 0.2.12 → 0.2.13
Sign up to get free protection for your applications and to get access to all the features.
- 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
|