mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
15ef5365e5
Since `fog-json` was extracted from `fog` it means if you rely on: require "fog/provider/compute" `Fog::JSON` was not defined although it was supposed to be a supported use case. This adds the requires for JSON or XML based APIs based on a quick scan of each provider to declare the required part. AWS seems to be relying on both. Which is nice. Providers relying on native code dependencies
146 lines
5.3 KiB
Ruby
146 lines
5.3 KiB
Ruby
require 'fog/core'
|
|
require 'fog/json'
|
|
require 'fog/rackspace/mock_data'
|
|
require 'fog/rackspace/service'
|
|
require 'fog/rackspace/errors'
|
|
|
|
module Fog
|
|
module Rackspace
|
|
extend Fog::Provider
|
|
|
|
US_AUTH_ENDPOINT = 'https://identity.api.rackspacecloud.com/v2.0' unless defined? US_AUTH_ENDPOINT
|
|
UK_AUTH_ENDPOINT = 'https://lon.identity.api.rackspacecloud.com/v2.0' unless defined? UK_AUTH_ENDPOINT
|
|
|
|
module Errors
|
|
class ServiceError < Fog::Errors::Error
|
|
attr_reader :response_data, :status_code, :transaction_id
|
|
|
|
def to_s
|
|
status = status_code ? "HTTP #{status_code}" : "HTTP <Unknown>"
|
|
"[#{status} | #{transaction_id}] #{super}"
|
|
end
|
|
|
|
def self.slurp(error, service=nil)
|
|
data = nil
|
|
message = nil
|
|
status_code = nil
|
|
|
|
if error.response
|
|
status_code = error.response.status
|
|
unless error.response.body.empty?
|
|
begin
|
|
data = Fog::JSON.decode(error.response.body)
|
|
message = extract_message(data)
|
|
rescue => e
|
|
Fog::Logger.warning("Received exception '#{e}' while decoding>> #{error.response.body}")
|
|
message = error.response.body
|
|
data = error.response.body
|
|
end
|
|
end
|
|
end
|
|
|
|
new_error = super(error, message)
|
|
new_error.instance_variable_set(:@response_data, data)
|
|
new_error.instance_variable_set(:@status_code, status_code)
|
|
new_error.set_transaction_id(error, service)
|
|
new_error
|
|
end
|
|
|
|
def set_transaction_id(error, service)
|
|
return unless service && service.respond_to?(:request_id_header) && error.response
|
|
@transaction_id = error.response.headers[service.request_id_header]
|
|
end
|
|
|
|
def self.extract_message(data)
|
|
if data.is_a?(Hash)
|
|
message = data.values.first['message'] if data.values.first.is_a?(Hash)
|
|
message ||= data['message']
|
|
end
|
|
message || data.inspect
|
|
end
|
|
end
|
|
|
|
class InternalServerError < ServiceError; end
|
|
class Conflict < ServiceError; end
|
|
class ServiceUnavailable < ServiceError; end
|
|
class MethodNotAllowed < ServiceError; end
|
|
class BadRequest < ServiceError
|
|
attr_reader :validation_errors
|
|
|
|
def to_s
|
|
"#{super} - #{validation_errors}"
|
|
end
|
|
|
|
def self.slurp(error, service=nil)
|
|
new_error = super(error)
|
|
unless new_error.response_data.nil? or new_error.response_data['badRequest'].nil?
|
|
new_error.instance_variable_set(:@validation_errors, new_error.response_data['badRequest']['validationErrors'])
|
|
end
|
|
|
|
status_code = error.response ? error.response.status : nil
|
|
new_error.instance_variable_set(:@status_code, status_code)
|
|
new_error.set_transaction_id(error, service)
|
|
new_error
|
|
end
|
|
end
|
|
end
|
|
|
|
service(:auto_scale, 'AutoScale')
|
|
service(:block_storage, 'BlockStorage')
|
|
service(:cdn, 'CDN')
|
|
service(:compute, 'Compute')
|
|
service(:compute_v2, 'Compute v2')
|
|
service(:dns, 'DNS')
|
|
service(:storage, 'Storage')
|
|
service(:load_balancers, 'LoadBalancers')
|
|
service(:identity, 'Identity')
|
|
service(:databases, 'Databases')
|
|
service(:monitoring, 'Monitoring')
|
|
service(:queues, 'Queues')
|
|
|
|
def self.authenticate(options, connection_options = {})
|
|
rackspace_auth_url = options[:rackspace_auth_url]
|
|
rackspace_auth_url ||= options[:rackspace_endpoint] == Fog::Compute::RackspaceV2::LON_ENDPOINT ? "lon.auth.api.rackspacecloud.com" : "auth.api.rackspacecloud.com"
|
|
url = rackspace_auth_url.match(/^https?:/) ? \
|
|
rackspace_auth_url : 'https://' + rackspace_auth_url
|
|
uri = URI.parse(url)
|
|
connection = Fog::Connection.new(url, false, connection_options)
|
|
@rackspace_api_key = options[:rackspace_api_key]
|
|
@rackspace_username = options[:rackspace_username]
|
|
response = connection.request({
|
|
:expects => [200, 204],
|
|
:headers => {
|
|
'X-Auth-Key' => @rackspace_api_key,
|
|
'X-Auth-User' => @rackspace_username
|
|
},
|
|
:method => 'GET',
|
|
:path => (uri.path and not uri.path.empty?) ? uri.path : 'v1.0'
|
|
})
|
|
response.headers.reject do |key, value|
|
|
!['X-Server-Management-Url', 'X-Storage-Url', 'X-CDN-Management-Url', 'X-Auth-Token'].include?(key)
|
|
end
|
|
end
|
|
|
|
def self.json_response?(response)
|
|
return false unless response && response.headers
|
|
response.get_header('Content-Type') =~ %r{application/json}i ? true : false
|
|
end
|
|
|
|
def self.normalize_url(endpoint)
|
|
return nil unless endpoint
|
|
str = endpoint.chomp " "
|
|
str = str.chomp "/"
|
|
str.downcase
|
|
end
|
|
|
|
# CGI.escape, but without special treatment on spaces
|
|
def self.escape(str,extra_exclude_chars = '')
|
|
# '-' is a special character inside a regex class so it must be first or last.
|
|
# Add extra excludes before the final '-' so it always remains trailing, otherwise
|
|
# an unwanted range is created by mistake.
|
|
str.gsub(/([^a-zA-Z0-9_.#{extra_exclude_chars}-]+)/) do
|
|
'%' + $1.unpack('H2' * $1.bytesize).join('%').upcase
|
|
end
|
|
end
|
|
end
|
|
end
|