fog--fog/lib/fog/ninefold/storage.rb

155 lines
4.9 KiB
Ruby
Raw Normal View History

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'ninefold'))
require 'fog/storage'
module Fog
module Storage
class Ninefold < Fog::Service
STORAGE_HOST = "onlinestorage.ninefold.com" #"api.ninefold.com"
STORAGE_PATH = "" #"/storage/v1.0"
STORAGE_PORT = "80" # "443"
STORAGE_SCHEME = "http" # "https"
requires :ninefold_storage_token, :ninefold_storage_secret
model_path 'fog/ninefold/models/storage'
model :directory
collection :directories
2011-07-10 09:44:35 -04:00
model :file
collection :files
request_path 'fog/ninefold/requests/storage'
# request :delete_container
request :get_namespace
2011-11-05 20:29:30 -04:00
request :head_namespace
request :post_namespace
request :put_namespace
request :delete_namespace
module Utils
end
class Mock
include Utils
def initialize(options={})
require 'mime/types'
@ninefold_storage_token = options[:ninefold_storage_token]
@ninefold_storage_secret = options[:ninefold_storage_secret]
end
def request(options)
raise "Ninefold Storage mocks not implemented"
end
end
class Real
include Utils
def initialize(options={})
require 'mime/types'
@ninefold_storage_token = options[:ninefold_storage_token]
@ninefold_storage_secret = options[:ninefold_storage_secret]
@ninefold_storage_secret_decoded = Base64.decode64( @ninefold_storage_secret )
@connection_options = options[:connection_options] || {}
@hmac = Fog::HMAC.new('sha1', @ninefold_storage_secret_decoded)
@persistent = options[:persistent] || true
2011-08-31 16:32:12 -04:00
@connection = Fog::Connection.new("#{Fog::Storage::Ninefold::STORAGE_SCHEME}://#{Fog::Storage::Ninefold::STORAGE_HOST}:#{Fog::Storage::Ninefold::STORAGE_PORT}", @persistent, @connection_options)
end
2011-07-10 09:44:35 -04:00
def uid
@ninefold_storage_token#.split('/')[-1]
end
def sign(string)
2011-08-31 16:32:12 -04:00
value = @hmac.sign(string)
2011-07-10 09:44:35 -04:00
Base64.encode64( value ).chomp()
end
def reload
@connection.reset
end
def request(params, &block)
req_path = params[:path]
# Force set host and port
params.merge!({
:host => Fog::Storage::Ninefold::STORAGE_HOST,
:path => "#{Fog::Storage::Ninefold::STORAGE_PATH}/rest/#{params[:path]}",
})
# Set default method and headers
params = {:method => 'GET', :headers => {}}.merge params
params[:headers]["Content-Type"] ||= "application/octet-stream"
# Add request date
params[:headers]["date"] = Time.now().httpdate()
params[:headers]["x-emc-uid"] = @ninefold_storage_token
# Build signature string
signstring = ""
signstring += params[:method]
signstring += "\n"
signstring += params[:headers]["Content-Type"]
signstring += "\n"
if( params[:headers]["range"] )
signstring += params[:headers]["range"]
end
signstring += "\n"
signstring += params[:headers]["date"]
signstring += "\n"
signstring += "/rest/" + URI.unescape( req_path ).downcase
query_str = params[:query].map{|k,v| "#{k}=#{v}"}.join('&')
2011-07-10 09:44:35 -04:00
signstring += '?' + query_str unless query_str.empty?
signstring += "\n"
customheaders = {}
params[:headers].each { |key,value|
case key
when 'x-emc-date', 'x-emc-signature'
#skip
when /^x-emc-/
customheaders[ key.downcase ] = value
end
}
header_arr = customheaders.sort()
2012-05-14 14:55:16 -04:00
header_arr.each { |key,value|
# Values are lowercase and whitespace-normalized
signstring += key + ":" + value.strip.chomp.squeeze( " " ) + "\n"
}
2011-08-31 16:32:12 -04:00
digest = @hmac.sign(signstring.chomp())
signature = Base64.encode64( digest ).chomp()
params[:headers]["x-emc-signature"] = signature
begin
response = @connection.request(params, &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Storage::Ninefold::NotFound.slurp(error)
else
error
end
end
unless response.body.empty?
if params[:parse]
document = Fog::ToHashDocument.new
parser = Nokogiri::XML::SAX::PushParser.new(document)
parser << response.body
parser.finish
response.body = document.body
end
end
response
end
end
end
end
end