summaryrefslogtreecommitdiff
path: root/lib/chef
diff options
context:
space:
mode:
authorJohn Keiser <jkeiser@opscode.com>2013-10-11 13:57:07 -0700
committerJohn Keiser <jkeiser@opscode.com>2013-10-11 13:57:07 -0700
commit12b902d5aa539f14ee2e25f1a1ca702f8fb81377 (patch)
tree6db3aef50f1f3e823cd928491796a09c40a822e0 /lib/chef
parent6d58ff931dda2d5bfa0eb8b7feadf5cd0fb37c8e (diff)
parent5e5f5b1b1e431612a40bf235c4081dc5ff885bef (diff)
downloadchef-12b902d5aa539f14ee2e25f1a1ca702f8fb81377.tar.gz
Use Chef::HTTP for knife-essentials raw requests, fix CHEF-4515 in the balance
Diffstat (limited to 'lib/chef')
-rw-r--r--lib/chef/chef_fs/file_system/acl_entry.rb2
-rw-r--r--lib/chef/chef_fs/file_system/chef_server_root_dir.rb10
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_dir.rb4
-rw-r--r--lib/chef/chef_fs/file_system/cookbook_file.rb7
-rw-r--r--lib/chef/chef_fs/file_system/cookbooks_dir.rb9
-rw-r--r--lib/chef/chef_fs/file_system/data_bag_dir.rb2
-rw-r--r--lib/chef/chef_fs/file_system/data_bags_dir.rb4
-rw-r--r--lib/chef/chef_fs/file_system/nodes_dir.rb2
-rw-r--r--lib/chef/chef_fs/file_system/rest_list_dir.rb4
-rw-r--r--lib/chef/chef_fs/file_system/rest_list_entry.rb10
-rw-r--r--lib/chef/chef_fs/raw_request.rb83
-rw-r--r--lib/chef/http.rb31
-rw-r--r--lib/chef/http/cookie_manager.rb8
-rw-r--r--lib/chef/http/json_input.rb53
-rw-r--r--lib/chef/http/json_output.rb (renamed from lib/chef/http/json_to_model_inflater.rb)32
-rw-r--r--lib/chef/http/json_to_model_output.rb34
-rw-r--r--lib/chef/http/simple.rb16
-rw-r--r--lib/chef/knife/raw.rb36
-rw-r--r--lib/chef/provider/http_request.rb16
-rw-r--r--lib/chef/provider/remote_file/http.rb8
-rw-r--r--lib/chef/rest.rb20
-rw-r--r--lib/chef/server_api.rb41
22 files changed, 262 insertions, 170 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