backup-backblaze 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -0
- data/Rakefile +25 -1
- data/lib/backup/backblaze.rb +3 -0
- data/lib/backup/backblaze/account.rb +41 -85
- data/lib/backup/backblaze/api_importer.rb +93 -0
- data/lib/backup/backblaze/back_blaze.rb +6 -18
- data/lib/backup/backblaze/hash_wrap.rb +2 -0
- data/lib/backup/backblaze/http.rb +132 -0
- data/lib/backup/backblaze/retry.rb +56 -52
- data/lib/backup/backblaze/retry_lookup.rb +112 -0
- data/lib/backup/backblaze/upload_file.rb +38 -49
- data/lib/backup/backblaze/upload_large_file.rb +61 -83
- data/lib/backup/backblaze/url_token.rb +11 -0
- data/lib/backup/backblaze/version.rb +1 -1
- data/src/retry.pl +157 -0
- data/src/retry_lookup.erb +42 -0
- metadata +8 -2
data/src/retry.pl
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
% execute with SWI-Prolog:
|
2
|
+
%
|
3
|
+
% generate the when clauses for matching
|
4
|
+
% swipl -q -l retry.pl -t to_whens
|
5
|
+
%
|
6
|
+
% generate the map for dependency checking
|
7
|
+
% swipl -q -l retry.pl -t to_map
|
8
|
+
|
9
|
+
:- use_module(library(bounds)).
|
10
|
+
|
11
|
+
% The complete list as of 04-Sep-2018
|
12
|
+
all_b2api(b2_authorize_account).
|
13
|
+
all_b2api(b2_cancel_large_file).
|
14
|
+
all_b2api(b2_create_bucket).
|
15
|
+
all_b2api(b2_create_key).
|
16
|
+
all_b2api(b2_delete_bucket).
|
17
|
+
all_b2api(b2_delete_file_version).
|
18
|
+
all_b2api(b2_delete_key).
|
19
|
+
all_b2api(b2_download_file_by_id).
|
20
|
+
all_b2api(b2_download_file_by_name).
|
21
|
+
all_b2api(b2_finish_large_file).
|
22
|
+
all_b2api(b2_get_download_authorization).
|
23
|
+
all_b2api(b2_get_file_info).
|
24
|
+
all_b2api(b2_get_upload_part_url).
|
25
|
+
all_b2api(b2_get_upload_url).
|
26
|
+
all_b2api(b2_hide_file).
|
27
|
+
all_b2api(b2_list_buckets).
|
28
|
+
all_b2api(b2_list_file_names).
|
29
|
+
all_b2api(b2_list_file_versions).
|
30
|
+
all_b2api(b2_list_keys).
|
31
|
+
all_b2api(b2_list_parts).
|
32
|
+
all_b2api(b2_list_unfinished_large_files).
|
33
|
+
all_b2api(b2_start_large_file).
|
34
|
+
all_b2api(b2_update_bucket).
|
35
|
+
all_b2api(b2_upload_file).
|
36
|
+
all_b2api(b2_upload_part ).
|
37
|
+
|
38
|
+
% All api calls we're interested in.
|
39
|
+
% In approximate frequency of usage order.
|
40
|
+
some_b2api(b2_upload_part).
|
41
|
+
some_b2api(b2_get_upload_part_url).
|
42
|
+
some_b2api(b2_get_upload_url).
|
43
|
+
some_b2api(b2_upload_file).
|
44
|
+
some_b2api(b2_authorize_account).
|
45
|
+
some_b2api(b2_list_buckets).
|
46
|
+
some_b2api(b2_list_file_names).
|
47
|
+
some_b2api(b2_delete_file_version).
|
48
|
+
some_b2api(b2_finish_large_file).
|
49
|
+
some_b2api(b2_start_large_file).
|
50
|
+
|
51
|
+
b2api(A) :- some_b2api(A).
|
52
|
+
|
53
|
+
% Needs library(bounds). Leaves the bounds as a predicate, which is nicer to
|
54
|
+
% read, can be output as a ruby range, and still matches correctly.
|
55
|
+
five_hundreds(V) :- V in 500..599.
|
56
|
+
|
57
|
+
% these two have special retries
|
58
|
+
upload_retry(b2_upload_part, b2_get_upload_part_url).
|
59
|
+
upload_retry(b2_upload_file, b2_get_upload_url).
|
60
|
+
|
61
|
+
% These two codes from 401 are allowed to retry
|
62
|
+
not_authorised_retryable_code(expired_auth_token).
|
63
|
+
not_authorised_retryable_code(bad_auth_token).
|
64
|
+
|
65
|
+
% Sources:
|
66
|
+
% https://www.backblaze.com/b2/docs/calling.html
|
67
|
+
% https://www.backblaze.com/b2/docs/uploading.html
|
68
|
+
% https://www.backblaze.com/b2/docs/integration_checklist.html
|
69
|
+
|
70
|
+
%%%%%%%%%%%%%%
|
71
|
+
% HttpStatus is one of the Http status codes, as an integer
|
72
|
+
% Code is a backblaze-specific string, read from the response body
|
73
|
+
% RetryCalls is the set of calls to use to retry the OriginalCall
|
74
|
+
% retry(OriginalCall, HttpStatus, Code, RetryCalls)
|
75
|
+
|
76
|
+
% No retry, cos it succeeded :-D
|
77
|
+
retry(_, HttpStatus, _, []) :- HttpStatus in 200..399, false.
|
78
|
+
|
79
|
+
% upload-specific 401 :- re-fetch upload url.
|
80
|
+
%
|
81
|
+
% Some docs say only for expired_auth_token? Other docs say just retry
|
82
|
+
% regardless of code.
|
83
|
+
retry( Call, 401, Code, [Retry,Call] ) :-
|
84
|
+
not_authorised_retryable_code(Code),
|
85
|
+
upload_retry(Call,Retry).
|
86
|
+
|
87
|
+
% upload-specific 408,5xx - re-fetch upload url
|
88
|
+
retry( Call, HttpStatus, _Code, [Retry,Call] ) :-
|
89
|
+
(HttpStatus = 408; five_hundreds(HttpStatus)),
|
90
|
+
upload_retry(Call,Retry).
|
91
|
+
|
92
|
+
% upload-specific 429 - just retry the call
|
93
|
+
retry( Call, 429, _Code, [Call] ) :- upload_retry(Call,_).
|
94
|
+
|
95
|
+
% non-upload 401 failures - re-auth account
|
96
|
+
retry( Call, 401, Code, [b2_authorize_account,Call] ) :-
|
97
|
+
Call \= b2_authorize_account, % b2_authorize_account can't retry with b2_authorize_account
|
98
|
+
not(upload_retry(Call,_)),
|
99
|
+
not_authorised_retryable_code(Code),
|
100
|
+
not(upload_retry(Call,_)).
|
101
|
+
|
102
|
+
% non-upload with 408, 429, and 5xx - retry call (after a backoff)
|
103
|
+
retry( Call,HttpStatus,_Code,[Call] ) :-
|
104
|
+
not(upload_retry(Call,_)),
|
105
|
+
(member(HttpStatus, [408,429]); five_hundreds(HttpStatus)),
|
106
|
+
not(upload_retry(Call,_)).
|
107
|
+
|
108
|
+
%%%%%%%%%%%%%%%%%%%
|
109
|
+
% generate all posibilities
|
110
|
+
allballs( Call,HttpStatus,Code,Retry ) :-
|
111
|
+
b2api(Call),
|
112
|
+
retry(Call,HttpStatus,Code,Retry).
|
113
|
+
|
114
|
+
%%%%%%%%%%%%%%%%%%%
|
115
|
+
% Various conversions to ruby
|
116
|
+
|
117
|
+
% use with with_output_to, can't figure out another way :-\
|
118
|
+
to_ruby_commas([]).
|
119
|
+
to_ruby_commas([Last]) :- !, to_ruby(Last).
|
120
|
+
to_ruby_commas([Fst|Rst]) :- to_ruby(Fst), format(','), to_ruby_commas(Rst).
|
121
|
+
|
122
|
+
% This has to be before ruby_lit(A). Dunno why.
|
123
|
+
to_ruby(Range) :- attvar(Range), get_attr(Range, bounds, bounds(N,X,_)), format('~d..~d', [N,X]).
|
124
|
+
to_ruby(A) :- atom(A), format(':~a', A).
|
125
|
+
to_ruby(S) :- string(S), format('"~s"', S).
|
126
|
+
to_ruby(N) :- integer(N), format('~d', N).
|
127
|
+
to_ruby(F) :- float(F), format( '~f', F).
|
128
|
+
to_ruby(L) :- is_list(L), format('[~@]', to_ruby_commas(L)).
|
129
|
+
to_ruby(ruby_lit(A)) :- format('~w', A).
|
130
|
+
|
131
|
+
default_to_any(Code,DefCode) :- ground(Code) -> format(atom(DefCode), ':~a', Code); DefCode = 'Any'.
|
132
|
+
|
133
|
+
all_whens :-
|
134
|
+
allballs( Call, HttpStatus, Code, Retries ),
|
135
|
+
to_when( Call, HttpStatus, Code, Retries ).
|
136
|
+
|
137
|
+
to_when( Call, HttpStatus, Code, Retries ) :-
|
138
|
+
default_to_any(Code,DefaultedAnyCode),
|
139
|
+
format('when [~@, ~@, ~a] then ~@~n', [to_ruby(Call),to_ruby(HttpStatus),DefaultedAnyCode,to_ruby(Retries)] ).
|
140
|
+
|
141
|
+
to_whens :- findall(_,all_whens,_).
|
142
|
+
to_whens(Term) :- findall(_,(apply(Term,C,Hs,Co,Re),retry(C,Hs,Co,Re)),_).
|
143
|
+
|
144
|
+
some_whens :-
|
145
|
+
findall(
|
146
|
+
_,
|
147
|
+
(member(C,[b2_upload_part,b2_upload_file,b2_authorize_account,any_call]),retry(C,Hs,Co,Re),to_when(C,Hs,Co,Re))
|
148
|
+
,_).
|
149
|
+
|
150
|
+
map_all :-
|
151
|
+
format('retries = Hash.new{|h,k| h[k] = Set.new}~n'),
|
152
|
+
allballs( Call, _HttpStatus, _Code, Retries ),
|
153
|
+
selectchk(Call,Retries,Uniqs),
|
154
|
+
Uniqs \= [],
|
155
|
+
format('retries[~@].merge(~@)~n', [to_ruby(Call),to_ruby(Uniqs)] ).
|
156
|
+
|
157
|
+
to_map :- findall(_,map_all,_), format('retries~n').
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Backup
|
4
|
+
module Backblaze
|
5
|
+
module RetryLookup
|
6
|
+
def (Any = Object.new).=== _other; true end
|
7
|
+
|
8
|
+
module Matcher
|
9
|
+
refine Array do
|
10
|
+
def === other
|
11
|
+
return false unless size == other.size
|
12
|
+
size.times.all? do |idx|
|
13
|
+
self[idx] === other[idx]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
using Matcher
|
20
|
+
|
21
|
+
# Generated from retry.pl
|
22
|
+
#
|
23
|
+
# Cross-product of all the retry scenarios we know about. This probably
|
24
|
+
# isn't the fastest way to calculate retries. But they're rare, so the
|
25
|
+
# slowdown doesn't matter. There is a more general pattern, but I don't
|
26
|
+
# want to get sucked into implementing unification.
|
27
|
+
module_function def retry_sequence api_call, http_status, code
|
28
|
+
case [api_call.to_sym, http_status, code.to_sym]
|
29
|
+
<%= `swipl -q -l #{__dir__}/retry.pl -t to_whens`.gsub(/^(\s*)/, ' ') -%>
|
30
|
+
else [] # No retry. eg 400 and most 401 should just fail immediately
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module_function def retry_dependencies
|
35
|
+
@retry_dependencies ||= begin
|
36
|
+
# didn't want to fight with prolog to generate uniq values here, so just let ruby do it.
|
37
|
+
<%= `swipl -q -l #{__dir__}/retry.pl -t to_map`.gsub(/^(\s*)/, ' ') -%>
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backup-backblaze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Anderson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -115,12 +115,18 @@ files:
|
|
115
115
|
- bin/setup
|
116
116
|
- lib/backup/backblaze.rb
|
117
117
|
- lib/backup/backblaze/account.rb
|
118
|
+
- lib/backup/backblaze/api_importer.rb
|
118
119
|
- lib/backup/backblaze/back_blaze.rb
|
119
120
|
- lib/backup/backblaze/hash_wrap.rb
|
121
|
+
- lib/backup/backblaze/http.rb
|
120
122
|
- lib/backup/backblaze/retry.rb
|
123
|
+
- lib/backup/backblaze/retry_lookup.rb
|
121
124
|
- lib/backup/backblaze/upload_file.rb
|
122
125
|
- lib/backup/backblaze/upload_large_file.rb
|
126
|
+
- lib/backup/backblaze/url_token.rb
|
123
127
|
- lib/backup/backblaze/version.rb
|
128
|
+
- src/retry.pl
|
129
|
+
- src/retry_lookup.erb
|
124
130
|
homepage: http://github.com/djellemah/backup-backblaze
|
125
131
|
licenses:
|
126
132
|
- MIT
|