Class: RightScale::CloudApi::ResponseAnalyzer
- Defined in:
- lib/base/routines/response_analyzer.rb
Overview
The routine analyzes HTTP responses and in the case of HTTP error it takes actions defined through error_pattern definitions.
Defined Under Namespace
Classes: Error
Instance Attribute Summary
Attributes inherited from Routine
Instance Method Summary collapse
-
#process ⇒ Object
Analyzes an HTTP response.
Methods inherited from Routine
#cloud_api_logger, #execute, #invoke_callback_method, #options, #reset, #with_timer
Instance Method Details
#process ⇒ Object
Analyzes an HTTP response.
In the case of 4xx, 5xx HTTP errors the method parses the response body to get the error message. Then it tries to find an error pattern that would match to the response. If the pattern found it takes the action (:retry, :abort, :disconnect_and_abort or :reconnect_and_retry) acordingly to the error patern. If the pattern not fount it just fails with RightScale::CloudApi::CloudError.
In the case of 2xx code the method does nothing.
In the case of any other unexpected HTTP code it fails with RightScale::CloudApi::CloudError.
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 79 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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/base/routines/response_analyzer.rb', line 53 def process # Extract the current response and log it. response = data[:response][:instance] unless response.nil? cloud_api_logger.log("Response received: #{response.to_s}", :response_analyzer) cloud_api_logger.log("Response headers: #{response.headers_info}", :response_analyzer) log_method = (response.is_error? || response.is_redirect?) ? :response_analyzer_body_error : :response_analyzer_body cloud_api_logger.log("Response body: #{response.body_info}", log_method) end code = data[:response][:instance].code body = data[:response][:instance].body close_current_connection_proc = data[:callbacks][:close_current_connection] # Analyze the response code. case code when /^(5..|4..)/ # Try to parse the received error message. = if data[:options][:response_error_parser] parser = data[:options][:response_error_parser] with_timer("Error parsing with #{parser}") do parser::parse(data[:response][:instance], data[:options]) end else "#{code}: #{body.to_s}" end # Get the list of patterns. error_patterns = data[:options][:error_patterns] || [] opts = { :request => data[:request][:instance], :response => data[:response][:instance], :verb => data[:request][:verb], :params => data[:request][:orig_params].dup } # Walk through all the patterns and find the first that matches. error_patterns.each do |pattern| if Utils::pattern_matches?(pattern, opts) cloud_api_logger.log("Error code: #{code}, pattern match: #{pattern.inspect}", :response_analyzer, :warn) # Take the required action. case pattern[:action] when :disconnect_and_abort close_current_connection_proc && close_current_connection_proc.call("Error code: #{code}") fail(HttpError::new(code, )) when :reconnect_and_retry close_current_connection_proc && close_current_connection_proc.call("Error code: #{code}") @data[:vars][:retry][:http] = { :code => code, :message => } fail(RetryAttempt::new) when :abort fail(HttpError::new(code, )) when :retry invoke_callback_method(data[:options][:before_retry_callback], :routine => self, :pattern => pattern, :opts => opts) @data[:vars][:retry][:http] = { :code => code, :message => } fail(RetryAttempt::new) end end end # The default behavior: this guy hits when there is no any matching pattern fail(HttpError::new(code, )) when /^3..$/ # In the case of redirect: update a request URI and retry location = Array(data[:response][:instance].headers['location']).first # ----- AMAZON HACK BEGIN ---------------------------------------------------------- # Amazon sometimes hide a location host into a response body. if location._blank? && body && body[/<Endpoint>(.*?)<\/Endpoint>/] && $1 data[:connection][:uri].host = $1 location = data[:connection][:uri].to_s end # ----- AMAZON HACK END ------------------------------------------------------------ # Replace URI and retry if the location was successfully set unless location._blank? data[:connection][:uri] = ::URI.parse(location) old_request = data[:request].delete(:instance) data[:request].delete(:path) cloud_api_logger.log("Redirect detected: #{location.inspect}", :response_analyzer) invoke_callback_method(data[:options][:before_redirect_callback], :routine => self, :old_request => old_request, :location => location) raise(RetryAttempt::new) else # ----- OPENSTACK BEGIN ---------------------------------------------------------- # some OS services like Glance returns a list of supported api versions with status 300 # if there is at least one href in the body we need to further analize it in the OS manager return true if body && body[/href/] # ----- OPENSTACK END ---------------------------------------------------------- raise HttpError::new(code, "Cannot parse a redirect location") end when /^2../ # There is nothing to do on 2xx code return true else fail(Error::new("Unexpected response code: #{code.inspect}")) end end |