lib/berkshelf/ridley_compat.rb
require "chef/server_api"
require "chef/http/simple_json"
require "chef/http/simple"
require_relative "api_client/errors"
require "chef/config"
require "chef/cookbook_manifest"
module Berkshelf
module RidleyCompatAPI
def initialize(**opts)
opts = opts.dup
opts[:ssl] ||= {}
chef_opts = {}
chef_opts[:rest_timeout] = opts[:timeout] if opts[:timeout] # opts[:open_timeout] is ignored on purpose
chef_opts[:headers] = opts[:headers] if opts[:headers]
chef_opts[:client_name] = opts[:client_name] if opts[:client_name]
chef_opts[:signing_key_filename] = opts[:client_key] if opts[:client_key]
chef_opts[:verify_api_cert] = opts[:ssl][:verify] || opts[:ssl][:verify].nil?
chef_opts[:ssl_verify_mode] = chef_opts[:verify_api_cert] ? :verify_peer : :verify_none
chef_opts[:ssl_ca_path] = opts[:ssl][:ca_path] if opts[:ssl][:ca_path]
chef_opts[:ssl_ca_file] = opts[:ssl][:ca_file] if opts[:ssl][:ca_file]
chef_opts[:ssl_client_cert] = opts[:ssl][:client_cert] if opts[:ssl][:client_cert]
chef_opts[:ssl_client_key] = opts[:ssl][:client_key] if opts[:ssl][:client_key]
chef_opts[:version_class] = opts[:version_class] if opts[:version_class]
# chef/http/ssl_policies.rb reads only from Chef::Config and not from the opts in the constructor
Chef::Config[:verify_api_cert] = chef_opts[:verify_api_cert]
Chef::Config[:ssl_verify_mode] = chef_opts[:ssl_verify_mode]
super(opts[:server_url].to_s, **chef_opts)
end
# for compat with Ridley::Connection
def server_url
url
end
def get(url)
super(url)
rescue Net::HTTPExceptions => e
case e.response.code
when "404"
raise Berkshelf::APIClient::ServiceNotFound, "service not found at: #{url}"
when /^5/
raise Berkshelf::APIClient::ServiceUnavailable, "service unavailable at: #{url}"
else
raise Berkshelf::APIClient::BadResponse, "bad response #{e.response}"
end
rescue Errno::ETIMEDOUT, Timeout::Error
raise Berkshelf::APIClient::TimeoutError, "Unable to connect to: #{url}"
rescue Errno::EHOSTUNREACH, Errno::ECONNREFUSED => e
raise Berkshelf::APIClient::ServiceUnavailable, e
end
module ClassMethods
def new_client(**opts, &block)
client = new(**opts)
yield client
# ensure
# FIXME: does Chef::HTTP support close anywhere? this will just leak open fds
end
end
def self.included(klass)
klass.extend ClassMethods
end
end
# This is for simple HTTP
class RidleyCompatSimple < ::Chef::ServerAPI
use Chef::HTTP::Decompressor
use Chef::HTTP::CookieManager
use Chef::HTTP::ValidateContentLength
include RidleyCompatAPI
end
# This is for JSON-REST
class RidleyCompatJSON < ::Chef::HTTP::SimpleJSON
use Chef::HTTP::JSONInput
use Chef::HTTP::JSONOutput
use Chef::HTTP::CookieManager
use Chef::HTTP::Decompressor
use Chef::HTTP::RemoteRequestID
use Chef::HTTP::ValidateContentLength
include RidleyCompatAPI
end
# RidleyCompat is the ServerAPI, but we inherit from Chef::HTTP::Simple and then include all our middlewares
# and then need to include our own CompatAPI. The end result is a ridley-esque way of talking to a chef server.
class RidleyCompat < ::Chef::HTTP::Simple
use Chef::HTTP::JSONInput
use Chef::HTTP::JSONOutput
use Chef::HTTP::CookieManager
use Chef::HTTP::Decompressor
use Chef::HTTP::Authenticator
use Chef::HTTP::RemoteRequestID
use Chef::HTTP::APIVersions if defined?(Chef::HTTP::APIVersions)
use Chef::HTTP::ValidateContentLength
include RidleyCompatAPI
def initialize(**opts)
opts[:version_class] = Chef::CookbookManifestVersions
super(**opts)
end
end
end