class EY::CloudClient::Connection

Constants

BASE_USER_AGENT
DEFAULT_ENDPOINT
RUBY_VERSION_NAME

Attributes

endpoint[R]
output[R]
token[RW]
user_agent[R]

Public Class Methods

new(options={}) click to toggle source

Initialize a new EY::CloudClient::Connection with a hash including:

:token: (optional) Perform authenticated requests with this token :user_agent: (optional) A user agent name/version pair to add to the User-Agent header. (e.g. EngineYardCLI/2.0.0) :output: (optional) Send output to a stream other than $stdout :endpoint: (optional) An alternate Engine Yard Cloud endpoint URI

# File lib/engineyard-cloud-client/connection.rb, line 24
def initialize(options={})
  @output     = options[:output] || $stdout
  @user_agent = [options[:user_agent], BASE_USER_AGENT].compact.join(' ').strip
  @endpoint   = URI.parse(options[:endpoint] || DEFAULT_ENDPOINT)
  @token      = options[:token]

  unless @endpoint.absolute?
    raise BadEndpointError.new(@endpoint)
  end
end

Public Instance Methods

==(other) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 48
def ==(other)
  other.is_a?(self.class) && [other.token, other.user_agent, other.endpoint] == [token, user_agent, endpoint]
end
authenticate!(email, password) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 89
def authenticate!(email, password)
  response = post("/authenticate", :email => email, :password => password)
  self.token = response["api_token"]
  token
end
authenticated?() click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 95
def authenticated?
  !token.nil? && !token.empty?
end
debug(name, value) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 35
def debug(name, value)
  return unless ENV['DEBUG']

  indent = 12                                           # 12 because that's what Thor used.
  unless String === value
    value = value.pretty_inspect.rstrip                 # remove trailing whitespace
    if value.index("\n")                                # if the inspect is multi-line
      value = value.gsub(/^/, " "*(indent + 2)).lstrip  # indent it
    end
  end
  @output << "#{name.to_s.rjust(indent)}  #{value.rstrip}\n"       # just one newline
end
request(meth, path, params=nil, extra_headers=nil) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 60
def request(meth, path, params=nil, extra_headers=nil)
  url    = endpoint + "api/v2#{path}"
  meth   ||= 'get'
  meth   = meth.to_s.downcase.to_sym
  params ||= {}

  headers = {
    "User-Agent" => user_agent,
    "Accept"     => "application/json",
  }

  if token
    headers["X-EY-Cloud-Token"] = token
  end

  if extra_headers
    headers.merge!(extra_headers)
  end

  debug(meth.to_s.upcase, url.to_s)
  debug("Params",  params) if params
  debug("Headers", headers)

  resp = do_request(meth, url, params, headers)
  data = parse_response(resp)

  data
end

Private Instance Methods

do_request(meth, url, params, headers) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 101
def do_request(meth, url, params, headers)
  case meth
  when :get, :delete, :head
    if params
      url.query = RestClient::Payload::UrlEncoded.new(params).to_s
    end
    RestClient.send(meth, url.to_s, headers)
  else
    RestClient.send(meth, url.to_s, params, headers)
  end
rescue RestClient::Unauthorized
  raise InvalidCredentials
rescue Errno::ECONNREFUSED
  raise RequestFailed, "Could not reach the cloud API"
rescue RestClient::ResourceNotFound
  raise ResourceNotFound, "The requested resource could not be found"
rescue RestClient::BadGateway
  raise RequestFailed, "EY Cloud API is temporarily unavailable. Please try again soon."
rescue RestClient::RequestFailed => e
  raise RequestFailed, "Error: #{parse_error(e)}"
rescue OpenSSL::SSL::SSLError
  raise RequestFailed, "SSL is misconfigured on your cloud"
end
parse_error(error) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 125
def parse_error(error)
  resp = error.response
  debug("Error", error.message)

  if resp.body.empty?
    debug("Response", '<<Response body is empty>>')
    error.message
  elsif resp.headers[:content_type] =~ /application\/json/
    begin
      data = MultiJson.load(resp.body)
      debug("Response", data)
      data['message'] ? data['message'] : "#{error.message} #{data.inspect}"
    rescue MultiJson::DecodeError
      debug("Response", resp.body)
      "#{error.message} #{resp.body}"
    end
  else
    debug("Response", resp.body)
    "#{error.message} #{resp.body}"
  end
end
parse_response(resp) click to toggle source
# File lib/engineyard-cloud-client/connection.rb, line 147
def parse_response(resp)
  if resp.body.empty?
    ''
  elsif resp.headers[:content_type] =~ /application\/json/
    begin
      data = MultiJson.load(resp.body)
      debug("Response", data)
      data
    rescue MultiJson::DecodeError
      debug("Response", resp.body)
      raise RequestFailed, "Response was not valid JSON."
    end
  else
    resp.body
  end
end