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, 1.6]
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?, #openshift_online_server?, #openshift_rest_endpoint, #openshift_server, #openshift_url, #pluralize, #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, #display_team, #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, #add_team, #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, #find_team, #find_team_by_id, #link_show_application_by_domain_name, #link_show_application_by_id, #link_show_domain_by_name, #link_show_team_by_id, #new_session, #owned_applications, #owned_domains, #owned_teams, #precheck_application_id, #precheck_domain_id, #precheck_team_id, #reset, #search_owned_teams, #search_teams, #sshkeys, #supports_sessions?, #teams, #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.



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
# File 'lib/rhc/rest/client.rb', line 331

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



362
363
364
365
366
# File 'lib/rhc/rest/client.rb', line 362

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



368
369
370
371
# File 'lib/rhc/rest/client.rb', line 368

def api_version_negotiated
  api
  current_api_version
end

#attempt(retries, &block) ⇒ Object



373
374
375
376
377
378
# File 'lib/rhc/rest/client.rb', line 373

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



380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'lib/rhc/rest/client.rb', line 380

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 'app domain show' or 'app 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 StartApp server '#{args[1]}'." : " Check that you have correctly specified your StartApp 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



358
359
360
# File 'lib/rhc/rest/client.rb', line 358

def url
  @end_point
end