diff options
Diffstat (limited to 'chef/lib/chef/rest.rb')
-rw-r--r-- | chef/lib/chef/rest.rb | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/chef/lib/chef/rest.rb b/chef/lib/chef/rest.rb new file mode 100644 index 0000000000..b78df6c35f --- /dev/null +++ b/chef/lib/chef/rest.rb @@ -0,0 +1,150 @@ +# +# Author:: Adam Jacob (<adam@hjksolutions.com>) +# Copyright:: Copyright (c) 2008 HJK Solutions, LLC +# 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 File.join(File.dirname(__FILE__), "mixin", "params_validate") +require 'net/https' +require 'uri' +require 'json' +require 'tempfile' + +class Chef + class REST + + def initialize(url) + @url = url + @cookies = Hash.new + end + + # Send an HTTP GET request to the path + # + # === Parameters + # path:: The path to GET + # raw:: Whether you want the raw body returned, or JSON inflated. Defaults + # to JSON inflated. + def get_rest(path, raw=false) + run_request(:GET, create_url(path), false, 10, raw) + end + + # Send an HTTP DELETE request to the path + def delete_rest(path) + run_request(:DELETE, create_url(path)) + end + + # Send an HTTP POST request to the path + def post_rest(path, json) + run_request(:POST, create_url(path), json) + end + + # Send an HTTP PUT request to the path + def put_rest(path, json) + run_request(:PUT, create_url(path), json) + end + + def create_url(path) + if path =~ /^(http|https):\/\// + URI.parse(path) + else + URI.parse("#{@url}/#{path}") + end + end + + # Actually run an HTTP request. First argument is the HTTP method, + # which should be one of :GET, :PUT, :POST or :DELETE. Next is the + # URL, then an object to include in the body (which will be converted with + # .to_json) and finally, the limit of HTTP Redirects to follow (10). + # + # Typically, you won't use this method -- instead, you'll use one of + # the helper methods (get_rest, post_rest, etc.) + # + # Will return the body of the response on success. + def run_request(method, url, data=false, limit=10, raw=false) + raise ArgumentError, 'HTTP redirect too deep' if limit == 0 + + http = Net::HTTP.new(url.host, url.port) + if url.scheme == "https" + http.use_ssl = true + if Chef::Config[:ssl_verify_mode] == :verify_none + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + end + end + http.read_timeout = Chef::Config[:rest_timeout] + headers = Hash.new + unless raw + headers = { + 'Accept' => "application/json", + } + end + if @cookies["#{url.host}:#{url.port}"] + headers['Cookie'] = @cookies["#{url.host}:#{url.port}"] + end + req = nil + case method + when :GET + req_path = "#{url.path}" + req_path << "?#{url.query}" if url.query + req = Net::HTTP::Get.new(req_path, headers) + when :POST + headers["Content-Type"] = 'application/json' if data + req = Net::HTTP::Post.new(url.path, headers) + req.body = data.to_json if data + when :PUT + headers["Content-Type"] = 'application/json' if data + req = Net::HTTP::Put.new(url.path, headers) + req.body = data.to_json if data + when :DELETE + req_path = "#{url.path}" + req_path << "?#{url.query}" if url.query + req = Net::HTTP::Delete.new(req_path, headers) + else + raise ArgumentError, "You must provide :GET, :PUT, :POST or :DELETE as the method" + end + Chef::Log.debug("Sending HTTP Request via #{req.method} to #{req.path}") + res = http.request(req) + + Chef::Log.debug("HTTP request headers: #{req.to_hash.inspect} ") + + Chef::Log.debug("HTTP response headers: #{res.to_hash.inspect} ") + + if res.kind_of?(Net::HTTPSuccess) + if res['set-cookie'] + @cookies["#{url.host}:#{url.port}"] = res['set-cookie'] + end + if res['content-type'] =~ /json/ + JSON.parse(res.body) + else + if raw + tf = Tempfile.new("chef-rest") + tf.print(res.body) + tf.close + tf + else + res.body + end + end + elsif res.kind_of?(Net::HTTPFound) + if res['set-cookie'] + @cookies["#{url.host}:#{url.port}"] = res['set-cookie'] + end + run_request(:GET, create_url(res['location']), false, limit - 1, raw) + else + res.error! + end + end + + end +end |