Class: Puppet::Util::Puppetdb::Http
- Inherits:
-
Object
- Object
- Puppet::Util::Puppetdb::Http
- Defined in:
- lib/puppet/util/puppetdb/http.rb
Constant Summary collapse
- SERVER_URL_FAIL_MSG =
"Failing over to the next PuppetDB server_url in the 'server_urls' list"- @@last_good_query_server_url_index =
Atom.new(0)
Class Method Summary collapse
-
.action(path_suffix, request_mode, &http_callback) ⇒ Response
Setup an http connection, provide a block that will do something with that http connection.
- .broadcast_action(path_suffix, server_urls, http_callback) ⇒ Object
-
.check_http_response(response, server_url, route) ⇒ Object
Check an http reponse from puppetdb; log a useful message if it looks like something went wrong.
-
.concat_url_snippets(snippet1, snippet2) ⇒ String
private
Concat two server_url snippets, taking into account a trailing/leading slash to ensure a correct server_url is constructed.
- .failover_action(path_suffix, server_urls, sticky, http_callback) ⇒ Object
- .raise_request_error(response, response_error, path_suffix) ⇒ Object
- .reset_query_failover ⇒ Object
-
.with_http_error_logging(server_url, route, &cb) ⇒ Object
Run the given block (cb) in a begin/rescue, catching common network exceptions and logging useful information about them.
Class Method Details
.action(path_suffix, request_mode, &http_callback) ⇒ Response
Setup an http connection, provide a block that will do something with that http connection. The block should be a two argument block, accepting the connection (which you can call get or post on for example) and the properly constructed path, which will be the concatenated version of any url_prefix and the path passed in.
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/puppet/util/puppetdb/http.rb', line 203 def self.action(path_suffix, request_mode, &http_callback) config = Puppet::Util::Puppetdb.config case request_mode when :query self.failover_action(path_suffix, config.server_urls, config.sticky_read_failover, http_callback) when :command submit_server_urls = config.server_urls + config.submit_only_server_urls if config.command_broadcast self.broadcast_action(path_suffix, submit_server_urls, http_callback) else self.failover_action(path_suffix, submit_server_urls, false, http_callback) end else raise Puppet::Error, "Unknown request mode: #{request_mode}" end end |
.broadcast_action(path_suffix, server_urls, http_callback) ⇒ Object
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/puppet/util/puppetdb/http.rb', line 162 def self.broadcast_action(path_suffix, server_urls, http_callback) response = nil response_error = nil config = Puppet::Util::Puppetdb.config successful_submit_count = 0 for server_url in server_urls route = concat_url_snippets(server_url.request_uri, path_suffix) request_exception = with_http_error_logging(server_url, route) { http = Puppet::Network::HttpPool.http_instance(server_url.host, server_url.port) response = Timeout.timeout(config.server_url_timeout) do http_callback.call(http, route) end } if request_exception.nil? response_error = check_http_response(response, server_url, route) if response_error.nil? successful_submit_count += 1 end end end if successful_submit_count < config.min_successful_submissions raise_request_error(response, response_error, path_suffix) end response end |
.check_http_response(response, server_url, route) ⇒ Object
Check an http reponse from puppetdb; log a useful message if it looks like something went wrong. Return a symbol indicating the problem (:server_error, :notfound, or :other_404), or nil if there wasn’t one.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/puppet/util/puppetdb/http.rb', line 87 def self.check_http_response(response, server_url, route) if response.is_a? Net::HTTPServerError Puppet.warning("Error connecting to #{server_url.host} on #{server_url.port} at route #{route}, " \ "error message received was '#{response.message}'. #{SERVER_URL_FAIL_MSG}") :server_error elsif response.is_a? Net::HTTPNotFound if response.body && response.body.chars.first == "{" # If it appears to be json, we've probably gotten an authentic 'not found' message. Puppet.debug("HTTP 404 (probably normal) when connecting to #{server_url.host} on #{server_url.port} " \ "at route #{route}, error message received was '#{response.message}'. #{SERVER_URL_FAIL_MSG}") :notfound else # But we can also get 404s when conneting to a puppetdb that's still starting or due to misconfiguration. Puppet.warning("Error connecting to #{server_url.host} on #{server_url.port} at route #{route}, " \ "error message received was '#{response.message}'. #{SERVER_URL_FAIL_MSG}") :other_404 end else nil end end |
.concat_url_snippets(snippet1, snippet2) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Concat two server_url snippets, taking into account a trailing/leading slash to ensure a correct server_url is constructed
22 23 24 25 26 27 28 29 30 |
# File 'lib/puppet/util/puppetdb/http.rb', line 22 def self.concat_url_snippets(snippet1, snippet2) if snippet1.end_with?('/') and snippet2.start_with?('/') snippet1 + snippet2[1..-1] elsif !snippet1.end_with?('/') and !snippet2.start_with?('/') snippet1 + '/' + snippet2 else snippet1 + snippet2 end end |
.failover_action(path_suffix, server_urls, sticky, http_callback) ⇒ Object
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 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/puppet/util/puppetdb/http.rb', line 119 def self.failover_action(path_suffix, server_urls, sticky, http_callback) response = nil response_error = nil config = Puppet::Util::Puppetdb.config last_good_index = 0 if sticky last_good_index = @@last_good_query_server_url_index.deref() end server_count = server_urls.length server_try_order = (0...server_count).map { |i| (i + last_good_index) % server_count } for server_url_index in server_try_order server_url = server_urls[server_url_index] route = concat_url_snippets(server_url.request_uri, path_suffix) request_exception = with_http_error_logging(server_url, route) { http = Puppet::Network::HttpPool.http_instance(server_url.host, server_url.port) response = Timeout.timeout(config.server_url_timeout) do http_callback.call(http, route) end } if request_exception.nil? response_error = check_http_response(response, server_url, route) if response_error.nil? if server_url_index != server_try_order.first() @@last_good_query_server_url_index.reset(server_url_index) end break end end end if response.nil? or not(response_error.nil?) raise_request_error(response, response_error, path_suffix) end response end |
.raise_request_error(response, response_error, path_suffix) ⇒ Object
109 110 111 112 113 114 115 116 117 |
# File 'lib/puppet/util/puppetdb/http.rb', line 109 def self.raise_request_error(response, response_error, path_suffix) server_url_strings = Puppet::Util::Puppetdb.config.server_urls.map {|server_url| server_url.to_s}.join(', ') if response_error == :notfound raise NotFoundError, "Failed to find '#{path_suffix}' on any of the following 'server_urls': #{server_url_strings}" else min_successful_submissions = Puppet::Util::Puppetdb.config.min_successful_submissions raise Puppet::Error, "Failed to execute '#{path_suffix}' on at least #{min_successful_submissions} of the following 'server_urls': #{server_url_strings}" end end |
.reset_query_failover ⇒ Object
221 222 223 |
# File 'lib/puppet/util/puppetdb/http.rb', line 221 def self.reset_query_failover() @@last_good_query_server_url_index.reset(0) end |
.with_http_error_logging(server_url, route, &cb) ⇒ Object
Run the given block (cb) in a begin/rescue, catching common network exceptions and logging useful information about them. If an expected exception was caught, it’s returned. An unexpected exception will be re-thrown. Returns nil on success.
36 37 38 39 40 41 42 43 44 45 46 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 79 80 81 82 |
# File 'lib/puppet/util/puppetdb/http.rb', line 36 def self.with_http_error_logging(server_url, route, &cb) config = Puppet::Util::Puppetdb.config begin cb.call() rescue Timeout::Error => e Puppet.warning("Request to #{server_url.host} on #{server_url.port} at route #{route} timed out " \ "after #{config.server_url_timeout} seconds. #{SERVER_URL_FAIL_MSG}") return e rescue SocketError, OpenSSL::SSL::SSLError, SystemCallError, Net::ProtocolError, IOError, Net::HTTPNotFound => e Puppet.warning("Error connecting to #{server_url.host} on #{server_url.port} at route #{route}, " \ "error message received was '#{e.message}'. #{SERVER_URL_FAIL_MSG}") return e rescue Puppet::Util::Puppetdb::InventorySearchError => e Puppet.warning("Could not perform inventory search from PuppetDB at #{server_url.host}:#{server_url.port}: " \ "'#{e.message}' #{SERVER_URL_FAIL_MSG}") return e rescue Puppet::Util::Puppetdb::CommandSubmissionError => e error = "Failed to submit '#{e.context[:command]}' command for '#{e.context[:for_whom]}' to PuppetDB " \ "at #{server_url.host}:#{server_url.port}: '#{e.message}'." if config.soft_write_failure Puppet.err error else Puppet.warning(error + " #{SERVER_URL_FAIL_MSG}") end return e rescue Puppet::Util::Puppetdb::SoftWriteFailError => e Puppet.warning("Failed to submit '#{e.context[:command]}' command for '#{e.context[:for_whom]}' to PuppetDB " \ "at #{server_url.host}:#{server_url.port}: '#{e.message}' #{SERVER_URL_FAIL_MSG}") return e rescue Puppet::Error => e if e. =~ /did not match server certificate; expected one of/ Puppet.warning("Error connecting to #{server_url.host} on #{server_url.port} at route #{route}, " \ "error message received was '#{e.message}'. #{SERVER_URL_FAIL_MSG}") return e else raise end end nil end |