lib/fog/hp/storage.rb in fog-maestrodev-1.8.0.20130114204828 vs lib/fog/hp/storage.rb in fog-maestrodev-1.14.0.20130806165225
- old
+ new
@@ -3,44 +3,62 @@
module Fog
module Storage
class HP < Fog::Service
- requires :hp_secret_key, :hp_account_id, :hp_tenant_id
- recognizes :hp_auth_uri, :hp_servicenet, :hp_cdn_ssl, :hp_cdn_uri, :persistent, :connection_options, :hp_use_upass_auth_style, :hp_auth_version
+ requires :hp_secret_key, :hp_tenant_id, :hp_avl_zone
+ recognizes :hp_auth_uri, :hp_cdn_ssl, :hp_cdn_uri
+ recognizes :persistent, :connection_options
+ recognizes :hp_use_upass_auth_style, :hp_auth_version, :user_agent
+ recognizes :hp_access_key, :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
+
+ # :os_account_meta_temp_url_key is an OpenStack specific setting used to generate temporary urls.
+ recognizes :os_account_meta_temp_url_key
- secrets :hp_secret_key
+ secrets :hp_secret_key, :os_account_meta_temp_url_key
model_path 'fog/hp/models/storage'
model :directory
collection :directories
+ model :shared_directory
+ collection :shared_directories
model :file
collection :files
+ model :shared_file
+ collection :shared_files
request_path 'fog/hp/requests/storage'
request :delete_container
request :delete_object
+ request :delete_shared_object
request :get_container
request :get_containers
request :get_object
+ request :get_object_temp_url
+ request :get_shared_container
+ request :get_shared_object
request :head_container
request :head_containers
request :head_object
+ request :head_shared_container
+ request :head_shared_object
request :put_container
request :put_object
+ request :put_shared_object
module Utils
def cdn
unless @hp_cdn_uri.nil?
@cdn ||= Fog::CDN.new(
:provider => 'HP',
- :hp_account_id => @hp_account_id,
+ :hp_access_key => @hp_access_key,
:hp_secret_key => @hp_secret_key,
:hp_auth_uri => @hp_auth_uri,
:hp_cdn_uri => @hp_cdn_uri,
:hp_tenant_id => @hp_tenant_id,
+ :hp_avl_zone => @hp_avl_zone,
:connection_options => @connection_options
)
if @cdn.enabled?
@cdn
end
@@ -51,39 +69,134 @@
def url
"#{@scheme}://#{@host}:#{@port}#{@path}"
end
- def acl_to_header(acl)
+ def public_url(container=nil, object=nil)
+ public_url = nil
+ unless container.nil?
+ if object.nil?
+ # return container public url
+ public_url = "#{url}/#{Fog::HP.escape(container)}"
+ else
+ # return object public url
+ public_url = "#{url}/#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
+ end
+ end
+ public_url
+ end
+
+ def perm_to_acl(perm, users=[])
+ read_perm_acl = []
+ write_perm_acl = []
+ valid_public_perms = ['pr', 'pw', 'prw']
+ valid_account_perms = ['r', 'w', 'rw']
+ valid_perms = valid_public_perms + valid_account_perms
+ unless valid_perms.include?(perm)
+ raise ArgumentError.new("permission must be one of [#{valid_perms.join(', ')}]")
+ end
+ # tackle the public access differently
+ if valid_public_perms.include?(perm)
+ case perm
+ when "pr"
+ read_perm_acl = [".r:*",".rlistings"]
+ when "pw"
+ write_perm_acl = ["*"]
+ when "prw"
+ read_perm_acl = [".r:*",".rlistings"]
+ write_perm_acl = ["*"]
+ end
+ elsif valid_account_perms.include?(perm)
+ # tackle the user access differently
+ unless (users.nil? || users.empty?)
+ # return the correct acls
+ tenant_id = "*" # this might change later
+ acl_array = users.map { |u| "#{tenant_id}:#{u}" }
+ #acl_string = acl_array.join(',')
+ case perm
+ when "r"
+ read_perm_acl = acl_array
+ when "w"
+ write_perm_acl = acl_array
+ when "rw"
+ read_perm_acl = acl_array
+ write_perm_acl = acl_array
+ end
+ end
+ end
+ return read_perm_acl, write_perm_acl
+ end
+
+ def perm_acl_to_header(read_perm_acl, write_perm_acl)
header = {}
- case acl
- when "private"
- header['X-Container-Read'] = ""
- header['X-Container-Write'] = ""
- when "public-read"
- header['X-Container-Read'] = ".r:*,.rlistings"
- when "public-write"
- header['X-Container-Write'] = "*"
- when "public-read-write"
- header['X-Container-Read'] = ".r:*,.rlistings"
- header['X-Container-Write'] = "*"
+ if read_perm_acl.nil? && write_perm_acl.nil?
+ header = {'X-Container-Read' => "", 'X-Container-Write' => ""}
+ elsif !read_perm_acl.nil? && write_perm_acl.nil?
+ header = {'X-Container-Read' => "#{read_perm_acl.join(',')}", 'X-Container-Write' => ""}
+ elsif read_perm_acl.nil? && !write_perm_acl.nil?
+ header = {'X-Container-Read' => "", 'X-Container-Write' => "#{write_perm_acl.join(',')}"}
+ elsif !read_perm_acl.nil? && !write_perm_acl.nil?
+ header = {'X-Container-Read' => "#{read_perm_acl.join(',')}", 'X-Container-Write' => "#{write_perm_acl.join(',')}"}
end
header
end
- def header_to_acl(read_header=nil, write_header=nil)
- acl = nil
- if read_header.nil? && write_header.nil?
- acl = nil
- elsif !read_header.nil? && read_header.include?(".r:*") && write_header.nil?
- acl = "public-read"
- elsif !write_header.nil? && write_header.include?("*") && read_header.nil?
- acl = "public-write"
- elsif !read_header.nil? && read_header.include?(".r:*") && !write_header.nil? && write_header.include?("*")
- acl = "public-read-write"
+ def header_to_perm_acl(read_header=nil, write_header=nil)
+ read_h, write_h = nil
+ read_h = read_header.split(',') unless read_header.nil?
+ write_h = write_header.split(',') unless write_header.nil?
+ return read_h, write_h
+ end
+
+ def generate_object_temp_url(container, object, expires_secs, method)
+ return unless (container && object && expires_secs && method)
+
+ # POST not allowed
+ allowed_methods = %w{GET PUT HEAD}
+ unless allowed_methods.include?(method)
+ raise ArgumentError.new("Invalid method '#{method}' specified. Valid methods are: #{allowed_methods.join(', ')}")
end
+
+ expires = (Time.now + expires_secs.to_i).to_i
+
+ # split up the storage uri
+ uri = URI.parse(@hp_storage_uri)
+ host = uri.host
+ path = uri.path
+ port = uri.port
+ scheme = uri.scheme
+
+ # do not encode before signature generation, encode after
+ sig_path = "#{path}/#{container}/#{object}"
+ encoded_path = "#{path}/#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
+
+ string_to_sign = "#{method}\n#{expires}\n#{sig_path}"
+
+ signature = nil
+
+ # HP uses a different strategy to create the signature that is passed to swift than OpenStack.
+ # As the HP provider is broadly used by OpenStack users the OpenStack strategy is applied when
+ # the @os_account_meta_temp_url_key is given.
+ if @os_account_meta_temp_url_key then
+ hmac = OpenSSL::HMAC.new(@os_account_meta_temp_url_key, OpenSSL::Digest::SHA1.new)
+ signature= hmac.update(string_to_sign).hexdigest
+ else
+ # Only works with 1.9+ Not compatible with 1.8.7
+ #signed_string = Digest::HMAC.hexdigest(string_to_sign, @hp_secret_key, Digest::SHA1)
+
+ # Compatible with 1.8.7 onwards
+ hmac = OpenSSL::HMAC.new(@hp_secret_key, OpenSSL::Digest::SHA1.new)
+ signed_string = hmac.update(string_to_sign).hexdigest
+
+ signature = @hp_tenant_id.to_s + ":" + @hp_access_key.to_s + ":" + signed_string
+ signature = Fog::HP.escape(signature)
+ end
+
+ # generate the temp url using the signature and expiry
+ "#{scheme}://#{host}:#{port}#{encoded_path}?temp_url_sig=#{signature}&temp_url_expires=#{expires}"
end
+
end
class Mock
include Utils
def self.acls(type)
@@ -106,40 +219,60 @@
@data = nil
end
def initialize(options={})
require 'mime/types'
+ # deprecate hp_account_id
+ if options[:hp_account_id]
+ Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
+ @hp_access_key = options.delete(:hp_account_id)
+ end
+ @hp_access_key = options[:hp_access_key]
+ unless @hp_access_key
+ raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
+ end
@hp_secret_key = options[:hp_secret_key]
- @hp_account_id = options[:hp_account_id]
+ @hp_tenant_id = options[:hp_tenant_id]
+ @os_account_meta_temp_url_key = options[:os_account_meta_temp_url_key]
end
def data
- self.class.data[@hp_account_id]
+ self.class.data[@hp_access_key]
end
def reset_data
- self.class.data.delete(@hp_account_id)
+ self.class.data.delete(@hp_access_key)
end
end
class Real
include Utils
attr_reader :hp_cdn_ssl
def initialize(options={})
require 'mime/types'
+ # deprecate hp_account_id
+ if options[:hp_account_id]
+ Fog::Logger.deprecation(":hp_account_id is deprecated, please use :hp_access_key instead.")
+ options[:hp_access_key] = options.delete(:hp_account_id)
+ end
+ @hp_access_key = options[:hp_access_key]
+ unless @hp_access_key
+ raise ArgumentError.new("Missing required arguments: hp_access_key. :hp_account_id is deprecated, please use :hp_access_key instead.")
+ end
@hp_secret_key = options[:hp_secret_key]
- @hp_account_id = options[:hp_account_id]
@hp_auth_uri = options[:hp_auth_uri]
@hp_cdn_ssl = options[:hp_cdn_ssl]
@connection_options = options[:connection_options] || {}
### Set an option to use the style of authentication desired; :v1 or :v2 (default)
auth_version = options[:hp_auth_version] || :v2
- ### Pass the service type for object storage to the authentication call
- options[:hp_service_type] = "object-store"
+ ### Pass the service name for object storage to the authentication call
+ options[:hp_service_type] = "Object Storage"
@hp_tenant_id = options[:hp_tenant_id]
+ @hp_avl_zone = options[:hp_avl_zone]
+ @os_account_meta_temp_url_key = options[:os_account_meta_temp_url_key]
### Make the authentication call
if (auth_version == :v2)
# Call the control services authentication
credentials = Fog::HP.authenticate_v2(options, @connection_options)
@@ -155,16 +288,15 @@
end
@auth_token = credentials[:auth_token]
uri = URI.parse(@hp_storage_uri)
- @host = options[:hp_servicenet] == true ? "snet-#{uri.host}" : uri.host
+ @host = uri.host
@path = uri.path
@persistent = options[:persistent] || false
@port = uri.port
@scheme = uri.scheme
- Excon.ssl_verify_peer = false if options[:hp_servicenet] == true
@connection = Fog::Connection.new("#{@scheme}://#{@host}:#{@port}", @persistent, @connection_options)
end
def reload
@@ -174,18 +306,47 @@
def request(params, parse_json = true, &block)
begin
response = @connection.request(params.merge!({
:headers => {
'Content-Type' => 'application/json',
+ 'Accept' => 'application/json',
'X-Auth-Token' => @auth_token
}.merge!(params[:headers] || {}),
:host => @host,
:path => "#{@path}/#{params[:path]}",
}), &block)
rescue Excon::Errors::HTTPStatusError => error
raise case error
when Excon::Errors::NotFound
Fog::Storage::HP::NotFound.slurp(error)
+ else
+ error
+ end
+ end
+ if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}
+ response.body = Fog::JSON.decode(response.body)
+ end
+ response
+ end
+
+ # this request is used only for get_shared_container and get_shared_object calls
+ def shared_request(params, parse_json = true, &block)
+ begin
+ response = @connection.request(params.merge!({
+ :headers => {
+ 'Content-Type' => 'application/json',
+ 'Accept' => 'application/json',
+ 'X-Auth-Token' => @auth_token
+ }.merge!(params[:headers] || {}),
+ :host => @host,
+ :path => "#{params[:path]}",
+ }), &block)
+ rescue Excon::Errors::HTTPStatusError => error
+ raise case error
+ when Excon::Errors::NotFound
+ Fog::Storage::HP::NotFound.slurp(error)
+ when Excon::Errors::Forbidden
+ Fog::HP::Errors::Forbidden.slurp(error)
else
error
end
end
if !response.body.empty? && parse_json && response.headers['Content-Type'] =~ %r{application/json}