summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/http.rb39
-rw-r--r--lib/chef/http/api_versions.rb3
-rw-r--r--lib/chef/http/authenticator.rb21
-rw-r--r--lib/chef/mixin/versioned_api.rb4
4 files changed, 61 insertions, 6 deletions
diff --git a/lib/chef/http.rb b/lib/chef/http.rb
index 12acae953c..c741dcca97 100644
--- a/lib/chef/http.rb
+++ b/lib/chef/http.rb
@@ -142,13 +142,26 @@ class Chef
# Makes an HTTP request to +path+ with the given +method+, +headers+, and
# +data+ (if applicable).
def request(method, path, headers = {}, data = false)
+ http_attempts ||= 0
url = create_url(path)
method, url, headers, data = apply_request_middleware(method, url, headers, data)
response, rest_request, return_value = send_http_request(method, url, headers, data)
response, rest_request, return_value = apply_response_middleware(response, rest_request, return_value)
+
response.error! unless success_response?(response)
return_value
+
+ rescue Net::HTTPServerException => e
+ http_attempts += 1
+ response = e.response
+ if response.kind_of?(Net::HTTPNotAcceptable) && version_retries - http_attempts > 0
+ Chef::Log.debug("Negotiating protocol version with #{url}, retry #{http_attempts}/#{version_retries}")
+ sleep(http_retry_delay)
+ retry
+ else
+ raise
+ end
rescue Exception => exception
log_failed_request(response, return_value) unless response.nil?
@@ -159,6 +172,7 @@ class Chef
end
def streaming_request_with_progress(path, headers = {}, &progress_block)
+ http_attempts ||= 0
url = create_url(path)
response, rest_request, return_value = nil, nil, nil
tempfile = nil
@@ -177,6 +191,16 @@ class Chef
response.error!
end
tempfile
+ rescue Net::HTTPServerException => e
+ http_attempts += 1
+ response = e.response
+ if response.kind_of?(Net::HTTPNotAcceptable) && version_retries - http_attempts > 0
+ Chef::Log.debug("Negotiating protocol version with #{url}, retry #{http_attempts}/#{version_retries}")
+ sleep(http_retry_delay)
+ retry
+ else
+ raise
+ end
rescue Exception => e
log_failed_request(response, return_value) unless response.nil?
if e.respond_to?(:chef_rest_request=)
@@ -195,6 +219,7 @@ class Chef
# @yield [tempfile] block to process the tempfile
# @yieldparams [tempfile<Tempfile>] tempfile
def streaming_request(path, headers = {})
+ http_attempts ||= 0
url = create_url(path)
response, rest_request, return_value = nil, nil, nil
tempfile = nil
@@ -222,6 +247,16 @@ class Chef
end
end
tempfile
+ rescue Net::HTTPServerException => e
+ http_attempts += 1
+ response = e.response
+ if response.kind_of?(Net::HTTPNotAcceptable) && version_retries - http_attempts > 0
+ Chef::Log.debug("Negotiating protocol version with #{url}, retry #{http_attempts}/#{version_retries}")
+ sleep(http_retry_delay)
+ retry
+ else
+ raise
+ end
rescue Exception => e
log_failed_request(response, return_value) unless response.nil?
if e.respond_to?(:chef_rest_request=)
@@ -413,6 +448,10 @@ class Chef
end
end
+ def version_retries
+ @version_retries ||= options[:version_class].possible_requests
+ end
+
# @api private
def http_retry_delay
config[:http_retry_delay]
diff --git a/lib/chef/http/api_versions.rb b/lib/chef/http/api_versions.rb
index 696c7072bf..674d8f85a7 100644
--- a/lib/chef/http/api_versions.rb
+++ b/lib/chef/http/api_versions.rb
@@ -32,6 +32,9 @@ class Chef
end
def handle_response(http_response, rest_request, return_value)
+ if http_response.code == "406"
+ ServerAPIVersions.instance.reset!
+ end
if http_response.key?("x-ops-server-api-version")
ServerAPIVersions.instance.set_versions(JSONCompat.parse(http_response["x-ops-server-api-version"]))
end
diff --git a/lib/chef/http/authenticator.rb b/lib/chef/http/authenticator.rb
index 84065bf816..65367af107 100644
--- a/lib/chef/http/authenticator.rb
+++ b/lib/chef/http/authenticator.rb
@@ -30,6 +30,8 @@ class Chef
attr_reader :raw_key
attr_reader :attr_names
attr_reader :auth_credentials
+ attr_reader :version_class
+ attr_reader :api_version
attr_accessor :sign_request
@@ -39,15 +41,12 @@ class Chef
@signing_key_filename = opts[:signing_key_filename]
@key = load_signing_key(opts[:signing_key_filename], opts[:raw_key])
@auth_credentials = AuthCredentials.new(opts[:client_name], @key)
- if opts[:api_version]
- @api_version = opts[:api_version]
- else
- @api_version = DEFAULT_SERVER_API_VERSION
- end
+ @version_class = opts[:version_class]
+ @api_version = opts[:api_version]
end
def handle_request(method, url, headers = {}, data = false)
- headers["X-Ops-Server-API-Version"] = @api_version
+ headers["X-Ops-Server-API-Version"] = request_version
headers.merge!(authentication_headers(method, url, data, headers)) if sign_requests?
[method, url, headers, data]
end
@@ -64,6 +63,16 @@ class Chef
[http_response, rest_request, return_value]
end
+ def request_version
+ if version_class
+ version_class.best_request_version
+ elsif api_version
+ api_version
+ else
+ DEFAULT_SERVER_API_VERSION
+ end
+ end
+
def sign_requests?
auth_credentials.sign_requests? && @sign_request
end
diff --git a/lib/chef/mixin/versioned_api.rb b/lib/chef/mixin/versioned_api.rb
index 3015345d44..17c9838d29 100644
--- a/lib/chef/mixin/versioned_api.rb
+++ b/lib/chef/mixin/versioned_api.rb
@@ -70,6 +70,10 @@ class Chef
klass.minimum_api_version.to_s
end
+ def possible_requests
+ versioned_interfaces.length
+ end
+
def new(*args)
object = versioned_api_class.allocate
object.send(:initialize, *args)