mirror of
https://github.com/fog/fog.git
synced 2022-11-09 13:51:43 -05:00
Merge pull request #10 from SDK-CLI-Docs/feature/93_cross_tenant_acls
Feature/93 cross tenant acls
This commit is contained in:
commit
24d5dac17e
16 changed files with 731 additions and 81 deletions
|
@ -20,8 +20,13 @@ module Fog
|
|||
data = nil
|
||||
message = nil
|
||||
else
|
||||
begin
|
||||
data = MultiJson.decode(error.response.body)
|
||||
message = data['message']
|
||||
rescue MultiJson::DecodeError
|
||||
data = error.response.body #### the body is not in JSON format so just return it as it is
|
||||
message = data
|
||||
end
|
||||
end
|
||||
|
||||
new_error = super(error, message)
|
||||
|
@ -33,6 +38,7 @@ module Fog
|
|||
class InternalServerError < ServiceError; end
|
||||
class Conflict < ServiceError; end
|
||||
class NotFound < ServiceError; end
|
||||
class Forbidden < ServiceError; end
|
||||
class ServiceUnavailable < ServiceError; end
|
||||
|
||||
class BadRequest < ServiceError
|
||||
|
|
|
@ -15,24 +15,8 @@ module Fog
|
|||
end
|
||||
|
||||
def head(key, options = {})
|
||||
read_header = nil
|
||||
write_header = nil
|
||||
data = connection.head_container(key)
|
||||
directory = new(:key => key)
|
||||
for key, value in data.headers
|
||||
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
|
||||
directory.merge_attributes(key => value)
|
||||
end
|
||||
if key == 'X-Container-Read'
|
||||
read_header = value
|
||||
elsif key == 'X-Container-Write'
|
||||
write_header = value
|
||||
end
|
||||
end
|
||||
# set the acl on the directory based on the headers
|
||||
if !(read_header.nil? && write_header.nil?)
|
||||
directory.acl = connection.header_to_acl(read_header, write_header)
|
||||
end
|
||||
directory = create_directory(key, data)
|
||||
# set the cdn state for the directory
|
||||
directory.cdn_enabled?
|
||||
|
||||
|
@ -42,24 +26,9 @@ module Fog
|
|||
end
|
||||
|
||||
def get(key, options = {})
|
||||
read_header = nil
|
||||
write_header = nil
|
||||
data = connection.get_container(key, options)
|
||||
directory = new(:key => key)
|
||||
for key, value in data.headers
|
||||
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
|
||||
directory.merge_attributes(key => value)
|
||||
end
|
||||
if key == 'X-Container-Read'
|
||||
read_header = value
|
||||
elsif key == 'X-Container-Write'
|
||||
write_header = value
|
||||
end
|
||||
end
|
||||
# set the acl on the directory based on the headers
|
||||
if !(read_header.nil? && write_header.nil?)
|
||||
directory.acl = connection.header_to_acl(read_header, write_header)
|
||||
end
|
||||
directory = create_directory(key, data)
|
||||
# set the files for the directory
|
||||
directory.files.merge_attributes(options)
|
||||
directory.files.instance_variable_set(:@loaded, true)
|
||||
data.body.each do |file|
|
||||
|
@ -73,6 +42,32 @@ module Fog
|
|||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_directory(key, data)
|
||||
read_header = nil
|
||||
write_header = nil
|
||||
directory = new(:key => key)
|
||||
for key, value in data.headers
|
||||
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
|
||||
directory.merge_attributes(key => value)
|
||||
end
|
||||
if key == 'X-Container-Read'
|
||||
read_header = value
|
||||
elsif key == 'X-Container-Write'
|
||||
write_header = value
|
||||
end
|
||||
end
|
||||
# set the acl on the directory based on the headers
|
||||
if !(read_header.nil? && write_header.nil?)
|
||||
read_acl, write_acl = connection.header_to_perm_acl(read_header, write_header)
|
||||
# do not want to expose the read_acl and write_acl as writable attributes
|
||||
directory.instance_variable_set(:@read_acl, read_acl)
|
||||
directory.instance_variable_set(:@write_acl, write_acl)
|
||||
end
|
||||
directory
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -12,15 +12,70 @@ module Fog
|
|||
attribute :bytes, :aliases => 'X-Container-Bytes-Used'
|
||||
attribute :count, :aliases => 'X-Container-Object-Count'
|
||||
|
||||
def acl=(new_acl)
|
||||
if new_acl.nil?
|
||||
new_acl = "private"
|
||||
def initialize(attributes = {})
|
||||
@read_acl = []
|
||||
@write_acl = []
|
||||
super
|
||||
end
|
||||
valid_acls = ['private', 'public-read', 'public-write', 'public-read-write']
|
||||
unless valid_acls.include?(new_acl)
|
||||
raise ArgumentError.new("acl must be one of [#{valid_acls.join(', ')}]")
|
||||
|
||||
def read_acl
|
||||
@read_acl
|
||||
end
|
||||
@acl = new_acl
|
||||
|
||||
def write_acl
|
||||
@write_acl
|
||||
end
|
||||
|
||||
def can_read?(user)
|
||||
return false if @read_acl.nil?
|
||||
list_users_with_read.include?(user)
|
||||
end
|
||||
|
||||
def can_write?(user)
|
||||
return false if @write_acl.nil?
|
||||
list_users_with_write.include?(user)
|
||||
end
|
||||
|
||||
def can_read_write?(user)
|
||||
can_read?(user) && can_write?(user)
|
||||
end
|
||||
|
||||
def list_users_with_read
|
||||
users = []
|
||||
users = @read_acl.map {|acl| acl.split(':')[1]} unless @read_acl.nil?
|
||||
return users
|
||||
end
|
||||
|
||||
def list_users_with_write
|
||||
users = []
|
||||
users = @write_acl.map {|acl| acl.split(':')[1]} unless @write_acl.nil?
|
||||
return users
|
||||
end
|
||||
|
||||
def grant(perm, users=[])
|
||||
r_acl, w_acl = connection.perm_to_acl(perm, users)
|
||||
unless r_acl.nil?
|
||||
@read_acl = @read_acl + r_acl
|
||||
@read_acl.uniq!
|
||||
end
|
||||
unless w_acl.nil?
|
||||
@write_acl = @write_acl + w_acl
|
||||
@write_acl.uniq!
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def revoke(perm, users=[])
|
||||
r_acl, w_acl = connection.perm_to_acl(perm, users)
|
||||
unless r_acl.nil?
|
||||
@read_acl = @read_acl - r_acl
|
||||
@read_acl.uniq!
|
||||
end
|
||||
unless w_acl.nil?
|
||||
@write_acl = @write_acl - w_acl
|
||||
@write_acl.uniq!
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -50,18 +105,20 @@ module Fog
|
|||
|
||||
def public=(new_public)
|
||||
if new_public
|
||||
@acl = 'public-read'
|
||||
self.grant("pr")
|
||||
else
|
||||
@acl = 'private'
|
||||
self.revoke("pr")
|
||||
end
|
||||
@public = new_public
|
||||
end
|
||||
|
||||
def public?
|
||||
if @acl.nil?
|
||||
if @read_acl.empty?
|
||||
false
|
||||
elsif @read_acl.include?(".r:*")
|
||||
true
|
||||
else
|
||||
@acl == 'public-read'
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -70,7 +127,7 @@ module Fog
|
|||
@public_url ||= begin
|
||||
begin response = connection.head_container(key)
|
||||
# escape the key to cover for special char. in container names
|
||||
url = "#{connection.url}/#{Fog::HP.escape(key)}"
|
||||
url = connection.public_url(key)
|
||||
rescue Fog::Storage::HP::NotFound => err
|
||||
nil
|
||||
end
|
||||
|
@ -135,9 +192,8 @@ module Fog
|
|||
def save
|
||||
requires :key
|
||||
options = {}
|
||||
if @acl
|
||||
options.merge!(connection.acl_to_header(@acl))
|
||||
end
|
||||
# write out the acls into the headers before save
|
||||
options.merge!(connection.perm_acl_to_header(@read_acl, @write_acl))
|
||||
connection.put_container(key, options)
|
||||
# Added an extra check to see if CDN is enabled for the container
|
||||
if (!connection.cdn.nil? && connection.cdn.enabled?)
|
||||
|
|
49
lib/fog/hp/models/storage/shared_directories.rb
Normal file
49
lib/fog/hp/models/storage/shared_directories.rb
Normal file
|
@ -0,0 +1,49 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/hp/models/storage/shared_directory'
|
||||
|
||||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
|
||||
class SharedDirectories < Fog::Collection
|
||||
|
||||
model Fog::Storage::HP::SharedDirectory
|
||||
|
||||
def head(url)
|
||||
data = connection.head_shared_container(url)
|
||||
shared_directory = new(:url => url)
|
||||
for key, value in data.headers
|
||||
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
|
||||
shared_directory.merge_attributes(key => value)
|
||||
end
|
||||
end
|
||||
|
||||
shared_directory
|
||||
rescue Fog::Storage::HP::NotFound, Fog::HP::Errors::Forbidden
|
||||
nil
|
||||
end
|
||||
|
||||
def get(url)
|
||||
data = connection.get_shared_container(url)
|
||||
shared_directory = new(:url => url)
|
||||
for key, value in data.headers
|
||||
if ['X-Container-Bytes-Used', 'X-Container-Object-Count'].include?(key)
|
||||
shared_directory.merge_attributes(key => value)
|
||||
end
|
||||
end
|
||||
# set the files for the directory
|
||||
shared_directory.files.instance_variable_set(:@loaded, true)
|
||||
data.body.each do |file|
|
||||
shared_directory.files << shared_directory.files.new(file)
|
||||
end
|
||||
|
||||
shared_directory
|
||||
rescue Fog::Storage::HP::NotFound, Fog::HP::Errors::Forbidden
|
||||
nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
28
lib/fog/hp/models/storage/shared_directory.rb
Normal file
28
lib/fog/hp/models/storage/shared_directory.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
require 'fog/core/model'
|
||||
require 'fog/hp/models/storage/shared_files'
|
||||
|
||||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
|
||||
class SharedDirectory < Fog::Model
|
||||
|
||||
identity :url
|
||||
|
||||
attribute :bytes, :aliases => 'X-Container-Bytes-Used'
|
||||
attribute :count, :aliases => 'X-Container-Object-Count'
|
||||
|
||||
def files
|
||||
@files ||= begin
|
||||
Fog::Storage::HP::SharedFiles.new(
|
||||
:shared_directory => self,
|
||||
:connection => connection
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
57
lib/fog/hp/models/storage/shared_file.rb
Normal file
57
lib/fog/hp/models/storage/shared_file.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
require 'fog/core/model'
|
||||
|
||||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
|
||||
class SharedFile < Fog::Model
|
||||
|
||||
identity :key, :aliases => 'name'
|
||||
attribute :url
|
||||
|
||||
attribute :content_length, :aliases => ['bytes', 'Content-Length'], :type => :integer
|
||||
attribute :content_type, :aliases => ['content_type', 'Content-Type']
|
||||
attribute :etag, :aliases => ['hash', 'Etag']
|
||||
attribute :last_modified, :aliases => ['last_modified', 'Last-Modified'], :type => :time
|
||||
|
||||
def url
|
||||
"#{self.collection.shared_directory.url}/#{key}"
|
||||
end
|
||||
|
||||
def body
|
||||
attributes[:body] ||= if last_modified
|
||||
collection.get(identity).body
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
def body=(new_body)
|
||||
attributes[:body] = new_body
|
||||
end
|
||||
|
||||
def shared_directory
|
||||
@shared_directory
|
||||
end
|
||||
|
||||
def save(options = {})
|
||||
requires :shared_directory, :key
|
||||
options['Content-Type'] = content_type if content_type
|
||||
data = connection.put_shared_object(shared_directory.url, key, body, options)
|
||||
merge_attributes(data.headers)
|
||||
self.content_length = Fog::Storage.get_body_size(body)
|
||||
true
|
||||
rescue Fog::Storage::HP::NotFound, Fog::HP::Errors::Forbidden
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def shared_directory=(new_shared_directory)
|
||||
@shared_directory = new_shared_directory
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
60
lib/fog/hp/models/storage/shared_files.rb
Normal file
60
lib/fog/hp/models/storage/shared_files.rb
Normal file
|
@ -0,0 +1,60 @@
|
|||
require 'fog/core/collection'
|
||||
require 'fog/hp/models/storage/shared_file'
|
||||
|
||||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
|
||||
class SharedFiles < Fog::Collection
|
||||
|
||||
attribute :shared_directory
|
||||
|
||||
model Fog::Storage::HP::SharedFile
|
||||
|
||||
def all
|
||||
requires :shared_directory
|
||||
parent = shared_directory.collection.get(shared_directory.url)
|
||||
if parent
|
||||
load(parent.files.map {|file| file.attributes})
|
||||
else
|
||||
nil
|
||||
end
|
||||
rescue Fog::Storage::HP::NotFound, Fog::HP::Errors::Forbidden
|
||||
nil
|
||||
end
|
||||
|
||||
def get(key, &block)
|
||||
requires :shared_directory
|
||||
shared_object_url = "#{shared_directory.url}/#{key}"
|
||||
data = connection.get_shared_object(shared_object_url, &block)
|
||||
file_data = data.headers.merge({
|
||||
:body => data.body,
|
||||
:key => key
|
||||
})
|
||||
new(file_data)
|
||||
rescue Fog::Storage::HP::NotFound, Fog::HP::Errors::Forbidden
|
||||
nil
|
||||
end
|
||||
|
||||
def head(key)
|
||||
requires :shared_directory
|
||||
shared_object_url = "#{shared_directory.url}/#{key}"
|
||||
data = connection.head_shared_object(shared_object_url)
|
||||
file_data = data.headers.merge({
|
||||
:key => key
|
||||
})
|
||||
new(file_data)
|
||||
rescue Fog::Storage::HP::NotFound, Fog::HP::Errors::Forbidden
|
||||
nil
|
||||
end
|
||||
|
||||
def new(attributes = {})
|
||||
requires :shared_directory
|
||||
super({ :shared_directory => shared_directory }.merge!(attributes))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
75
lib/fog/hp/requests/storage/get_shared_container.rb
Normal file
75
lib/fog/hp/requests/storage/get_shared_container.rb
Normal file
|
@ -0,0 +1,75 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
class Real
|
||||
|
||||
# Get details for a shared container
|
||||
#
|
||||
# ==== Parameters
|
||||
# * shared_container_url<~String> - Url of the shared container
|
||||
# * options<~String>:
|
||||
# * 'limit'<~String> - Maximum number of objects to return
|
||||
# * 'marker'<~String> - Only return objects whose name is greater than marker
|
||||
# * 'prefix'<~String> - Limits results to those starting with prefix
|
||||
# * 'path'<~String> - Return objects nested in the pseudo path
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * headers<~Hash>:
|
||||
# * 'X-Container-Object-Count'<~String> - Count of objects in container
|
||||
# * 'X-Container-Bytes-Used'<~String> - Bytes used
|
||||
# * 'X-Trans-Id'<~String> - Trans Id
|
||||
# * body<~Array>:
|
||||
# * item<~Hash>:
|
||||
# * 'bytes'<~String> - Size of object
|
||||
# * 'content_type'<~String> Content-Type of object
|
||||
# * 'hash'<~String> - Hash of object (etag?)
|
||||
# * 'last_modified'<~String> - Last modified timestamp
|
||||
# * 'name'<~String> - Name of object
|
||||
def get_shared_container(shared_container_url, options = {})
|
||||
options = options.reject {|key, value| value.nil?}
|
||||
# split up the shared container url
|
||||
uri = URI.parse(shared_container_url)
|
||||
path = uri.path
|
||||
|
||||
response = shared_request(
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path,
|
||||
:query => {'format' => 'json'}.merge!(options)
|
||||
)
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def get_shared_container(shared_container_url, options = {})
|
||||
response = Excon::Response.new
|
||||
data = {
|
||||
'name' => Fog::Mock.random_letters(10),
|
||||
'hash' => Fog::HP::Mock.etag,
|
||||
'bytes' => 11,
|
||||
'content_type' => "text/plain",
|
||||
'last_modified' => Time.now
|
||||
}
|
||||
response.status = 200
|
||||
response.body = [data]
|
||||
response.headers = {
|
||||
'X-Container-Object-Count' => 1,
|
||||
'X-Container-Bytes-Used' => 11,
|
||||
'Accept-Ranges' => 'bytes',
|
||||
'Content-Type' => "application/json",
|
||||
'Content-Length' => 11,
|
||||
'X-Trans-Id' => "tx#{Fog::Mock.random_hex(32)}"
|
||||
}
|
||||
response
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
67
lib/fog/hp/requests/storage/get_shared_object.rb
Normal file
67
lib/fog/hp/requests/storage/get_shared_object.rb
Normal file
|
@ -0,0 +1,67 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
class Real
|
||||
|
||||
# Get details for a shared object
|
||||
#
|
||||
# ==== Parameters
|
||||
# * shared_object_url<~String> - Url of the shared object
|
||||
#
|
||||
def get_shared_object(shared_object_url, &block)
|
||||
# split up the shared object url
|
||||
uri = URI.parse(shared_object_url)
|
||||
path = uri.path
|
||||
|
||||
if block_given?
|
||||
response = shared_request(
|
||||
:response_block => block,
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
)
|
||||
else
|
||||
response = shared_request({
|
||||
:block => block,
|
||||
:expects => 200,
|
||||
:method => 'GET',
|
||||
:path => path
|
||||
}, false, &block)
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def get_shared_object(shared_object_url, &block)
|
||||
response = Excon::Response.new
|
||||
response.status = 200
|
||||
response.headers = {
|
||||
'Last-Modified' => Date.today.rfc822,
|
||||
'Etag' => Fog::HP::Mock.etag,
|
||||
'Accept-Ranges' => 'bytes',
|
||||
'Content-Type' => "text/plain",
|
||||
'Content-Length' => 11,
|
||||
'X-Trans-Id' => "tx#{Fog::Mock.random_hex(32)}"
|
||||
}
|
||||
unless block_given?
|
||||
response.body = "This is a sample text.\n"
|
||||
else
|
||||
data = StringIO.new("This is a sample text.\n")
|
||||
remaining = data.length
|
||||
while remaining > 0
|
||||
chunk = data.read([remaining, Excon::CHUNK_SIZE].min)
|
||||
block.call(chunk)
|
||||
remaining -= Excon::CHUNK_SIZE
|
||||
end
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,6 +30,7 @@ module Fog
|
|||
def head_container(container_name)
|
||||
response = get_container(container_name)
|
||||
response.body = nil
|
||||
response.status = 204
|
||||
response
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module Fog
|
|||
#
|
||||
def head_object(container, object)
|
||||
response = request({
|
||||
:expects => 200,
|
||||
:expects => 200, # should be 204
|
||||
:method => 'HEAD',
|
||||
:path => "#{Fog::HP.escape(container)}/#{Fog::HP.escape(object)}"
|
||||
}, false)
|
||||
|
@ -25,6 +25,7 @@ module Fog
|
|||
def head_object(container_name, object_name, options = {})
|
||||
response = get_object(container_name, object_name, options)
|
||||
response.body = nil
|
||||
response.status = 200 # should be 204
|
||||
response
|
||||
end
|
||||
|
||||
|
|
45
lib/fog/hp/requests/storage/head_shared_container.rb
Normal file
45
lib/fog/hp/requests/storage/head_shared_container.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
class Real
|
||||
|
||||
# List number of objects and total bytes stored for a shared container
|
||||
#
|
||||
# ==== Parameters
|
||||
# * shared_container_url<~String> - Url of the shared container
|
||||
#
|
||||
# ==== Returns
|
||||
# * response<~Excon::Response>:
|
||||
# * headers<~Hash>:
|
||||
# * 'X-Container-Object-Count'<~String> - Count of containers
|
||||
# * 'X-Container-Bytes-Used'<~String> - Bytes used
|
||||
def head_shared_container(shared_container_url)
|
||||
# split up the shared container url
|
||||
uri = URI.parse(shared_container_url)
|
||||
path = uri.path
|
||||
|
||||
response = shared_request(
|
||||
:expects => 204,
|
||||
:method => 'HEAD',
|
||||
:path => path,
|
||||
:query => {'format' => 'json'}
|
||||
)
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def head_shared_container(shared_container_url)
|
||||
response = get_shared_container(shared_container_url)
|
||||
response.body = nil
|
||||
response.status = 204
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
39
lib/fog/hp/requests/storage/head_shared_object.rb
Normal file
39
lib/fog/hp/requests/storage/head_shared_object.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
class Real
|
||||
|
||||
# Get headers for shared object
|
||||
#
|
||||
# ==== Parameters
|
||||
# * * shared_object_url<~String> - Url of the shared object
|
||||
#
|
||||
def head_shared_object(shared_object_url)
|
||||
# split up the shared object url
|
||||
uri = URI.parse(shared_object_url)
|
||||
path = uri.path
|
||||
|
||||
response = shared_request({
|
||||
:expects => 200, # should be 204
|
||||
:method => 'HEAD',
|
||||
:path => path
|
||||
}, false)
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def head_shared_object(shared_object_url)
|
||||
response = get_shared_object(shared_object_url)
|
||||
response.body = nil
|
||||
response.status = 200 # should be 204
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,16 +22,16 @@ module Fog
|
|||
|
||||
class Mock # :nodoc:all
|
||||
def put_container(container_name, options = {})
|
||||
acl = options['X-Container-Read'] || 'private'
|
||||
if !['private', 'public-read'].include?(acl)
|
||||
#raise Excon::Errors::BadRequest.new('invalid X-Container-Read')
|
||||
else
|
||||
self.data[:acls][:container][container_name] = self.class.acls(acl)
|
||||
read_h = options['X-Container-Read'] || ''
|
||||
write_h = options['X-Container-Write'] || ''
|
||||
unless options
|
||||
read_acl, write_acl = self.class.header_to_perm_acl(read_h, write_h)
|
||||
self.data[:acls][:container][container_name] = {:read_acl => read_acl, :write_acl => write_acl}
|
||||
end
|
||||
|
||||
response = Excon::Response.new
|
||||
container = {
|
||||
:objects => {},
|
||||
:objects => {}
|
||||
}
|
||||
if self.data[:containers][container_name]
|
||||
response.status = 202
|
||||
|
|
85
lib/fog/hp/requests/storage/put_shared_object.rb
Normal file
85
lib/fog/hp/requests/storage/put_shared_object.rb
Normal file
|
@ -0,0 +1,85 @@
|
|||
module Fog
|
||||
module Storage
|
||||
class HP
|
||||
class Real
|
||||
|
||||
# Create a new object in a shared container
|
||||
#
|
||||
# ==== Parameters
|
||||
# * shared_container_url<~String> - Shared url for the container
|
||||
# * object<~String> - Name of the object
|
||||
# * options<~Hash> - header options
|
||||
#
|
||||
def put_shared_object(shared_container_url, object_name, data, options = {}, &block)
|
||||
# split up the shared object url
|
||||
uri = URI.parse(shared_container_url)
|
||||
path = uri.path
|
||||
|
||||
data = Fog::Storage.parse_data(data)
|
||||
headers = data[:headers].merge!(options)
|
||||
if block_given?
|
||||
headers['Transfer-Encoding'] = 'chunked'
|
||||
headers.delete('Content-Length')
|
||||
return shared_request(
|
||||
:request_block => block,
|
||||
:expects => 201,
|
||||
:headers => headers,
|
||||
:method => 'PUT',
|
||||
:path => "#{path}/#{Fog::HP.escape(object_name)}"
|
||||
)
|
||||
end
|
||||
if headers.has_key?('Transfer-Encoding')
|
||||
headers.delete('Content-Length')
|
||||
end
|
||||
response = shared_request(
|
||||
:body => data[:body],
|
||||
:expects => 201,
|
||||
:headers => headers,
|
||||
:method => 'PUT',
|
||||
:path => "#{path}/#{Fog::HP.escape(object_name)}"
|
||||
)
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Mock # :nodoc:all
|
||||
|
||||
def put_shared_object(shared_container_url, object_name, data, options = {}, &block)
|
||||
response = Excon::Response.new
|
||||
data = Fog::Storage.parse_data(data)
|
||||
unless data[:body].is_a?(String)
|
||||
data[:body] = data[:body].read
|
||||
end
|
||||
response.status = 201
|
||||
object = {
|
||||
:body => data[:body],
|
||||
'Content-Type' => options['Content-Type'] || data[:headers]['Content-Type'],
|
||||
'ETag' => Fog::HP::Mock.etag,
|
||||
'Key' => object_name,
|
||||
'Date' => Fog::Time.now.to_date_header,
|
||||
'Content-Length' => options['Content-Length'] || data[:headers]['Content-Length'],
|
||||
}
|
||||
|
||||
for key, value in options
|
||||
case key
|
||||
when 'Cache-Control', 'Content-Disposition', 'Content-Encoding', 'Content-MD5', 'Expires', /^X-Object-Meta-/
|
||||
object[key] = value
|
||||
end
|
||||
end
|
||||
|
||||
response.headers = {
|
||||
'Content-Length' => object['Content-Length'],
|
||||
'Content-Type' => object['Content-Type'],
|
||||
'ETag' => object['ETag'],
|
||||
'Date' => object['Date']
|
||||
}
|
||||
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -11,8 +11,12 @@ module Fog
|
|||
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
|
||||
|
@ -21,11 +25,16 @@ module Fog
|
|||
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
|
||||
|
||||
|
@ -53,34 +62,80 @@ module Fog
|
|||
"#{@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"
|
||||
end
|
||||
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)
|
||||
|
@ -230,6 +285,37 @@ module Fog
|
|||
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',
|
||||
'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}
|
||||
begin
|
||||
response.body = MultiJson.decode(response.body)
|
||||
rescue MultiJson::DecodeError => error
|
||||
response.body #### the body is not in JSON format so just return it as it is
|
||||
end
|
||||
end
|
||||
response
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue