diff options
author | John Keiser <jkeiser@opscode.com> | 2013-10-11 13:57:07 -0700 |
---|---|---|
committer | John Keiser <jkeiser@opscode.com> | 2013-10-11 13:57:07 -0700 |
commit | 12b902d5aa539f14ee2e25f1a1ca702f8fb81377 (patch) | |
tree | 6db3aef50f1f3e823cd928491796a09c40a822e0 | |
parent | 6d58ff931dda2d5bfa0eb8b7feadf5cd0fb37c8e (diff) | |
parent | 5e5f5b1b1e431612a40bf235c4081dc5ff885bef (diff) | |
download | chef-12b902d5aa539f14ee2e25f1a1ca702f8fb81377.tar.gz |
Use Chef::HTTP for knife-essentials raw requests, fix CHEF-4515 in the balance
27 files changed, 341 insertions, 221 deletions
diff --git a/lib/chef/chef_fs/file_system/acl_entry.rb b/lib/chef/chef_fs/file_system/acl_entry.rb index 0be9076038..8edc02d5c5 100644 --- a/lib/chef/chef_fs/file_system/acl_entry.rb +++ b/lib/chef/chef_fs/file_system/acl_entry.rb @@ -40,7 +40,7 @@ class Chef acls = data_handler.normalize(JSON.parse(file_contents, :create_additions => false), self) PERMISSIONS.each do |permission| begin - rest.put_rest("#{api_path}/#{permission}", { permission => acls[permission] }) + rest.put("#{api_path}/#{permission}", { permission => acls[permission] }) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}" rescue Net::HTTPServerException => e diff --git a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb index 98f90e3a68..0083ee4cfa 100644 --- a/lib/chef/chef_fs/file_system/chef_server_root_dir.rb +++ b/lib/chef/chef_fs/file_system/chef_server_root_dir.rb @@ -16,6 +16,7 @@ # limitations under the License. # +require 'chef/server_api' require 'chef/chef_fs/file_system/acls_dir' require 'chef/chef_fs/file_system/base_fs_dir' require 'chef/chef_fs/file_system/rest_list_dir' @@ -23,7 +24,6 @@ require 'chef/chef_fs/file_system/cookbooks_dir' require 'chef/chef_fs/file_system/data_bags_dir' require 'chef/chef_fs/file_system/nodes_dir' require 'chef/chef_fs/file_system/environments_dir' -require 'chef/rest' require 'chef/chef_fs/data_handler/client_data_handler' require 'chef/chef_fs/data_handler/role_data_handler' require 'chef/chef_fs/data_handler/user_data_handler' @@ -57,6 +57,14 @@ class Chef end def rest + Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true) + end + + def get_json(path) + Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key).get(path) + end + + def chef_rest Chef::REST.new(chef_server_url, chef_username, chef_private_key) end diff --git a/lib/chef/chef_fs/file_system/cookbook_dir.rb b/lib/chef/chef_fs/file_system/cookbook_dir.rb index 5751328b02..d7411e1c74 100644 --- a/lib/chef/chef_fs/file_system/cookbook_dir.rb +++ b/lib/chef/chef_fs/file_system/cookbook_dir.rb @@ -126,7 +126,7 @@ class Chef def delete(recurse) if recurse begin - rest.delete_rest(api_path) + rest.delete(api_path) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" rescue Net::HTTPServerException @@ -191,7 +191,7 @@ class Chef old_retry_count = Chef::Config[:http_retry_count] begin Chef::Config[:http_retry_count] = 0 - @chef_object ||= Chef::CookbookVersion.json_create(Chef::ChefFS::RawRequest.raw_json(rest, api_path)) + @chef_object ||= Chef::CookbookVersion.json_create(root.get_json(api_path)) ensure Chef::Config[:http_retry_count] = old_retry_count end diff --git a/lib/chef/chef_fs/file_system/cookbook_file.rb b/lib/chef/chef_fs/file_system/cookbook_file.rb index e05c4aa614..6673ad73f4 100644 --- a/lib/chef/chef_fs/file_system/cookbook_file.rb +++ b/lib/chef/chef_fs/file_system/cookbook_file.rb @@ -17,6 +17,7 @@ # require 'chef/chef_fs/file_system/base_fs_object' +require 'chef/http/simple' require 'digest/md5' class Chef @@ -35,16 +36,12 @@ class Chef end def read - old_sign_on_redirect = rest.sign_on_redirect - rest.sign_on_redirect = false begin - tmpfile = rest.get_rest(file[:url], true) + tmpfile = Chef::HTTP::Simple.new(file[:url]).streaming_request(file[:url]) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading #{file[:url]}: #{e}" rescue Net::HTTPServerException => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "#{e.message} retrieving #{file[:url]}" - ensure - rest.sign_on_redirect = old_sign_on_redirect end begin diff --git a/lib/chef/chef_fs/file_system/cookbooks_dir.rb b/lib/chef/chef_fs/file_system/cookbooks_dir.rb index 73684450b3..a58bfdd1f2 100644 --- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb +++ b/lib/chef/chef_fs/file_system/cookbooks_dir.rb @@ -18,7 +18,6 @@ require 'chef/chef_fs/file_system/rest_list_dir' require 'chef/chef_fs/file_system/cookbook_dir' -require 'chef/chef_fs/raw_request' require 'chef/chef_fs/file_system/operation_failed_error' require 'chef/chef_fs/file_system/cookbook_frozen_error' require 'chef/chef_fs/file_system/chef_repository_file_system_cookbook_dir' @@ -54,13 +53,13 @@ class Chef @children ||= begin if Chef::Config[:versioned_cookbooks] result = [] - Chef::ChefFS::RawRequest.raw_json(rest, "#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks| + root.get_json("#{api_path}/?num_versions=all").each_pair do |cookbook_name, cookbooks| cookbooks['versions'].each do |cookbook_version| result << CookbookDir.new("#{cookbook_name}-#{cookbook_version['version']}", self, :exists => true) end end else - result = Chef::ChefFS::RawRequest.raw_json(rest, api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) } + result = root.get_json(api_path).keys.map { |cookbook_name| CookbookDir.new(cookbook_name, self, :exists => true) } end result.sort_by(&:name) end @@ -107,7 +106,7 @@ class Chef cookbook_to_upload.freeze_version if options[:freeze] # Instantiate a new uploader based on the proxy loader - uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => rest) + uploader = Chef::CookbookUploader.new(cookbook_to_upload, proxy_cookbook_path, :force => options[:force], :rest => root.chef_rest) with_actual_cookbooks_dir(temp_cookbooks_path) do upload_cookbook!(uploader) @@ -129,7 +128,7 @@ class Chef def upload_unversioned_cookbook(other, options) cookbook_to_upload = other.chef_object cookbook_to_upload.freeze_version if options[:freeze] - uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => rest) + uploader = Chef::CookbookUploader.new(cookbook_to_upload, other.parent.file_path, :force => options[:force], :rest => root.chef_rest) with_actual_cookbooks_dir(other.parent.file_path) do upload_cookbook!(uploader) diff --git a/lib/chef/chef_fs/file_system/data_bag_dir.rb b/lib/chef/chef_fs/file_system/data_bag_dir.rb index 3814b94fac..212f76fdb9 100644 --- a/lib/chef/chef_fs/file_system/data_bag_dir.rb +++ b/lib/chef/chef_fs/file_system/data_bag_dir.rb @@ -52,7 +52,7 @@ class Chef raise MustDeleteRecursivelyError.new(self), "#{path_for_printing} must be deleted recursively" end begin - rest.delete_rest(api_path) + rest.delete(api_path) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" rescue Net::HTTPServerException => e diff --git a/lib/chef/chef_fs/file_system/data_bags_dir.rb b/lib/chef/chef_fs/file_system/data_bags_dir.rb index d0404c284b..6d0685d3b7 100644 --- a/lib/chef/chef_fs/file_system/data_bags_dir.rb +++ b/lib/chef/chef_fs/file_system/data_bags_dir.rb @@ -34,7 +34,7 @@ class Chef def children begin - @children ||= Chef::ChefFS::RawRequest.raw_json(rest, api_path).keys.sort.map do |entry| + @children ||= root.get_json(api_path).keys.sort.map do |entry| DataBagDir.new(entry, self, true) end rescue Timeout::Error => e @@ -54,7 +54,7 @@ class Chef def create_child(name, file_contents) begin - rest.post_rest(api_path, { 'name' => name }) + rest.post(api_path, { 'name' => name }) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating child '#{name}': #{e}" rescue Net::HTTPServerException => e diff --git a/lib/chef/chef_fs/file_system/nodes_dir.rb b/lib/chef/chef_fs/file_system/nodes_dir.rb index 82683e81ac..c3c48377cd 100644 --- a/lib/chef/chef_fs/file_system/nodes_dir.rb +++ b/lib/chef/chef_fs/file_system/nodes_dir.rb @@ -32,7 +32,7 @@ class Chef # Identical to RestListDir.children, except supports environments def children begin - @children ||= Chef::ChefFS::RawRequest.raw_json(rest, env_api_path).keys.sort.map do |key| + @children ||= root.get_json(env_api_path).keys.sort.map do |key| _make_child_entry("#{key}.json", true) end rescue Timeout::Error => e diff --git a/lib/chef/chef_fs/file_system/rest_list_dir.rb b/lib/chef/chef_fs/file_system/rest_list_dir.rb index 7e4a33813b..b7ee51d284 100644 --- a/lib/chef/chef_fs/file_system/rest_list_dir.rb +++ b/lib/chef/chef_fs/file_system/rest_list_dir.rb @@ -45,7 +45,7 @@ class Chef def children begin - @children ||= Chef::ChefFS::RawRequest.raw_json(rest, api_path).keys.sort.map do |key| + @children ||= root.get_json(api_path).keys.sort.map do |key| _make_child_entry("#{key}.json", true) end rescue Timeout::Error => e @@ -76,7 +76,7 @@ class Chef end begin - rest.post_rest(api_path, object) + rest.post(api_path, object) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:create_child, self, e), "Timeout creating '#{name}': #{e}" rescue Net::HTTPServerException => e diff --git a/lib/chef/chef_fs/file_system/rest_list_entry.rb b/lib/chef/chef_fs/file_system/rest_list_entry.rb index 6e6ad12438..0d5557de1d 100644 --- a/lib/chef/chef_fs/file_system/rest_list_entry.rb +++ b/lib/chef/chef_fs/file_system/rest_list_entry.rb @@ -19,7 +19,6 @@ require 'chef/chef_fs/file_system/base_fs_object' require 'chef/chef_fs/file_system/not_found_error' require 'chef/chef_fs/file_system/operation_failed_error' -require 'chef/chef_fs/raw_request' require 'chef/role' require 'chef/node' @@ -68,7 +67,7 @@ class Chef def delete(recurse) begin - rest.delete_rest(api_path) + rest.delete(api_path) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:delete, self, e), "Timeout deleting: #{e}" rescue Net::HTTPServerException => e @@ -86,7 +85,8 @@ class Chef def _read_hash begin - json = Chef::ChefFS::RawRequest.raw_request(rest, api_path) + # Minimize the value (get rid of defaults) so the results don't look terrible + minimize_value(root.get_json(api_path)) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "Timeout reading: #{e}" rescue Net::HTTPServerException => e @@ -96,8 +96,6 @@ class Chef raise Chef::ChefFS::FileSystem::OperationFailedError.new(:read, self, e), "HTTP error reading: #{e}" end end - # Minimize the value (get rid of defaults) so the results don't look terrible - minimize_value(JSON.parse(json, :create_additions => false)) end def chef_object @@ -160,7 +158,7 @@ class Chef end begin - rest.put_rest(api_path, object) + rest.put(api_path, object) rescue Timeout::Error => e raise Chef::ChefFS::FileSystem::OperationFailedError.new(:write, self, e), "Timeout writing: #{e}" rescue Net::HTTPServerException => e diff --git a/lib/chef/chef_fs/raw_request.rb b/lib/chef/chef_fs/raw_request.rb deleted file mode 100644 index e017589fa4..0000000000 --- a/lib/chef/chef_fs/raw_request.rb +++ /dev/null @@ -1,83 +0,0 @@ -class Chef - module ChefFS - module RawRequest - def self.raw_json(chef_rest, api_path) - api_request(chef_rest, :GET, chef_rest.create_url(api_path), {}, nil, :parse_json => true) - end - - def self.raw_request(chef_rest, api_path) - api_request(chef_rest, :GET, chef_rest.create_url(api_path)) - end - - def self.api_request(chef_rest, method, url, headers={}, data=nil, options = {}) - json_body = data || nil - # json_body = data ? Chef::JSONCompat.to_json(data) : nil - # Force encoding to binary to fix SSL related EOFErrors - # cf. http://tickets.opscode.com/browse/CHEF-2363 - # http://redmine.ruby-lang.org/issues/5233 - # json_body.force_encoding(Encoding::BINARY) if json_body.respond_to?(:force_encoding) - headers = build_headers(chef_rest, method, url, headers, json_body) - - chef_rest.retriable_rest_request(method, url, json_body, headers) do |rest_request| - response = rest_request.call {|r| r.read_body} - - response_body = chef_rest.decompress_body(response) - - if response.kind_of?(Net::HTTPSuccess) - if options[:parse_json] && response['content-type'] =~ /json/ - JSON.parse(response_body, :create_additions => false) - else - response_body - end - elsif redirect_location = redirected_to(response) - if [:GET, :HEAD].include?(method) - chef_rest.follow_redirect do - api_request(chef_rest, method, chef_rest.create_url(redirect_location), headers, nil, options) - end - else - raise Exceptions::InvalidRedirect, "#{method} request was redirected from #{url} to #{redirect_location}. Only GET and HEAD support redirects." - end - else - # have to decompress the body before making an exception for it. But the body could be nil. - response.body.replace(chef_rest.decompress_body(response)) if response.body.respond_to?(:replace) - - if response['content-type'] =~ /json/ - exception = response_body - msg = "HTTP Request Returned #{response.code} #{response.message}: " - msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s) - Chef::Log.info(msg) - end - response.error! - end - end - end - - private - - # Copied so that it does not automatically inflate an object - # This is also used by knife raw_essentials - - ACCEPT_ENCODING = "Accept-Encoding".freeze - ENCODING_GZIP_DEFLATE = "gzip;q=1.0,deflate;q=0.6,identity;q=0.3".freeze - - def self.redirected_to(response) - return nil unless response.kind_of?(Net::HTTPRedirection) - # Net::HTTPNotModified is undesired subclass of Net::HTTPRedirection so test for this - return nil if response.kind_of?(Net::HTTPNotModified) - response['location'] - end - - def self.build_headers(chef_rest, method, url, headers={}, json_body=nil, raw=nil) - # headers = @default_headers.merge(headers) - #headers['Accept'] = "application/json" unless raw - headers['Accept'] = "application/json" unless raw - headers['Content-Type'] = 'application/json' if json_body - headers['Content-Length'] = json_body.bytesize.to_s if json_body - headers[Chef::REST::RESTRequest::ACCEPT_ENCODING] = Chef::REST::RESTRequest::ENCODING_GZIP_DEFLATE - headers.merge!(chef_rest.authentication_headers(method, url, json_body)) if chef_rest.sign_requests? - headers.merge!(Chef::Config[:custom_http_headers]) if Chef::Config[:custom_http_headers] - headers - end - end - end -end diff --git a/lib/chef/http.rb b/lib/chef/http.rb index 77faa686a0..4852a3eb8a 100644 --- a/lib/chef/http.rb +++ b/lib/chef/http.rb @@ -94,7 +94,7 @@ class Chef # === Parameters # path:: path part of the request URL def head(path, headers={}) - api_request(:HEAD, create_url(path), headers) + request(:HEAD, path, headers) end # Send an HTTP GET request to the path @@ -102,7 +102,7 @@ class Chef # === Parameters # path:: The path to GET def get(path, headers={}) - api_request(:GET, create_url(path), headers) + request(:GET, path, headers) end # Send an HTTP PUT request to the path @@ -110,7 +110,7 @@ class Chef # === Parameters # path:: path part of the request URL def put(path, json, headers={}) - api_request(:PUT, create_url(path), headers, json) + request(:PUT, path, headers, json) end # Send an HTTP POST request to the path @@ -118,7 +118,7 @@ class Chef # === Parameters # path:: path part of the request URL def post(path, json, headers={}) - api_request(:POST, create_url(path), headers, json) + request(:POST, path, headers, json) end # Send an HTTP DELETE request to the path @@ -126,13 +126,13 @@ class Chef # === Parameters # path:: path part of the request URL def delete(path, headers={}) - api_request(:DELETE, create_url(path), headers) + request(:DELETE, path, headers) end - # Makes an HTTP request to +url+ with the given +method+, +headers+, and + # Makes an HTTP request to +path+ with the given +method+, +headers+, and # +data+ (if applicable). - def request(method, url, headers={}, data=false) - + def request(method, path, headers={}, data=false) + 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) @@ -154,7 +154,8 @@ class Chef # # If no block is given, the tempfile is returned, which means it's up to # you to unlink the tempfile when you're done with it. - def streaming_request(url, headers, &block) + def streaming_request(path, headers={}, &block) + url = create_url(path) response, rest_request, return_value = nil, nil, nil tempfile = nil @@ -185,13 +186,15 @@ class Chef raise end - def http_client - BasicClient.new(create_url(url)) + def http_client(base_url=nil) + base_url ||= url + BasicClient.new(base_url) end protected def create_url(path) + return path if path.is_a?(URI) if path =~ /^(http|https):\/\// URI.parse(path) else @@ -228,10 +231,11 @@ class Chef headers = build_headers(method, url, headers, body) retrying_http_errors(url) do + client = http_client(url) if block_given? - request, response = http_client.request(method, url, body, headers, &response_handler) + request, response = client.request(method, url, body, headers, &response_handler) else - request, response = http_client.request(method, url, body, headers) {|r| r.read_body } + request, response = client.request(method, url, body, headers) {|r| r.read_body } end @last_response = response @@ -320,7 +324,6 @@ class Chef yield ensure @redirects_followed = 0 - @authenticator.sign_request = true end private diff --git a/lib/chef/http/cookie_manager.rb b/lib/chef/http/cookie_manager.rb index 067dc3ed22..f6dcf9aa32 100644 --- a/lib/chef/http/cookie_manager.rb +++ b/lib/chef/http/cookie_manager.rb @@ -32,16 +32,16 @@ class Chef end def handle_request(method, url, headers={}, data=false) - host, port = url.host, url.port - if @cookies.has_key?("#{host}:#{port}") - headers['Cookie'] = @cookies["#{host}:#{port}"] + @host, @port = url.host, url.port + if @cookies.has_key?("#{@host}:#{@port}") + headers['Cookie'] = @cookies["#{@host}:#{@port}"] end [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) if http_response['set-cookie'] - @cookies["#{host}:#{port}"] = http_response['set-cookie'] + @cookies["#{@host}:#{@port}"] = http_response['set-cookie'] end [http_response, rest_request, return_value] end diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb new file mode 100644 index 0000000000..741c48f5f6 --- /dev/null +++ b/lib/chef/http/json_input.rb @@ -0,0 +1,53 @@ +#-- +# Author:: Daniel DeLeo (<dan@opscode.com>) +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2013 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/json_compat' + +class Chef + class HTTP + + # Middleware that takes json input and turns it into raw text + class JSONInput + + def initialize(opts={}) + end + + def handle_request(method, url, headers={}, data=false) + if data + headers["Content-Type"] = 'application/json' + data = Chef::JSONCompat.to_json(data) + # Force encoding to binary to fix SSL related EOFErrors + # cf. http://tickets.opscode.com/browse/CHEF-2363 + # http://redmine.ruby-lang.org/issues/5233 + data.force_encoding(Encoding::BINARY) if data.respond_to?(:force_encoding) + end + [method, url, headers, data] + end + + def handle_response(http_response, rest_request, return_value) + [http_response, rest_request, return_value] + end + + def stream_response_handler(response) + nil + end + + end + end +end diff --git a/lib/chef/http/json_to_model_inflater.rb b/lib/chef/http/json_output.rb index 0b46054510..48407d933f 100644 --- a/lib/chef/http/json_to_model_inflater.rb +++ b/lib/chef/http/json_output.rb @@ -1,5 +1,6 @@ #-- # Author:: Daniel DeLeo (<dan@opscode.com>) +# Author:: John Keiser (<jkeiser@opscode.com>) # Copyright:: Copyright (c) 2013 Opscode, Inc. # License:: Apache License, Version 2.0 # @@ -17,29 +18,25 @@ # require 'chef/json_compat' +require 'chef/log' + class Chef class HTTP - # A Middleware-ish thing that takes an HTTP response, parses it as JSON if - # possible, and converts it into an appropriate model object if it contains - # a `json_class` key. - class JSONToModelInflater + # Middleware that takes an HTTP response, parses it as JSON if possible. + class JSONOutput def initialize(opts={}) + @raw_output = opts[:raw_output] + @inflate_json_class = opts[:inflate_json_class] end def handle_request(method, url, headers={}, data=false) # Ideally this should always set Accept to application/json, but # Chef::REST is sometimes used to make non-JSON requests, so it sets # Accept to the desired value before middlewares get called. - headers['Accept'] ||= "application/json" - headers["Content-Type"] = 'application/json' if data - json_body = data ? Chef::JSONCompat.to_json(data) : nil - # Force encoding to binary to fix SSL related EOFErrors - # cf. http://tickets.opscode.com/browse/CHEF-2363 - # http://redmine.ruby-lang.org/issues/5233 - json_body.force_encoding(Encoding::BINARY) if json_body.respond_to?(:force_encoding) - [method, url, headers, json_body] + headers['Accept'] ||= 'application/json' + [method, url, headers, data] end def handle_response(http_response, rest_request, return_value) @@ -47,7 +44,16 @@ class Chef # needed to keep conditional get stuff working correctly. return [http_response, rest_request, return_value] if return_value == false if http_response['content-type'] =~ /json/ - [http_response, rest_request, Chef::JSONCompat.from_json(http_response.body.chomp)] + if @raw_output + return_value = http_response.body.to_s + else + if @inflate_json_class + return_value = Chef::JSONCompat.from_json(http_response.body.chomp) + else + return_value = Chef::JSONCompat.from_json(http_response.body.chomp, :create_additions => false) + end + end + [http_response, rest_request, return_value] else Chef::Log.warn("Expected JSON response, but got content-type '#{http_response['content-type']}'") return [http_response, rest_request, http_response.body.to_s] diff --git a/lib/chef/http/json_to_model_output.rb b/lib/chef/http/json_to_model_output.rb new file mode 100644 index 0000000000..9bc90a52ae --- /dev/null +++ b/lib/chef/http/json_to_model_output.rb @@ -0,0 +1,34 @@ +#-- +# Author:: Daniel DeLeo (<dan@opscode.com>) +# Copyright:: Copyright (c) 2013 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/http/json_output' + +class Chef + class HTTP + + # A Middleware-ish thing that takes an HTTP response, parses it as JSON if + # possible, and converts it into an appropriate model object if it contains + # a `json_class` key. + class JSONToModelOutput < JSONOutput + def initialize(opts={}) + opts[:inflate_json_class] = true if !opts.has_key?(:inflate_json_class) + super + end + end + end +end diff --git a/lib/chef/http/simple.rb b/lib/chef/http/simple.rb new file mode 100644 index 0000000000..0ecb28846c --- /dev/null +++ b/lib/chef/http/simple.rb @@ -0,0 +1,16 @@ +require 'chef/http' +require 'chef/http/authenticator' +require 'chef/http/decompressor' + + +class Chef + class HTTP + + class Simple < HTTP + + use Decompressor + use CookieManager + + end + end +end diff --git a/lib/chef/knife/raw.rb b/lib/chef/knife/raw.rb index 5f357c6f1e..2756de1a5a 100644 --- a/lib/chef/knife/raw.rb +++ b/lib/chef/knife/raw.rb @@ -6,10 +6,13 @@ class Chef banner "knife raw REQUEST_PATH" deps do - require 'json' - require 'chef/rest' + require 'chef/json_compat' require 'chef/config' - require 'chef/chef_fs/raw_request' + require 'chef/http' + require 'chef/http/authenticator' + require 'chef/http/cookie_manager' + require 'chef/http/decompressor' + require 'chef/http/json_output' end option :method, @@ -29,6 +32,18 @@ class Chef :short => '-i FILE', :description => "Name of file to use for PUT or POST" + class RawInputServerAPI < Chef::HTTP + def initialize(options = {}) + options[:client_name] ||= Chef::Config[:node_name] + options[:signing_key_filename] ||= Chef::Config[:client_key] + super(Chef::Config[:chef_server_url], options) + end + use Chef::HTTP::JSONOutput + use Chef::HTTP::CookieManager + use Chef::HTTP::Decompressor + use Chef::HTTP::Authenticator + end + def run if name_args.length == 0 show_usage @@ -45,13 +60,18 @@ class Chef if config[:input] data = IO.read(config[:input]) end - chef_rest = Chef::REST.new(Chef::Config[:chef_server_url]) begin method = config[:method].to_sym - url = chef_rest.create_url(name_args[0]) - result = Chef::ChefFS::RawRequest.api_request(chef_rest, method, url, {}, data, :parse_json => config[:pretty]) - if result.is_a?(Hash) || result.is_a?(Array) - result = Chef::JSONCompat.to_json_pretty(result) + + if config[:pretty] + chef_rest = RawInputServerAPI.new + result = chef_rest.request(method, name_args[0], {'Content-Type' => 'application/json'}, data) + unless result.is_a?(String) + result = Chef::JSONCompat.to_json_pretty(result) + end + else + chef_rest = RawInputServerAPI.new(:raw_output => true) + result = chef_rest.request(method, name_args[0], {'Content-Type' => 'application/json'}, data) end output result rescue Timeout::Error => e diff --git a/lib/chef/provider/http_request.rb b/lib/chef/provider/http_request.rb index a5bc3b5e04..1e0aa8b4a0 100644 --- a/lib/chef/provider/http_request.rb +++ b/lib/chef/provider/http_request.rb @@ -17,26 +17,27 @@ # require 'tempfile' +require 'chef/http/simple' class Chef class Provider class HttpRequest < Chef::Provider - attr_accessor :rest + attr_accessor :http def whyrun_supported? true end def load_current_resource - @rest = Chef::REST.new(@new_resource.url, nil, nil) + @http = Chef::HTTP::Simple.new(@new_resource.url) end # Send a HEAD request to @new_resource.url, with ?message=@new_resource.message def action_head message = check_message(@new_resource.message) # returns true from Chef::REST if returns 2XX (Net::HTTPSuccess) - modified = @rest.head( + modified = @http.head( "#{@new_resource.url}?message=#{message}", @new_resource.headers ) @@ -53,9 +54,8 @@ class Chef converge_by("#{@new_resource} GET to #{@new_resource.url}") do message = check_message(@new_resource.message) - body = @rest.get( + body = @http.get( "#{@new_resource.url}?message=#{message}", - false, @new_resource.headers ) Chef::Log.info("#{@new_resource} GET to #{@new_resource.url} successful") @@ -67,7 +67,7 @@ class Chef def action_put converge_by("#{@new_resource} PUT to #{@new_resource.url}") do message = check_message(@new_resource.message) - body = @rest.put( + body = @http.put( "#{@new_resource.url}", message, @new_resource.headers @@ -81,7 +81,7 @@ class Chef def action_post converge_by("#{@new_resource} POST to #{@new_resource.url}") do message = check_message(@new_resource.message) - body = @rest.post( + body = @http.post( "#{@new_resource.url}", message, @new_resource.headers @@ -94,7 +94,7 @@ class Chef # Send a DELETE request to @new_resource.url def action_delete converge_by("#{@new_resource} DELETE to #{@new_resource.url}") do - body = @rest.delete( + body = @http.delete( "#{@new_resource.url}", @new_resource.headers ) diff --git a/lib/chef/provider/remote_file/http.rb b/lib/chef/provider/remote_file/http.rb index 9b65d87895..7eb2cda108 100644 --- a/lib/chef/provider/remote_file/http.rb +++ b/lib/chef/provider/remote_file/http.rb @@ -17,7 +17,7 @@ # limitations under the License. # -require 'chef/rest' +require 'chef/http/simple' require 'chef/digester' require 'chef/provider/remote_file' require 'chef/provider/remote_file/cache_control_data' @@ -58,9 +58,9 @@ class Chef def fetch tempfile = nil begin - rest = Chef::REST.new(uri, nil, nil, http_client_opts) - tempfile = rest.streaming_request(uri, headers) - update_cache_control_data(tempfile, rest.last_response) + http = Chef::HTTP::Simple.new(uri, http_client_opts) + tempfile = http.streaming_request(uri, headers) + update_cache_control_data(tempfile, http.last_response) rescue Net::HTTPRetriableError => e if e.response.is_a? Net::HTTPNotModified tempfile = nil diff --git a/lib/chef/rest.rb b/lib/chef/rest.rb index b264f96336..1a60fa093e 100644 --- a/lib/chef/rest.rb +++ b/lib/chef/rest.rb @@ -29,7 +29,8 @@ end require 'chef/http/authenticator' require 'chef/http/decompressor' -require 'chef/http/json_to_model_inflater' +require 'chef/http/json_input' +require 'chef/http/json_to_model_output' require 'chef/http/cookie_manager' require 'chef/config' require 'chef/exceptions' @@ -58,10 +59,14 @@ class Chef options[:signing_key_filename] = signing_key_filename super(url, options) - @chef_json_inflater = JSONToModelInflater.new(options) - @cookie_manager = CookieManager.new(options) @decompressor = Decompressor.new(options) @authenticator = Authenticator.new(options) + + @middlewares << JSONInput.new(options) + @middlewares << JSONToModelOutput.new(options) + @middlewares << CookieManager.new(options) + @middlewares << @decompressor + @middlewares << @authenticator end def signing_key_filename @@ -94,9 +99,9 @@ class Chef # to JSON inflated. def get(path, raw=false, headers={}) if raw - streaming_request(create_url(path), headers) + streaming_request(path, headers) else - api_request(:GET, create_url(path), headers) + request(:GET, path, headers) end end @@ -117,11 +122,6 @@ class Chef streaming_request(create_url(path), headers) {|tmp_file| yield tmp_file } end - # Chef::REST doesn't define middleware in the normal way for backcompat reasons, so it's hardcoded here. - def middlewares - [@chef_json_inflater, @cookie_manager, @decompressor, @authenticator] - end - alias :api_request :request alias :raw_http_request :send_http_request diff --git a/lib/chef/server_api.rb b/lib/chef/server_api.rb new file mode 100644 index 0000000000..e9e7593dd6 --- /dev/null +++ b/lib/chef/server_api.rb @@ -0,0 +1,41 @@ +# +# Author:: John Keiser (<jkeiser@opscode.com>) +# Copyright:: Copyright (c) 2012 Opscode, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'chef/http' +require 'chef/http/authenticator' +require 'chef/http/cookie_manager' +require 'chef/http/decompressor' +require 'chef/http/json_input' +require 'chef/http/json_output' + +class Chef + class ServerAPI < Chef::HTTP + + def initialize(url = Chef::Config[:chef_server_url], options = {}) + options[:client_name] ||= Chef::Config[:node_name] + options[:signing_key_filename] ||= Chef::Config[:client_key] + super(url, options) + end + + use Chef::HTTP::JSONInput + use Chef::HTTP::JSONOutput + use Chef::HTTP::CookieManager + use Chef::HTTP::Decompressor + use Chef::HTTP::Authenticator + end +end
\ No newline at end of file diff --git a/spec/integration/knife/raw_spec.rb b/spec/integration/knife/raw_spec.rb index 7ebe5476d9..b7412e4e8a 100644 --- a/spec/integration/knife/raw_spec.rb +++ b/spec/integration/knife/raw_spec.rb @@ -214,13 +214,13 @@ EOM end it 'knife raw /blah returns the raw text' do - knife('raw /blah').should_succeed <<EOM + knife('raw /blah').should_succeed(<<EOM, :stderr => "WARN: Expected JSON response, but got content-type 'text'\n") { "x": "y", "a": "b" } EOM end it 'knife raw --no-pretty /blah returns the raw text' do - knife('raw --no-pretty /blah').should_succeed <<EOM + knife('raw --no-pretty /blah').should_succeed(<<EOM, :stderr => "WARN: Expected JSON response, but got content-type 'text'\n") { "x": "y", "a": "b" } EOM end diff --git a/spec/integration/knife/upload_spec.rb b/spec/integration/knife/upload_spec.rb index 770efb2d46..46b804205f 100644 --- a/spec/integration/knife/upload_spec.rb +++ b/spec/integration/knife/upload_spec.rb @@ -1064,4 +1064,13 @@ EOM end end # with versioned cookbooks + when_the_chef_server 'has a user' do + user 'x', {} + when_the_repository 'has the same user with json_class in it' do + file 'users/x.json', { 'admin' => true, 'json_class' => 'Chef::WebUIUser' } + it 'knife upload /users/x.json succeeds' do + knife('upload /users/x.json').should_succeed "Updated /users/x.json\n" + end + end + end end diff --git a/spec/unit/provider/http_request_spec.rb b/spec/unit/provider/http_request_spec.rb index 436eaec558..e8ce5f9ae3 100644 --- a/spec/unit/provider/http_request_spec.rb +++ b/spec/unit/provider/http_request_spec.rb @@ -35,7 +35,7 @@ describe Chef::Provider::HttpRequest do describe "load_current_resource" do it "should set up a Chef::REST client, with no authentication" do - Chef::REST.should_receive(:new).with(@new_resource.url, nil, nil) + Chef::HTTP::Simple.should_receive(:new).with(@new_resource.url) @provider.load_current_resource end end @@ -45,21 +45,21 @@ describe Chef::Provider::HttpRequest do # run_action(x) forces load_current_resource to run; # that would overwrite our supplied mock Chef::Rest # object @provider.stub!(:load_current_resource).and_return(true) - @rest = mock("Chef::REST") - @provider.rest = @rest + @http = mock("Chef::REST") + @provider.http = @http end describe "action_get" do it "should inflate a message block at runtime" do @new_resource.message { "return" } - @rest.should_receive(:get).with("http://www.opscode.com/?message=return", false, {}) + @http.should_receive(:get).with("http://www.opscode.com/?message=return", {}) @provider.run_action(:get) @new_resource.should be_updated end it "should run a GET request" do - @rest.should_receive(:get).with("http://www.opscode.com/?message=is cool", false, {}) + @http.should_receive(:get).with("http://www.opscode.com/?message=is cool", {}) @provider.run_action(:get) @new_resource.should be_updated end @@ -67,14 +67,14 @@ describe Chef::Provider::HttpRequest do describe "action_put" do it "should run a PUT request with the message as the payload" do - @rest.should_receive(:put).with("http://www.opscode.com/", @new_resource.message, {}) + @http.should_receive(:put).with("http://www.opscode.com/", @new_resource.message, {}) @provider.run_action(:put) @new_resource.should be_updated end it "should inflate a message block at runtime" do @new_resource.stub!(:message).and_return(lambda { "return" }) - @rest.should_receive(:put).with("http://www.opscode.com/", "return", {}) + @http.should_receive(:put).with("http://www.opscode.com/", "return", {}) @provider.run_action(:put) @new_resource.should be_updated end @@ -82,14 +82,14 @@ describe Chef::Provider::HttpRequest do describe "action_post" do it "should run a PUT request with the message as the payload" do - @rest.should_receive(:post).with("http://www.opscode.com/", @new_resource.message, {}) + @http.should_receive(:post).with("http://www.opscode.com/", @new_resource.message, {}) @provider.run_action(:post) @new_resource.should be_updated end it "should inflate a message block at runtime" do @new_resource.message { "return" } - @rest.should_receive(:post).with("http://www.opscode.com/", "return", {}) + @http.should_receive(:post).with("http://www.opscode.com/", "return", {}) @provider.run_action(:post) @new_resource.should be_updated end @@ -97,7 +97,7 @@ describe Chef::Provider::HttpRequest do describe "action_delete" do it "should run a DELETE request" do - @rest.should_receive(:delete).with("http://www.opscode.com/", {}) + @http.should_receive(:delete).with("http://www.opscode.com/", {}) @provider.run_action(:delete) @new_resource.should be_updated end @@ -105,30 +105,30 @@ describe Chef::Provider::HttpRequest do describe "action_head" do before do - @provider.rest = @rest + @provider.http = @http end it "should inflate a message block at runtime" do @new_resource.message { "return" } - @rest.should_receive(:head).with("http://www.opscode.com/?message=return", {}).and_return("") + @http.should_receive(:head).with("http://www.opscode.com/?message=return", {}).and_return("") @provider.run_action(:head) @new_resource.should be_updated end it "should run a HEAD request" do - @rest.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return("") + @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", {}).and_return("") @provider.run_action(:head) @new_resource.should be_updated end it "should run a HEAD request with If-Modified-Since header" do @new_resource.headers "If-Modified-Since" => File.mtime(__FILE__).httpdate - @rest.should_receive(:head).with("http://www.opscode.com/?message=is cool", @new_resource.headers) + @http.should_receive(:head).with("http://www.opscode.com/?message=is cool", @new_resource.headers) @provider.run_action(:head) end it "doesn't call converge_by if HEAD does not return modified" do - @rest.should_receive(:head).and_return(false) + @http.should_receive(:head).and_return(false) @provider.should_not_receive(:converge_by) @provider.run_action(:head) end diff --git a/spec/unit/provider/remote_file/http_spec.rb b/spec/unit/provider/remote_file/http_spec.rb index 6ae19327eb..9fbe76f68e 100644 --- a/spec/unit/provider/remote_file/http_spec.rb +++ b/spec/unit/provider/remote_file/http_spec.rb @@ -155,7 +155,7 @@ describe Chef::Provider::RemoteFile::HTTP do describe "when fetching the uri" do let(:expected_http_opts) { {} } - let(:expected_http_args) { [uri, nil, nil, expected_http_opts] } + let(:expected_http_args) { [uri, expected_http_opts] } let(:tempfile_path) { "/tmp/chef-mock-tempfile-abc123" } @@ -164,7 +164,7 @@ describe Chef::Provider::RemoteFile::HTTP do let(:last_response) { {} } let(:rest) do - rest = mock(Chef::REST) + rest = mock(Chef::HTTP::Simple) rest.stub!(:streaming_request).and_return(tempfile) rest.stub!(:last_response).and_return(last_response) rest @@ -175,7 +175,7 @@ describe Chef::Provider::RemoteFile::HTTP do new_resource.use_last_modified(false) Chef::Provider::RemoteFile::CacheControlData.should_receive(:load_and_validate).with(uri, current_resource_checksum).and_return(cache_control_data) - Chef::REST.should_receive(:new).with(*expected_http_args).and_return(rest) + Chef::HTTP::Simple.should_receive(:new).with(*expected_http_args).and_return(rest) end @@ -188,7 +188,7 @@ describe Chef::Provider::RemoteFile::HTTP do lambda { fetcher.fetch }.should raise_error(Net::HTTPServerException) end - it "should return HTTPRetriableError when Chef::REST returns a 301" do + it "should return HTTPRetriableError when Chef::HTTP::Simple returns a 301" do r = Net::HTTPMovedPermanently.new("one", "two", "three") e = Net::HTTPRetriableError.new("301", r) rest.stub!(:streaming_request).and_raise(e) @@ -290,21 +290,21 @@ describe Chef::Provider::RemoteFile::HTTP do # CHEF-3140 # Some servers return tarballs as content type tar and encoding gzip, which - # is totally wrong. When this happens and gzip isn't disabled, Chef::REST + # is totally wrong. When this happens and gzip isn't disabled, Chef::HTTP::Simple # will decompress the file for you, which is not at all what you expected # to happen (you end up with an uncomressed tar archive instead of the # gzipped tar archive you expected). To work around this behavior, we # detect when users are fetching gzipped files and turn off gzip in - # Chef::REST. + # Chef::HTTP::Simple. it "should disable gzip compression in the client" do # Before block in the parent context has set an expectation on - # Chef::REST.new() being called with expected arguments. Here we fufil + # Chef::HTTP::Simple.new() being called with expected arguments. Here we fufil # that expectation, so that we can explicitly set it for this test. # This is intended to provide insurance that refactoring of the parent # context does not negate the value of this particular example. - Chef::REST.new(*expected_http_args) - Chef::REST.should_receive(:new).once.with(*expected_http_args).and_return(rest) + Chef::HTTP::Simple.new(*expected_http_args) + Chef::HTTP::Simple.should_receive(:new).once.with(*expected_http_args).and_return(rest) fetcher.fetch cache_control_data.etag.should be_nil cache_control_data.mtime.should be_nil diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb index 073ff691d6..fddb3dc407 100644 --- a/spec/unit/rest_spec.rb +++ b/spec/unit/rest_spec.rb @@ -76,27 +76,46 @@ describe Chef::REST do end it "makes a :GET request with the composed url object" do - @rest.should_receive(:api_request).with(:GET, @monkey_uri, {}) + @rest.should_receive(:send_http_request). + with(:GET, @monkey_uri, STANDARD_READ_HEADERS, false). + and_return([1,2,3]) + @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) + @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.get_rest("monkey") end it "makes a :GET reqest for a streaming download with the composed url" do - @rest.should_receive(:streaming_request).with(@monkey_uri, {}) + @rest.should_receive(:streaming_request).with('monkey', {}) @rest.get_rest("monkey", true) end - it "makes a :DELETE request with the composed url object" do - @rest.should_receive(:api_request).with(:DELETE, @monkey_uri, {}) + STANDARD_READ_HEADERS = {"Accept"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"} + STANDARD_WRITE_HEADERS = {"Accept"=>"application/json", "Content-Type"=>"application/json", "Accept"=>"application/json", "Accept-Encoding"=>"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"} + + it "makes a :DELETE request with the composed url object" do + @rest.should_receive(:send_http_request). + with(:DELETE, @monkey_uri, STANDARD_READ_HEADERS, false). + and_return([1,2,3]) + @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) + @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.delete_rest("monkey") end it "makes a :POST request with the composed url object and data" do - @rest.should_receive(:api_request).with(:POST, @monkey_uri, {}, "data") + @rest.should_receive(:send_http_request). + with(:POST, @monkey_uri, STANDARD_WRITE_HEADERS, "\"data\""). + and_return([1,2,3]) + @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) + @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.post_rest("monkey", "data") end it "makes a :PUT request with the composed url object and data" do - @rest.should_receive(:api_request).with(:PUT, @monkey_uri, {}, "data") + @rest.should_receive(:send_http_request). + with(:PUT, @monkey_uri, STANDARD_WRITE_HEADERS, "\"data\""). + and_return([1,2,3]) + @rest.should_receive(:apply_response_middleware).with(1,2,3).and_return([1,2,3]) + @rest.should_receive('success_response?'.to_sym).with(1).and_return(true) @rest.put_rest("monkey", "data") end end @@ -235,13 +254,13 @@ describe Chef::REST do it "should always include the X-Chef-Version header" do Net::HTTP::Get.should_receive(:new).with("/?foo=bar", @base_headers).and_return(@request_mock) - @rest.api_request(:GET, @url, {}) + @rest.request(:GET, @url, {}) end it "sets the user agent to chef-client" do # must reset to default b/c knife changes the UA Chef::REST::RESTRequest.user_agent = Chef::REST::RESTRequest::DEFAULT_UA - @rest.api_request(:GET, @url, {}) + @rest.request(:GET, @url, {}) @request_mock['User-Agent'].should match(/^Chef Client\/#{Chef::VERSION}/) end @@ -260,7 +279,7 @@ describe Chef::REST do request = Net::HTTP::Get.new(@url.path) Net::HTTP::Get.should_receive(:new).and_return(request) # will raise a Zlib error if incorrect - @rest.api_request(:GET, @url, {}).should == "ninja" + @rest.request(:GET, @url, {}).should == "ninja" end end context "when configured with custom http headers" do @@ -280,19 +299,19 @@ describe Chef::REST do url_string = an_instance_of(String) header_hash = hash_including(@custom_headers) Net::HTTP::Get.should_receive(:new).with(url_string, header_hash) - @rest.api_request(:GET, @url, {}) + @rest.request(:GET, @url, {}) end end it "should set the cookie for this request if one exists for the given host:port" do Chef::REST::CookieJar.instance["#{@url.host}:#{@url.port}"] = "cookie monster" Net::HTTP::Get.should_receive(:new).with("/?foo=bar", @base_headers.merge('Cookie' => "cookie monster")).and_return(@request_mock) - @rest.api_request(:GET, @url, {}) + @rest.request(:GET, @url, {}) end it "should build a new HTTP GET request" do Net::HTTP::Get.should_receive(:new).with("/?foo=bar", @base_headers).and_return(@request_mock) - @rest.api_request(:GET, @url, {}) + @rest.request(:GET, @url, {}) end it "should build a new HTTP POST request" do @@ -300,7 +319,7 @@ describe Chef::REST do expected_headers = @base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13') Net::HTTP::Post.should_receive(:new).with("/?foo=bar", expected_headers).and_return(request) - @rest.api_request(:POST, @url, {}, {:one=>:two}) + @rest.request(:POST, @url, {}, {:one=>:two}) request.body.should == '{"one":"two"}' end @@ -308,31 +327,31 @@ describe Chef::REST do request = Net::HTTP::Put.new(@url.path) expected_headers = @base_headers.merge("Content-Type" => 'application/json', 'Content-Length' => '13') Net::HTTP::Put.should_receive(:new).with("/?foo=bar",expected_headers).and_return(request) - @rest.api_request(:PUT, @url, {}, {:one=>:two}) + @rest.request(:PUT, @url, {}, {:one=>:two}) request.body.should == '{"one":"two"}' end it "should build a new HTTP DELETE request" do Net::HTTP::Delete.should_receive(:new).with("/?foo=bar", @base_headers).and_return(@request_mock) - @rest.api_request(:DELETE, @url) + @rest.request(:DELETE, @url) end it "should raise an error if the method is not GET/PUT/POST/DELETE" do - lambda { @rest.api_request(:MONKEY, @url) }.should raise_error(ArgumentError) + lambda { @rest.request(:MONKEY, @url) }.should raise_error(ArgumentError) end it "returns nil when the response is successful but content-type is not JSON" do - @rest.api_request(:GET, @url).should == "ninja" + @rest.request(:GET, @url).should == "ninja" end it "should inflate the body as to an object if JSON is returned" do @http_response.add_field('content-type', "application/json") @http_response.stub(:body).and_return('{"ohai2u":"json_api"}') - @rest.api_request(:GET, @url, {}).should == {"ohai2u"=>"json_api"} + @rest.request(:GET, @url, {}).should == {"ohai2u"=>"json_api"} end %w[ HTTPFound HTTPMovedPermanently HTTPSeeOther HTTPUseProxy HTTPTemporaryRedirect HTTPMultipleChoice ].each do |resp_name| - it "should call api_request again on a #{resp_name} response" do + it "should call request again on a #{resp_name} response" do resp_cls = Net.const_get(resp_name) resp_code = Net::HTTPResponse::CODE_TO_OBJ.keys.detect { |k| Net::HTTPResponse::CODE_TO_OBJ[k] == resp_cls } http_response = Net::HTTPFound.new("1.1", resp_code, "bob is somewhere else again") @@ -341,10 +360,10 @@ describe Chef::REST do @http_client.stub(:request).and_yield(http_response).and_return(http_response) - lambda { @rest.api_request(:GET, @url) }.should raise_error(Chef::Exceptions::RedirectLimitExceeded) + lambda { @rest.request(:GET, @url) }.should raise_error(Chef::Exceptions::RedirectLimitExceeded) [:PUT, :POST, :DELETE].each do |method| - lambda { @rest.api_request(method, @url) }.should raise_error(Chef::Exceptions::InvalidRedirect) + lambda { @rest.request(method, @url) }.should raise_error(Chef::Exceptions::InvalidRedirect) end end end @@ -355,7 +374,7 @@ describe Chef::REST do @http_client.stub(:request).and_yield(http_response).and_return(http_response) - @rest.api_request(:GET, @url).should be_false + @rest.request(:GET, @url).should be_false end describe "when the request fails" do @@ -376,7 +395,7 @@ describe Chef::REST do @rest.stub(:sleep) @http_client.stub(:request).and_yield(http_response).and_return(http_response) - lambda {@rest.api_request(:GET, @url)}.should raise_error(Net::HTTPFatalError) + lambda {@rest.request(:GET, @url)}.should raise_error(Net::HTTPFatalError) @log_stringio.string.should match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four')) end @@ -394,7 +413,7 @@ describe Chef::REST do @rest.stub(:http_retry_count).and_return(0) @http_client.stub(:request).and_yield(http_response).and_return(http_response) - lambda {@rest.api_request(:GET, @url)}.should raise_error(Net::HTTPFatalError) + lambda {@rest.request(:GET, @url)}.should raise_error(Net::HTTPFatalError) @log_stringio.string.should match(Regexp.escape('INFO: HTTP Request Returned 500 drooling from inside of mouth: Ears get sore!, Not even four')) end @@ -404,7 +423,7 @@ describe Chef::REST do http_response.stub(:read_body) @rest.stub(:sleep) @http_client.stub(:request).and_yield(http_response).and_return(http_response) - lambda {@rest.api_request(:GET, @url)}.should raise_error(Net::HTTPFatalError) + lambda {@rest.request(:GET, @url)}.should raise_error(Net::HTTPFatalError) end end |