2014-02-01 21:13:17 -05:00
require 'fog/hp/core'
2011-10-17 15:25:07 -04:00
2011-06-15 02:13:18 -04:00
module Fog
2011-10-17 15:25:07 -04:00
module Storage
class HP < Fog :: Service
2013-01-22 17:28:33 -05:00
requires :hp_secret_key , :hp_tenant_id , :hp_avl_zone
2013-03-27 09:52:52 -04:00
recognizes :hp_auth_uri , :hp_cdn_ssl , :hp_cdn_uri , :credentials , :hp_service_type
2013-01-18 15:06:41 -05:00
recognizes :persistent , :connection_options
recognizes :hp_use_upass_auth_style , :hp_auth_version , :user_agent
2013-01-22 17:28:33 -05:00
recognizes :hp_access_key , :hp_account_id # :hp_account_id is deprecated use hp_access_key instead
2013-09-25 10:46:03 -04:00
2013-06-26 14:45:31 -04:00
# :os_account_meta_temp_url_key is an OpenStack specific setting used to generate temporary urls.
recognizes :os_account_meta_temp_url_key
2011-06-15 02:10:54 -04:00
2013-06-26 14:45:31 -04:00
secrets :hp_secret_key , :os_account_meta_temp_url_key
2011-06-15 02:13:18 -04:00
2011-10-17 15:25:07 -04:00
model_path 'fog/hp/models/storage'
2011-06-16 00:36:38 -04:00
model :directory
collection :directories
2012-10-19 01:33:20 -04:00
model :shared_directory
collection :shared_directories
2011-06-16 00:36:38 -04:00
model :file
collection :files
2012-10-19 01:33:20 -04:00
model :shared_file
collection :shared_files
2011-06-15 02:13:18 -04:00
2011-10-17 15:25:07 -04:00
request_path 'fog/hp/requests/storage'
2011-06-15 02:13:18 -04:00
request :delete_container
2011-06-15 17:59:06 -04:00
request :delete_object
2012-10-30 17:47:17 -04:00
request :delete_shared_object
2011-06-15 02:13:18 -04:00
request :get_container
request :get_containers
2011-06-15 17:59:06 -04:00
request :get_object
2012-09-26 13:01:32 -04:00
request :get_object_temp_url
2012-10-16 22:51:59 -04:00
request :get_shared_container
request :get_shared_object
2011-06-15 14:33:26 -04:00
request :head_container
request :head_containers
2011-06-15 17:59:06 -04:00
request :head_object
2012-10-16 22:51:59 -04:00
request :head_shared_container
request :head_shared_object
2013-04-23 22:41:51 -04:00
request :post_container
request :post_object
2011-06-15 02:13:18 -04:00
request :put_container
2011-06-15 17:59:06 -04:00
request :put_object
2012-10-19 01:33:20 -04:00
request :put_shared_object
2011-06-15 02:13:18 -04:00
module Utils
def cdn
2011-11-11 16:12:57 -05:00
unless @hp_cdn_uri . nil?
@cdn || = Fog :: CDN . new (
:provider = > 'HP' ,
2013-01-22 17:28:33 -05:00
:hp_access_key = > @hp_access_key ,
2011-11-11 16:12:57 -05:00
:hp_secret_key = > @hp_secret_key ,
:hp_auth_uri = > @hp_auth_uri ,
2012-01-18 17:23:54 -05:00
:hp_cdn_uri = > @hp_cdn_uri ,
2012-04-16 17:18:58 -04:00
:hp_tenant_id = > @hp_tenant_id ,
2012-04-27 14:13:39 -04:00
:hp_avl_zone = > @hp_avl_zone ,
2013-04-04 19:08:02 -04:00
:credentials = > @credentials ,
2012-04-16 17:18:58 -04:00
:connection_options = > @connection_options
2011-11-11 16:12:57 -05:00
)
if @cdn . enabled?
@cdn
end
else
nil
end
2011-06-15 02:13:18 -04:00
end
2011-07-13 18:11:08 -04:00
def url
" #{ @scheme } :// #{ @host } : #{ @port } #{ @path } "
end
2011-07-13 19:25:47 -04:00
2012-10-16 21:48:50 -04:00
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 )
2011-07-13 19:25:47 -04:00
header = { }
2012-10-16 21:48:50 -04:00
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 ( ',' ) } " }
2011-07-13 19:25:47 -04:00
end
header
end
2011-08-01 15:03:08 -04:00
2012-10-16 21:48:50 -04:00
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
2011-08-01 15:03:08 -04:00
end
2014-02-19 07:30:59 -05:00
2013-10-08 10:48:26 -04:00
# Get an expiring object https url
#
# ==== Parameters
# * container<~String> - Name of container containing object
# * object<~String> - Name of object to get expiring url for
# * expires<~Time> - An expiry time for this url
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~String> - url for object
def get_object_https_url ( container , object , expires , options = { } )
create_temp_url ( container , object , expires , " GET " , options . merge ( :scheme = > " https " ) )
end
2014-02-19 07:30:59 -05:00
2013-10-08 10:48:26 -04:00
# Get an expiring object http url
#
# ==== Parameters
# * container<~String> - Name of container containing object
# * object<~String> - Name of object to get expiring url for
# * expires<~Time> - An expiry time for this url
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~String> - url for object
def get_object_http_url ( container , object , expires , options = { } )
create_temp_url ( container , object , expires , " GET " , options . merge ( :scheme = > " http " ) )
end
2012-09-26 13:01:32 -04:00
2013-10-08 10:48:26 -04:00
# Get an object http url expiring in the given amount of seconds
#
# ==== Parameters
# * container<~String> - Name of container containing object
# * object<~String> - Name of object to get expiring url for
# * expires_secs<~Integer> - the amount of seconds from now until the url expires
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~String> - url for object
2012-09-26 13:01:32 -04:00
def generate_object_temp_url ( container , object , expires_secs , method )
2013-10-08 10:48:26 -04:00
expiration_time = ( Time . now + expires_secs . to_i ) . to_i
create_temp_url ( container , object , expiration_time , method , { } )
end
2014-02-19 07:30:59 -05:00
# creates a temporary url
2013-10-08 10:48:26 -04:00
#
# ==== Parameters
# * container<~String> - Name of container containing object
# * object<~String> - Name of object to get expiring url for
# * expires<~Time> - An expiry time for this url
# * method<~String> - The method to use for accessing the object (GET, PUT, HEAD)
# * scheme<~String> - The scheme to use (http, https)
# * options<~Hash> - An optional options hash
#
# ==== Returns
# * response<~Excon::Response>:
# * body<~String> - url for object
def create_temp_url ( container , object , expires , method , options = { } )
raise ArgumentError , " Insufficient parameters specified. " unless ( container && object && expires && method )
2012-09-26 13:01:32 -04:00
# 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
2013-10-08 10:48:26 -04:00
expires = expires . to_i
2013-10-09 05:09:46 -04:00
scheme = options [ :scheme ] || @scheme
2014-02-19 07:30:59 -05:00
2012-09-26 13:01:32 -04:00
# do not encode before signature generation, encode after
2013-10-09 05:09:46 -04:00
sig_path = " #{ @path } / #{ container } / #{ object } "
encoded_path = " #{ @path } / #{ Fog :: HP . escape ( container ) } / #{ Fog :: HP . escape ( object ) } "
2012-09-26 13:01:32 -04:00
2012-09-27 15:55:57 -04:00
string_to_sign = " #{ method } \n #{ expires } \n #{ sig_path } "
2013-10-08 10:48:26 -04:00
signature = nil
2013-06-24 17:02:21 -04:00
# 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
2013-06-26 14:45:31 -04:00
# 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
2013-06-24 17:02:21 -04:00
else
2014-06-24 12:22:44 -04:00
#Note if the value of the @hp_secret_key is really a password, this will NOT work
#HP Public Cloud FormPost and Temporary URL hashing algorithms require the secret key NOT password.
if Fog :: HP . instance_variable_get ( " @hp_use_upass_auth_style " )
raise ArgumentError , " Temporary URLS cannot be generated unless you login via access_key/secret_key "
end
2013-06-24 17:02:21 -04:00
# Only works with 1.9+ Not compatible with 1.8.7
2013-06-26 05:14:49 -04:00
#signed_string = Digest::HMAC.hexdigest(string_to_sign, @hp_secret_key, Digest::SHA1)
2014-02-19 07:30:59 -05:00
# Compatible with 1.8.7 onwards
2013-06-26 05:14:49 -04:00
hmac = OpenSSL :: HMAC . new ( @hp_secret_key , OpenSSL :: Digest :: SHA1 . new )
2013-06-24 17:02:21 -04:00
signed_string = hmac . update ( string_to_sign ) . hexdigest
2014-02-19 07:30:59 -05:00
2013-06-24 17:02:21 -04:00
signature = @hp_tenant_id . to_s + " : " + @hp_access_key . to_s + " : " + signed_string
signature = Fog :: HP . escape ( signature )
end
2014-02-19 07:30:59 -05:00
2012-09-26 13:01:32 -04:00
# generate the temp url using the signature and expiry
2014-02-19 07:30:59 -05:00
" #{ scheme } :// #{ @host } #{ encoded_path } ?temp_url_sig= #{ signature } &temp_url_expires= #{ expires } "
2012-09-26 13:01:32 -04:00
end
2011-06-15 02:13:18 -04:00
end
class Mock
include Utils
2011-07-29 11:33:28 -04:00
def self . acls ( type )
type
end
2011-06-15 02:13:18 -04:00
def self . data
@data || = Hash . new do | hash , key |
2011-07-29 11:33:28 -04:00
hash [ key ] = {
:acls = > {
:container = > { } ,
:object = > { }
} ,
:containers = > { }
}
end
2011-06-15 02:13:18 -04:00
end
def self . reset
@data = nil
end
def initialize ( options = { } )
2013-01-22 17:28:33 -05:00
# 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
2011-07-11 10:46:24 -04:00
@hp_secret_key = options [ :hp_secret_key ]
2012-09-27 15:55:57 -04:00
@hp_tenant_id = options [ :hp_tenant_id ]
2014-02-19 07:30:59 -05:00
@os_account_meta_temp_url_key = options [ :os_account_meta_temp_url_key ]
2011-06-15 02:13:18 -04:00
end
def data
2013-01-22 17:28:33 -05:00
self . class . data [ @hp_access_key ]
2011-06-15 02:13:18 -04:00
end
def reset_data
2013-01-22 17:28:33 -05:00
self . class . data . delete ( @hp_access_key )
2011-06-15 02:13:18 -04:00
end
end
class Real
include Utils
2013-03-27 09:52:52 -04:00
attr_reader :credentials
2011-06-15 02:13:18 -04:00
attr_reader :hp_cdn_ssl
def initialize ( options = { } )
2013-01-22 17:28:33 -05:00
# 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
2014-06-23 13:18:55 -04:00
if options [ :os_account_meta_temp_url_key ]
Fog :: Logger . deprecation ( " :os_account_meta_temp_url_key is deprecated, and will be removed in a future release. please use the :openstack provider instead. " )
@os_account_meta_temp_url_key = options . delete ( :os_account_meta_temp_url_key )
end
2011-07-11 10:46:24 -04:00
@hp_secret_key = options [ :hp_secret_key ]
2012-02-09 18:43:07 -05:00
@hp_auth_uri = options [ :hp_auth_uri ]
2011-10-21 15:51:40 -04:00
@hp_cdn_ssl = options [ :hp_cdn_ssl ]
2011-10-20 22:07:42 -04:00
@connection_options = options [ :connection_options ] || { }
2012-01-13 20:12:39 -05:00
### Set an option to use the style of authentication desired; :v1 or :v2 (default)
2013-09-30 11:58:29 -04:00
### A symbol is required, we should ensure that the value is loaded as a symbol
2013-10-07 05:29:31 -04:00
auth_version = options [ :hp_auth_version ] || :v2
auth_version = auth_version . to_s . downcase . to_sym
2014-02-19 07:30:59 -05:00
2012-05-01 12:15:22 -04:00
### Pass the service name for object storage to the authentication call
2013-09-25 10:46:03 -04:00
options [ :hp_service_type ] || = " Object Storage "
2012-01-18 17:23:54 -05:00
@hp_tenant_id = options [ :hp_tenant_id ]
2012-04-27 14:13:39 -04:00
@hp_avl_zone = options [ :hp_avl_zone ]
2011-06-15 02:13:18 -04:00
2012-01-13 20:12:39 -05:00
### Make the authentication call
if ( auth_version == :v2 )
# Call the control services authentication
credentials = Fog :: HP . authenticate_v2 ( options , @connection_options )
2012-01-18 17:23:54 -05:00
# the CS service catalog returns the cdn endpoint
2012-01-19 14:50:43 -05:00
@hp_storage_uri = credentials [ :endpoint_url ]
2012-01-18 17:23:54 -05:00
@hp_cdn_uri = credentials [ :cdn_endpoint_url ]
2013-03-27 09:52:52 -04:00
@credentials = credentials
2012-01-13 20:12:39 -05:00
else
# Call the legacy v1.0/v1.1 authentication
credentials = Fog :: HP . authenticate_v1 ( options , @connection_options )
2012-01-18 17:23:54 -05:00
# the user sends in the cdn endpoint
2012-01-19 14:50:43 -05:00
@hp_storage_uri = options [ :hp_auth_uri ]
2012-01-18 17:23:54 -05:00
@hp_cdn_uri = options [ :hp_cdn_uri ]
2012-01-13 20:12:39 -05:00
end
2012-01-09 17:05:51 -05:00
2012-01-13 20:12:39 -05:00
@auth_token = credentials [ :auth_token ]
2012-01-18 17:23:54 -05:00
2012-01-19 14:50:43 -05:00
uri = URI . parse ( @hp_storage_uri )
2012-05-08 15:08:03 -04:00
@host = uri . host
2011-06-15 02:13:18 -04:00
@path = uri . path
2011-10-20 22:07:42 -04:00
@persistent = options [ :persistent ] || false
2011-06-15 02:13:18 -04:00
@port = uri . port
@scheme = uri . scheme
2012-01-18 17:23:54 -05:00
2014-02-26 19:50:35 -05:00
@connection = Fog :: XML :: Connection . new ( " #{ @scheme } :// #{ @host } : #{ @port } " , @persistent , @connection_options )
2011-06-15 02:13:18 -04:00
end
def reload
@connection . reset
end
def request ( params , parse_json = true , & block )
begin
response = @connection . request ( params . merge! ( {
:headers = > {
'Content-Type' = > 'application/json' ,
2013-03-13 11:33:51 -04:00
'Accept' = > 'application/json' ,
2011-06-15 02:13:18 -04:00
'X-Auth-Token' = > @auth_token
} . merge! ( params [ :headers ] || { } ) ,
:path = > " #{ @path } / #{ params [ :path ] } " ,
} ) , & block )
rescue Excon :: Errors :: HTTPStatusError = > error
raise case error
when Excon :: Errors :: NotFound
2011-10-17 15:25:07 -04:00
Fog :: Storage :: HP :: NotFound . slurp ( error )
2011-06-15 02:13:18 -04:00
else
error
end
end
if ! response . body . empty? && parse_json && response . headers [ 'Content-Type' ] =~ %r{ application/json }
2012-04-25 10:31:28 -04:00
response . body = Fog :: JSON . decode ( response . body )
2011-06-15 02:13:18 -04:00
end
response
end
2012-10-16 22:51:59 -04:00
# 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' ,
2013-03-13 11:33:51 -04:00
'Accept' = > 'application/json' ,
2012-10-16 22:51:59 -04:00
'X-Auth-Token' = > @auth_token
} . merge! ( params [ :headers ] || { } ) ,
:path = > " #{ params [ :path ] } " ,
} ) , & block )
rescue Excon :: Errors :: HTTPStatusError = > error
raise case error
when Excon :: Errors :: NotFound
Fog :: Storage :: HP :: NotFound . slurp ( error )
2012-10-19 01:33:20 -04:00
when Excon :: Errors :: Forbidden
Fog :: HP :: Errors :: Forbidden . slurp ( error )
2012-10-16 22:51:59 -04:00
else
error
end
end
if ! response . body . empty? && parse_json && response . headers [ 'Content-Type' ] =~ %r{ application/json }
2013-01-18 15:06:41 -05:00
response . body = Fog :: JSON . decode ( response . body )
2012-10-16 22:51:59 -04:00
end
response
end
2011-06-15 02:13:18 -04:00
end
end
end
end