Class: RHC::Rest::Client

Inherits:
Base show all
Includes:
Helpers, ApiMethods
Defined in:
lib/rhc/rest/client.rb

Direct Known Subclasses

Mock::MockRestClient

Constant Summary collapse

CLIENT_API_VERSIONS =

Keep the list of supported API versions here The list may not necessarily be sorted; we will select the last matching one supported by the server. See #api_version_negotiated

[1.1, 1.2, 1.3, 1.4, 1.5]
MAX_RETRIES =
5

Constants included from Helpers

Helpers::BOUND_WARNING, Helpers::PREFIX, Helpers::ROLES

Instance Method Summary collapse

Methods included from Helpers

#agree, #certificate_file, #client_from_options, #collect_env_vars, #color, #confirm_action, #date, #datetime_rfc3339, #debug, #debug?, #debug_error, #decode_json, #deprecated, #deprecated_command, #disable_deprecated?, #distance_of_time_in_words, #env_var_regex_pattern, #error, #exec, #host_exists?, #hosts_file_contains?, #human_size, #info, #interactive?, #jruby?, #mac?, #pluralize, #protonbox_online_server?, #protonbox_rest_endpoint, #protonbox_server, #protonbox_url, #results, #role_name, #run_with_tee, #ssh_string, #ssh_string_parts, #ssl_options, #success, #system_path, #table_heading, #to_host, #to_uri, #token_for_user, #unix?, #warn, #windows?, #with_tolerant_encoding

Methods included from OutputHelpers

#default_display_env_var, #display_app, #display_app_configurations, #display_authorization, #display_cart, #display_cart_storage_info, #display_cart_storage_list, #display_deployment, #display_deployment_list, #display_domain, #display_env_var_list, #display_key, #format_cart_gears, #format_cart_header, #format_gear_info, #format_key_header, #format_scaling_info, #format_usage_message

Methods included from ApiMethods

#add_authorization, #add_domain, #add_key, #applications, #authorization_scope_list, #authorizations, #cartridges, #delete_authorization, #delete_authorizations, #delete_key, #domains, #find_application, #find_application_aliases, #find_application_by_id, #find_application_by_id_gear_groups, #find_application_gear_groups, #find_cartridges, #find_domain, #find_key, #link_show_application_by_domain_name, #link_show_application_by_id, #link_show_domain_by_name, #new_session, #owned_domains, #reset, #sshkeys, #supports_sessions?, #user

Methods inherited from Base

#add_message, #has_param?, #link_href, #links, #rest_method, #supports?

Methods included from AttributesClass

#define_attr, #model_name

Methods included from Attributes

#attribute, #attributes, #attributes=, #clear_attribute

Constructor Details

#initialize(*args) ⇒ Client

Returns a new instance of Client.



220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/rhc/rest/client.rb', line 220

def initialize(*args)
  options = args[0].is_a?(Hash) && args[0] || {}
  @end_point, @debug, @preferred_api_versions =
    if options.empty?
      options[:user] = args.delete_at(1)
      options[:password] = args.delete_at(1)
      args
    else
      [
        options.delete(:url) ||
          (options[:server] && "https://#{options.delete(:server)}/broker/rest/api"),
        options.delete(:debug),
        options.delete(:preferred_api_versions)
      ]
    end

  @preferred_api_versions ||= CLIENT_API_VERSIONS
  @debug ||= false

  @auth = options.delete(:auth)

  self.headers.merge!(options.delete(:headers)) if options[:headers]
  self.options.merge!(options)

  debug "Connecting to #{@end_point}"
end

Instance Method Details

#apiObject



251
252
253
254
255
# File 'lib/rhc/rest/client.rb', line 251

def api
  @api ||= RHC::Rest::Api.new(self, @preferred_api_versions).tap do |api|
    self.current_api_version = api.api_version_negotiated
  end
end

#api_version_negotiatedObject



257
258
259
260
# File 'lib/rhc/rest/client.rb', line 257

def api_version_negotiated
  api
  current_api_version
end

#attempt(retries, &block) ⇒ Object



262
263
264
265
266
267
# File 'lib/rhc/rest/client.rb', line 262

def attempt(retries, &block)
  (0..retries).each do |i|
    yield i < (retries-1), i
  end
  raise "Too many retries, giving up."
end

#request(options, &block) ⇒ Object



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/rhc/rest/client.rb', line 269

def request(options, &block)
  attempt(MAX_RETRIES) do |more, i|
    begin
      client, args = new_request(options.dup)
      auth = options[:auth] || self.auth
      response = nil

      debug "Request #{args[0].to_s.upcase} #{args[1]}#{"?#{args[2].map{|a| a.join('=')}.join(' ')}" if args[2] && args[0] == 'GET'}"
      time = Benchmark.realtime{ response = client.request(*(args << true)) }
      debug "   code %s %4i ms" % [response.status, (time*1000).to_i] if response

      next if more && retry_proxy(response, i, args, client)
      auth.retry_auth?(response, self) and next if more && auth
      handle_error!(response, args[1], client) unless response.ok?

      return (if block_given?
          yield response
        else
          parse_response(response.content) unless response.nil? or response.code == 204
        end)
    rescue HTTPClient::BadResponseError => e
      if e.res
        debug "Response: #{e.res.status} #{e.res.headers.inspect}\n#{e.res.content}\n-------------" if debug?

        next if more && retry_proxy(e.res, i, args, client)
        auth.retry_auth?(e.res, self) and next if more && auth
        handle_error!(e.res, args[1], client)
      end
      raise ConnectionException.new(
        "An unexpected error occured when connecting to the server: #{e.message}")
    rescue HTTPClient::TimeoutError => e
      raise TimeoutException.new(
        "Connection to server timed out. "\
        "It is possible the operation finished without being able "\
        "to report success. Use 'pbox domain show' or 'pbox app show' "\
        "to see the status of your applications.", e)
    rescue EOFError => e
      raise ConnectionException.new(
        "Connection to server got interrupted: #{e.message}")
    rescue OpenSSL::SSL::SSLError => e
      raise SelfSignedCertificate.new(
        'self signed certificate',
        "The server is using a self-signed certificate, which means that a secure connection can't be established '#{args[1]}'.\n\n"\
        "You may disable certificate checks with the -k (or --insecure) option. Using this option means that your data is potentially visible to third parties.") if self_signed?
      raise case e.message
        when /self signed certificate/
          CertificateVerificationFailed.new(
            e.message,
            "The server is using a self-signed certificate, which means that a secure connection can't be established '#{args[1]}'.\n\n"\
            "You may disable certificate checks with the -k (or --insecure) option. Using this option means that your data is potentially visible to third parties.")
        when /certificate verify failed/
          CertificateVerificationFailed.new(
            e.message,
            "The server's certificate could not be verified, which means that a secure connection can't be established to the server '#{args[1]}'.\n\n"\
            "If your server is using a self-signed certificate, you may disable certificate checks with the -k (or --insecure) option. Using this option means that your data is potentially visible to third parties.")
        when /unable to get local issuer certificate/
          SSLConnectionFailed.new(
            e.message,
            "The server's certificate could not be verified, which means that a secure connection can't be established to the server '#{args[1]}'.\n\n"\
            "You may need to specify your system CA certificate file with --ssl-ca-file=<path_to_file>. If your server is using a self-signed certificate, you may disable certificate checks with the -k (or --insecure) option. Using this option means that your data is potentially visible to third parties.")
        when /^SSL_connect returned=1 errno=0 state=SSLv2\/v3 read server hello A/
          SSLVersionRejected.new(
            e.message,
            "The server has rejected your connection attempt with an older SSL protocol.  Pass --ssl-version=sslv3 on the command line to connect to this server.")
        when /^SSL_CTX_set_cipher_list:: no cipher match/
          SSLVersionRejected.new(
            e.message,
            "The server has rejected your connection attempt because it does not support the requested SSL protocol version.\n\n"\
            "Check with the administrator for a valid SSL version to use and pass --ssl-version=<version> on the command line to connect to this server.")
        else
          SSLConnectionFailed.new(
            e.message,
            "A secure connection could not be established to the server (#{e.message}). You may disable secure connections to your server with the -k (or --insecure) option '#{args[1]}'.\n\n"\
            "If your server is using a self-signed certificate, you may disable certificate checks with the -k (or --insecure) option. Using this option means that your data is potentially visible to third parties.")
        end
    rescue SocketError, Errno::ECONNREFUSED => e
      raise ConnectionException.new(
        "Unable to connect to the server (#{e.message})."\
        "#{client.proxy.present? ? " Check that you have correctly specified your proxy server '#{client.proxy}' as well as your ProtonBox server '#{args[1]}'." : " Check that you have correctly specified your ProtonBox server '#{args[1]}'."}")
    rescue Errno::ECONNRESET => e
      raise ConnectionException.new(
        "The server has closed the connection unexpectedly (#{e.message}). Your last operation may still be running on the server; please check before retrying your last request.")
    rescue RHC::Rest::Exception
      raise
    rescue => e
      debug_error(e)
      raise ConnectionException, "An unexpected error occured: #{e.message}", e.backtrace
    end
  end
end

#urlObject



247
248
249
# File 'lib/rhc/rest/client.rb', line 247

def url
  @end_point
end