class Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector
Attributes
exception[R]
expanded_run_list[R]
Public Class Methods
new(expanded_run_list, exception)
click to toggle source
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 31 def initialize(expanded_run_list, exception) @expanded_run_list = expanded_run_list @exception = exception end
Public Instance Methods
add_explanation(error_description)
click to toggle source
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 36 def add_explanation(error_description) case exception when Net::HTTPServerException, Net::HTTPFatalError humanize_http_exception(error_description) when *NETWORK_ERROR_CLASSES describe_network_errors(error_description) else error_description.section("Unexpected Error:","#{exception.class.name}: #{exception.message}") end end
describe_412_error(error_description)
click to toggle source
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 80 def describe_412_error(error_description) explanation = "" error_reasons = extract_412_error_message # Prepare the error message if there is detailed information # about individual cookbooks. if !error_reasons.respond_to?(:key?) explanation << error_reasons.to_s else if error_reasons.key?("non_existent_cookbooks") && !Array(error_reasons["non_existent_cookbooks"]).empty? explanation << "The following cookbooks are required by the client but don't exist on the server:\n" Array(error_reasons["non_existent_cookbooks"]).each do |cookbook| explanation << "* #{cookbook}\n" end explanation << "\n" end if error_reasons.key?("cookbooks_with_no_versions") && !Array(error_reasons["cookbooks_with_no_versions"]).empty? explanation << "The following cookbooks exist on the server, but there is no version that meets\nthe version constraints in this environment:\n" Array(error_reasons["cookbooks_with_no_versions"]).each do |cookbook| explanation << "* #{cookbook}\n" end explanation << "\n" end end if !explanation.empty? error_description.section("Missing Cookbooks:", explanation) else # If we don't have any cookbook details print a more # generic error message. if error_reasons.respond_to?(:key?) && error_reasons["message"] explanation << "Error message: #{error_reasons["message"]}\n" end explanation << <<EOM You might be able to resolve this issue with: 1-) Removing cookbook versions that depend on deleted cookbooks. 2-) Removing unused cookbook versions. 3-) Pinning exact cookbook versions using environments. EOM error_description.section("Cookbook dependency resolution error:", explanation) end error_description.section("Expanded Run List:", expanded_run_list_ul) end
expanded_run_list_ul()
click to toggle source
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 126 def expanded_run_list_ul @expanded_run_list.map {|i| "* #{i}"}.join("\n") end
extract_412_error_message()
click to toggle source
In my tests, the error from the server is double JSON encoded, but we should not rely on this not getting fixed.
Return should be a Hash like this:
{ "non_existent_cookbooks" => ["nope"], "cookbooks_with_no_versions" => [], "message" => "Run list contains invalid items: no such cookbook nope."}
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 137 def extract_412_error_message # Example: # "{\"error\":[\"{\\\"non_existent_cookbooks\\\":[\\\"nope\\\"],\\\"cookbooks_with_no_versions\\\":[],\\\"message\\\":\\\"Run list contains invalid items: no such cookbook nope.\\\"}\"]}" wrapped_error_message = attempt_json_parse(exception.response.body) unless wrapped_error_message.kind_of?(Hash) && wrapped_error_message.key?("error") return wrapped_error_message.to_s end error_description = Array(wrapped_error_message["error"]).first if error_description.kind_of?(Hash) return error_description end attempt_json_parse(error_description) end
humanize_http_exception(error_description)
click to toggle source
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 47 def humanize_http_exception(error_description) response = exception.response case response when Net::HTTPUnauthorized # TODO: this is where you'd see conflicts b/c of username/clientname stuff describe_401_error(error_description) when Net::HTTPForbidden # TODO: we're rescuing errors from Node.find_or_create # * could be no write on nodes container # * could be no read on the node error_description.section("Authorization Error","This client is not authorized to read some of the information required to access its coobooks (HTTP 403). To access its cookbooks, a client needs to be able to read its environment and all of the cookbooks in its expanded run list. ") error_description.section("Expanded Run List:", expanded_run_list_ul) error_description.section("Server Response:", format_rest_error) when Net::HTTPPreconditionFailed describe_412_error(error_description) when Net::HTTPBadRequest describe_400_error(error_description) when Net::HTTPNotFound when Net::HTTPInternalServerError describe_500_error(error_description) when Net::HTTPBadGateway, Net::HTTPServiceUnavailable describe_503_error(error_description) else describe_http_error(error_description) end end
Private Instance Methods
attempt_json_parse(maybe_json_string)
click to toggle source
# File lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb, line 155 def attempt_json_parse(maybe_json_string) Chef::JSONCompat.from_json(maybe_json_string) rescue Exception maybe_json_string end