diff options
-rw-r--r-- | lib/chef/chef_fs/file_system/acl_entry.rb | 2 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/chef_server_root_dir.rb | 8 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/cookbook_dir.rb | 2 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/cookbook_file.rb | 7 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/cookbooks_dir.rb | 4 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/data_bag_dir.rb | 2 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/data_bags_dir.rb | 2 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/rest_list_dir.rb | 2 | ||||
-rw-r--r-- | lib/chef/chef_fs/file_system/rest_list_entry.rb | 4 | ||||
-rw-r--r-- | lib/chef/http.rb | 19 | ||||
-rw-r--r-- | lib/chef/http/json_input.rb | 56 | ||||
-rw-r--r-- | lib/chef/http/json_output.rb (renamed from lib/chef/http/json_to_model_inflater.rb) | 26 | ||||
-rw-r--r-- | lib/chef/http/json_to_model_output.rb | 34 | ||||
-rw-r--r-- | lib/chef/rest.rb | 10 | ||||
-rw-r--r-- | lib/chef/server_api.rb | 41 | ||||
-rw-r--r-- | spec/integration/knife/redirection_spec.rb | 4 | ||||
-rw-r--r-- | spec/unit/rest_spec.rb | 31 |
17 files changed, 197 insertions, 57 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 f74fc8e463..0287c7ab20 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,14 +57,14 @@ class Chef end def rest - Chef::REST.new(chef_server_url, chef_username, chef_private_key, { :raw_output => true }) + Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key, :raw_output => true) end def rest_json - Chef::REST.new(chef_server_url, chef_username, chef_private_key, { :inflate_json_class => false }) + Chef::ServerAPI.new(chef_server_url, :client_name => chef_username, :signing_key_filename => chef_private_key) end - def rest_normal + 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 79540067f7..3f5bffe264 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 diff --git a/lib/chef/chef_fs/file_system/cookbook_file.rb b/lib/chef/chef_fs/file_system/cookbook_file.rb index 552f360173..57f2ca3f64 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 2358408585..793f31d060 100644 --- a/lib/chef/chef_fs/file_system/cookbooks_dir.rb +++ b/lib/chef/chef_fs/file_system/cookbooks_dir.rb @@ -106,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 => root.rest_normal) + 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) @@ -128,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 => root.rest_normal) + 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 bdae077586..7c9d822f08 100644 --- a/lib/chef/chef_fs/file_system/data_bags_dir.rb +++ b/lib/chef/chef_fs/file_system/data_bags_dir.rb @@ -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/rest_list_dir.rb b/lib/chef/chef_fs/file_system/rest_list_dir.rb index 05ee031954..3a0ea4f37e 100644 --- a/lib/chef/chef_fs/file_system/rest_list_dir.rb +++ b/lib/chef/chef_fs/file_system/rest_list_dir.rb @@ -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 420dac9c72..3963afb8da 100644 --- a/lib/chef/chef_fs/file_system/rest_list_entry.rb +++ b/lib/chef/chef_fs/file_system/rest_list_entry.rb @@ -67,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 @@ -162,7 +162,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/http.rb b/lib/chef/http.rb index 50e0509b91..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={}) - 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={}) - 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={}) - 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={}) - request(:POST, create_url(path), headers, json) + request(:POST, path, headers, json) end # Send an HTTP DELETE request to the path @@ -126,12 +126,13 @@ class Chef # === Parameters # path:: path part of the request URL def delete(path, headers={}) - 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) @@ -153,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 @@ -192,6 +194,7 @@ class Chef protected def create_url(path) + return path if path.is_a?(URI) if path =~ /^(http|https):\/\// URI.parse(path) else diff --git a/lib/chef/http/json_input.rb b/lib/chef/http/json_input.rb new file mode 100644 index 0000000000..5f8b700e85 --- /dev/null +++ b/lib/chef/http/json_input.rb @@ -0,0 +1,56 @@ +#-- +# 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={}) + @raw_input = opts[:raw_input] + end + + def handle_request(method, url, headers={}, data=false) + if data + headers["Content-Type"] = 'application/json' + if !@raw_input + 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 + 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 31cd18a6b6..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,36 +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_input = opts[:raw_input] @raw_output = opts[:raw_output] - @inflate_json_class = opts.has_key?(:inflate_json_class) ? opts[:inflate_json_class] : true + @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 - if @raw_input - json_body = data || nil - else - json_body = data ? Chef::JSONCompat.to_json(data) : nil - end - # 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) 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/rest.rb b/lib/chef/rest.rb index 236e4cbac2..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' @@ -61,7 +62,8 @@ class Chef @decompressor = Decompressor.new(options) @authenticator = Authenticator.new(options) - @middlewares << JSONToModelInflater.new(options) + @middlewares << JSONInput.new(options) + @middlewares << JSONToModelOutput.new(options) @middlewares << CookieManager.new(options) @middlewares << @decompressor @middlewares << @authenticator @@ -97,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 - request(:GET, create_url(path), headers) + request(:GET, path, headers) end end 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/redirection_spec.rb b/spec/integration/knife/redirection_spec.rb index 48944b1140..5af9fd36e1 100644 --- a/spec/integration/knife/redirection_spec.rb +++ b/spec/integration/knife/redirection_spec.rb @@ -50,9 +50,7 @@ describe 'redirection' do end it 'knife list /roles returns the role' do - pending 'merge of api-code-path branch' do - knife('list /roles').should_succeed "/roles/x.json\n" - end + knife('list /roles').should_succeed "/roles/x.json\n" end end end diff --git a/spec/unit/rest_spec.rb b/spec/unit/rest_spec.rb index 9352afad11..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(: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(: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(: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(: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 |