Class: Chef::Formatters::ErrorInspectors::CookbookResolveErrorInspector

Inherits:
Object
  • Object
show all
Includes:
APIErrorFormatting
Defined in:
lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb

Constant Summary

Constants included from APIErrorFormatting

APIErrorFormatting::NETWORK_ERROR_CLASSES

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from APIErrorFormatting

#api_key, #clock_skew?, #describe_400_error, #describe_401_error, #describe_500_error, #describe_503_error, #describe_http_error, #describe_network_errors, #format_rest_error, #server_url, #username

Constructor Details

#initialize(expanded_run_list, exception) ⇒ CookbookResolveErrorInspector

Returns a new instance of CookbookResolveErrorInspector.



31
32
33
34
# 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

Instance Attribute Details

#exceptionObject (readonly)

Returns the value of attribute exception.



26
27
28
# File 'lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb', line 26

def exception
  @exception
end

#expanded_run_listObject (readonly)

Returns the value of attribute expanded_run_list.



27
28
29
# File 'lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb', line 27

def expanded_run_list
  @expanded_run_list
end

Instance Method Details

#add_explanation(error_description) ⇒ Object



36
37
38
39
40
41
42
43
44
45
# 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) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# 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
  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

  error_description.section("Missing Cookbooks:", explanation)
  error_description.section("Expanded Run List:", expanded_run_list_ul)
end

#expanded_run_list_ulObject



106
107
108
# File 'lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb', line 106

def expanded_run_list_ul
  @expanded_run_list.map {|i| "* #{i}"}.join("\n")
end

#extract_412_error_messageObject

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."}


117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb', line 117

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) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# 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",<<-E)
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.
E
    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