ridley 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/lib/ridley/connection.rb +30 -6
- data/lib/ridley/errors.rb +15 -12
- data/lib/ridley/middleware.rb +7 -3
- data/lib/ridley/middleware/retry.rb +60 -0
- data/lib/ridley/version.rb +1 -1
- data/ridley.gemspec +1 -0
- data/spec/unit/ridley/chef/digester_spec.rb +22 -0
- data/spec/unit/ridley/connection_spec.rb +27 -0
- metadata +22 -3
data/Gemfile
CHANGED
data/lib/ridley/connection.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'open-uri'
|
2
|
+
require 'retryable'
|
2
3
|
require 'tempfile'
|
3
4
|
|
4
5
|
module Ridley
|
@@ -17,6 +18,12 @@ module Ridley
|
|
17
18
|
attr_reader :organization
|
18
19
|
attr_reader :client_key
|
19
20
|
attr_reader :client_name
|
21
|
+
# @return [Integer]
|
22
|
+
# how many retries to attempt on HTTP requests
|
23
|
+
attr_reader :retries
|
24
|
+
# @return [Float]
|
25
|
+
# time to wait between retries
|
26
|
+
attr_reader :retry_interval
|
20
27
|
|
21
28
|
# @param [String] server_url
|
22
29
|
# @param [String] client_name
|
@@ -26,6 +33,10 @@ module Ridley
|
|
26
33
|
# URI query unencoded key/value pairs
|
27
34
|
# @option options [Hash] :headers
|
28
35
|
# unencoded HTTP header key/value pairs
|
36
|
+
# @option options [Integer] :retries (5)
|
37
|
+
# retry requests on 5XX failures
|
38
|
+
# @option options [Float] :retry_interval (0.5)
|
39
|
+
# how often we should pause between retries
|
29
40
|
# @option options [Hash] :request
|
30
41
|
# request options
|
31
42
|
# @option options [Hash] :ssl
|
@@ -33,14 +44,25 @@ module Ridley
|
|
33
44
|
# @option options [URI, String, Hash] :proxy
|
34
45
|
# URI, String, or Hash of HTTP proxy options
|
35
46
|
def initialize(server_url, client_name, client_key, options = {})
|
36
|
-
|
37
|
-
@
|
47
|
+
options = options.reverse_merge(retries: 5, retry_interval: 0.5)
|
48
|
+
@client_name = client_name
|
49
|
+
@client_key = client_key
|
50
|
+
@retries = options[:retries]
|
51
|
+
@retry_interval = options[:retry_interval]
|
38
52
|
|
39
53
|
options = options.reverse_merge(
|
40
54
|
builder: Faraday::Builder.new { |b|
|
41
|
-
b.request :chef_auth, client_name, client_key
|
42
|
-
b.response :chef_response
|
43
55
|
b.response :json
|
56
|
+
b.request :retry,
|
57
|
+
max: @retries,
|
58
|
+
interval: @retry_interval,
|
59
|
+
exceptions: [
|
60
|
+
Ridley::Errors::HTTP5XXError,
|
61
|
+
Errno::ETIMEDOUT,
|
62
|
+
Faraday::Error::TimeoutError
|
63
|
+
]
|
64
|
+
b.response :chef_response
|
65
|
+
b.request :chef_auth, client_name, client_key
|
44
66
|
|
45
67
|
b.adapter :net_http_persistent
|
46
68
|
}
|
@@ -117,8 +139,10 @@ module Ridley
|
|
117
139
|
local = Tempfile.new('ridley-stream')
|
118
140
|
local.binmode
|
119
141
|
|
120
|
-
|
121
|
-
|
142
|
+
retryable(tries: retries, on: OpenURI::HTTPError, sleep: retry_interval) do
|
143
|
+
open(target, 'rb', headers) do |remote|
|
144
|
+
local.write(remote.read)
|
145
|
+
end
|
122
146
|
end
|
123
147
|
|
124
148
|
local.flush
|
data/lib/ridley/errors.rb
CHANGED
@@ -87,18 +87,21 @@ module Ridley
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
class
|
91
|
-
class
|
92
|
-
|
93
|
-
class
|
94
|
-
class
|
95
|
-
class
|
96
|
-
class
|
90
|
+
class HTTP4XXError < HTTPError; end
|
91
|
+
class HTTP5XXError < HTTPError; end
|
92
|
+
|
93
|
+
class HTTPBadRequest < HTTP4XXError; register_error(400); end
|
94
|
+
class HTTPUnauthorized < HTTP4XXError; register_error(401); end
|
95
|
+
class HTTPForbidden < HTTP4XXError; register_error(403); end
|
96
|
+
class HTTPNotFound < HTTP4XXError; register_error(404); end
|
97
|
+
class HTTPMethodNotAllowed < HTTP4XXError; register_error(405); end
|
98
|
+
class HTTPRequestTimeout < HTTP4XXError; register_error(408); end
|
99
|
+
class HTTPConflict < HTTP4XXError; register_error(409); end
|
97
100
|
|
98
|
-
class HTTPInternalServerError <
|
99
|
-
class HTTPNotImplemented <
|
100
|
-
class HTTPBadGateway <
|
101
|
-
class HTTPServiceUnavailable <
|
102
|
-
class HTTPGatewayTimeout <
|
101
|
+
class HTTPInternalServerError < HTTP5XXError; register_error(500); end
|
102
|
+
class HTTPNotImplemented < HTTP5XXError; register_error(501); end
|
103
|
+
class HTTPBadGateway < HTTP5XXError; register_error(502); end
|
104
|
+
class HTTPServiceUnavailable < HTTP5XXError; register_error(503); end
|
105
|
+
class HTTPGatewayTimeout < HTTP5XXError; register_error(504); end
|
103
106
|
end
|
104
107
|
end
|
data/lib/ridley/middleware.rb
CHANGED
@@ -6,14 +6,18 @@ module Ridley
|
|
6
6
|
require 'ridley/middleware/parse_json'
|
7
7
|
require 'ridley/middleware/chef_response'
|
8
8
|
require 'ridley/middleware/chef_auth'
|
9
|
+
require 'ridley/middleware/retry'
|
9
10
|
|
10
11
|
Faraday.register_middleware :request,
|
11
|
-
chef_auth: -> { ChefAuth }
|
12
|
+
chef_auth: -> { Ridley::Middleware::ChefAuth }
|
13
|
+
|
14
|
+
Faraday.register_middleware :request,
|
15
|
+
retry: -> { Ridley::Middleware::Retry }
|
12
16
|
|
13
17
|
Faraday.register_middleware :response,
|
14
|
-
json: -> { ParseJson }
|
18
|
+
json: -> { Ridley::Middleware::ParseJson }
|
15
19
|
|
16
20
|
Faraday.register_middleware :response,
|
17
|
-
chef_response: -> { ChefResponse }
|
21
|
+
chef_response: -> { Ridley::Middleware::ChefResponse }
|
18
22
|
end
|
19
23
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Ridley
|
2
|
+
# @author Jamie Winsor <jamie@vialstudios.com>
|
3
|
+
#
|
4
|
+
# Catches exceptions and retries each request a limited number of times.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
#
|
8
|
+
# Faraday.new do |conn|
|
9
|
+
# conn.request :retry, max: 2, interval: 0.05, exceptions: [CustomException, Faraday::Timeout::Error]
|
10
|
+
# conn.adapter ...
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# @note Borrowed and modified from: {https://github.com/lostisland/faraday/blob/master/lib/faraday/request/retry.rb}
|
14
|
+
# use the Faraday official middleware after the release of 0.9.x
|
15
|
+
class Middleware::Retry < Faraday::Middleware
|
16
|
+
# @option options [Integer] :max
|
17
|
+
# maximum number of retries
|
18
|
+
# @option options [Float] :interval
|
19
|
+
# pause in seconds between retries
|
20
|
+
# @option options [Array] :exceptions
|
21
|
+
# the list of exceptions to handle
|
22
|
+
def initialize(app, options = {})
|
23
|
+
super(app)
|
24
|
+
@options = options.slice(:max, :interval, :exceptions)
|
25
|
+
@errmatch = build_exception_matcher(@options[:exceptions])
|
26
|
+
end
|
27
|
+
|
28
|
+
def call(env)
|
29
|
+
retries = @options[:max]
|
30
|
+
begin
|
31
|
+
@app.call(env)
|
32
|
+
rescue @errmatch
|
33
|
+
if retries > 0
|
34
|
+
retries -= 1
|
35
|
+
sleep @options[:interval] if @options[:interval] > 0
|
36
|
+
retry
|
37
|
+
end
|
38
|
+
raise
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# construct an exception matcher object.
|
43
|
+
#
|
44
|
+
# An exception matcher for the rescue clause can usually be any object that
|
45
|
+
# responds to `===`, but for Ruby 1.8 it has to be a Class or Module.
|
46
|
+
def build_exception_matcher(exceptions)
|
47
|
+
matcher = Module.new
|
48
|
+
(class << matcher; self; end).class_eval do
|
49
|
+
define_method(:===) do |error|
|
50
|
+
exceptions.any? do |ex|
|
51
|
+
if ex.is_a? Module then error.is_a? ex
|
52
|
+
else error.class.to_s == ex.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
matcher
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/ridley/version.rb
CHANGED
data/ridley.gemspec
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Borrowed and modified from: {https://github.com/opscode/chef/blob/11.4.0/spec/unit/digester_spec.rb}
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Ridley::Chef::Digester do
|
6
|
+
before(:each) do
|
7
|
+
@cache = described_class.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "when computing checksums of cookbook files and templates" do
|
11
|
+
it "proxies the class method checksum_for_file to the instance" do
|
12
|
+
@cache.should_receive(:checksum_for_file).with("a_file_or_a_fail")
|
13
|
+
described_class.checksum_for_file("a_file_or_a_fail")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "generates a checksum from a non-file IO object" do
|
17
|
+
io = StringIO.new("riseofthemachines\nriseofthechefs\n")
|
18
|
+
expected_md5 = '0e157ac1e2dd73191b76067fb6b4bceb'
|
19
|
+
@cache.generate_md5_checksum(io).should == expected_md5
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -9,6 +9,33 @@ describe Ridley::Connection do
|
|
9
9
|
described_class.new(server_url, client_name, client_key)
|
10
10
|
end
|
11
11
|
|
12
|
+
describe "configurable retries" do
|
13
|
+
before(:each) do
|
14
|
+
stub_request(:get, "https://api.opscode.com/organizations/vialstudios").to_return(status: 500, body: "")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "attempts five (5) retries by default" do
|
18
|
+
expect {
|
19
|
+
subject.get('organizations/vialstudios')
|
20
|
+
}.to raise_error
|
21
|
+
a_request(:get, "https://api.opscode.com/organizations/vialstudios").should have_been_made.times(6)
|
22
|
+
end
|
23
|
+
|
24
|
+
context "given a configured count of two (2) retries" do
|
25
|
+
subject do
|
26
|
+
described_class.new(server_url, client_name, client_key, retries: 2)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "attempts two (2) retries" do
|
30
|
+
expect {
|
31
|
+
subject.get('organizations/vialstudios')
|
32
|
+
}.to raise_error
|
33
|
+
|
34
|
+
a_request(:get, "https://api.opscode.com/organizations/vialstudios").should have_been_made.times(3)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
12
39
|
describe "#api_type" do
|
13
40
|
it "returns :foss if the organization is not set" do
|
14
41
|
subject.stub(:organization).and_return(nil)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ridley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -251,6 +251,22 @@ dependencies:
|
|
251
251
|
- - ! '>='
|
252
252
|
- !ruby/object:Gem::Version
|
253
253
|
version: '2.8'
|
254
|
+
- !ruby/object:Gem::Dependency
|
255
|
+
name: retryable
|
256
|
+
requirement: !ruby/object:Gem::Requirement
|
257
|
+
none: false
|
258
|
+
requirements:
|
259
|
+
- - ! '>='
|
260
|
+
- !ruby/object:Gem::Version
|
261
|
+
version: '0'
|
262
|
+
type: :runtime
|
263
|
+
prerelease: false
|
264
|
+
version_requirements: !ruby/object:Gem::Requirement
|
265
|
+
none: false
|
266
|
+
requirements:
|
267
|
+
- - ! '>='
|
268
|
+
- !ruby/object:Gem::Version
|
269
|
+
version: '0'
|
254
270
|
description: A reliable Chef API client with a clean syntax
|
255
271
|
email:
|
256
272
|
- jamie@vialstudios.com
|
@@ -285,6 +301,7 @@ files:
|
|
285
301
|
- lib/ridley/middleware/chef_auth.rb
|
286
302
|
- lib/ridley/middleware/chef_response.rb
|
287
303
|
- lib/ridley/middleware/parse_json.rb
|
304
|
+
- lib/ridley/middleware/retry.rb
|
288
305
|
- lib/ridley/mixin.rb
|
289
306
|
- lib/ridley/mixin/checksum.rb
|
290
307
|
- lib/ridley/mixin/shell_out.rb
|
@@ -340,6 +357,7 @@ files:
|
|
340
357
|
- spec/unit/ridley/bootstrapper/context_spec.rb
|
341
358
|
- spec/unit/ridley/bootstrapper_spec.rb
|
342
359
|
- spec/unit/ridley/chef/cookbook_spec.rb
|
360
|
+
- spec/unit/ridley/chef/digester_spec.rb
|
343
361
|
- spec/unit/ridley/client_spec.rb
|
344
362
|
- spec/unit/ridley/connection_spec.rb
|
345
363
|
- spec/unit/ridley/errors_spec.rb
|
@@ -382,7 +400,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
382
400
|
version: '0'
|
383
401
|
segments:
|
384
402
|
- 0
|
385
|
-
hash:
|
403
|
+
hash: -1703790355388058426
|
386
404
|
requirements: []
|
387
405
|
rubyforge_project:
|
388
406
|
rubygems_version: 1.8.24
|
@@ -423,6 +441,7 @@ test_files:
|
|
423
441
|
- spec/unit/ridley/bootstrapper/context_spec.rb
|
424
442
|
- spec/unit/ridley/bootstrapper_spec.rb
|
425
443
|
- spec/unit/ridley/chef/cookbook_spec.rb
|
444
|
+
- spec/unit/ridley/chef/digester_spec.rb
|
426
445
|
- spec/unit/ridley/client_spec.rb
|
427
446
|
- spec/unit/ridley/connection_spec.rb
|
428
447
|
- spec/unit/ridley/errors_spec.rb
|