1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
module Fog
module AWS
class Storage
class Real
require 'fog/aws/parsers/storage/get_bucket_object_versions'
# List information about object versions in an S3 bucket
#
# @param bucket_name [String] name of bucket to list object keys from
# @param options [Hash] config arguments for list
# @option options delimiter [String] causes keys with the same string between the prefix value and the first occurence of delimiter to be rolled up
# @option options key-marker [String] limits object keys to only those that appear lexicographically after its value.
# @option options max-keys [Integer] limits number of object keys returned
# @option options prefix [String] limits object keys to those beginning with its value.
# @option options version-id-marker [String] limits object versions to only those that appear lexicographically after its value
#
# @return [Excon::Response] response:
# * body [Hash]:
# * Delimeter [String] - Delimiter specified for query
# * KeyMarker [String] - Key marker specified for query
# * MaxKeys [Integer] - Maximum number of keys specified for query
# * Name [String] - Name of the bucket
# * Prefix [String] - Prefix specified for query
# * VersionIdMarker [String] - Version id marker specified for query
# * IsTruncated [Boolean] - Whether or not this is the totality of the bucket
# * Versions [Array]:
# * DeleteMarker [Hash]:
# * IsLatest [Boolean] - Whether or not this is the latest version
# * Key [String] - Name of object
# * LastModified [String]: Timestamp of last modification of object
# * Owner [Hash]:
# * DisplayName [String] - Display name of object owner
# * ID [String] - Id of object owner
# * VersionId [String] - The id of this version
# or
# * Version [Hash]:
# * ETag [String]: Etag of object
# * IsLatest [Boolean] - Whether or not this is the latest version
# * Key [String] - Name of object
# * LastModified [String]: Timestamp of last modification of object
# * Owner [Hash]:
# * DisplayName [String] - Display name of object owner
# * ID [String] - Id of object owner
# * Size [Integer] - Size of object
# * StorageClass [String] - Storage class of object
# * VersionId [String] - The id of this version
#
# @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGETVersion.html
def get_bucket_object_versions(bucket_name, options = {})
unless bucket_name
raise ArgumentError.new('bucket_name is required')
end
request({
:expects => 200,
:headers => {},
:bucket_name => bucket_name,
:idempotent => true,
:method => 'GET',
:parser => Fog::Parsers::AWS::Storage::GetBucketObjectVersions.new,
:query => {'versions' => nil}.merge!(options) })
end
end
class Mock
def get_bucket_object_versions(bucket_name, options = {})
delimiter, key_marker, max_keys, prefix, version_id_marker = \
options['delimiter'], options['key-marker'], options['max-keys'],options['prefix'],options['version-id-marker']
unless bucket_name
raise ArgumentError.new('bucket_name is required')
end
response = Excon::Response.new
# Invalid arguments.
if version_id_marker && !key_marker
response.status = 400
response.body = {
'Error' => {
'Code' => 'InvalidArgument',
'Message' => 'A version-id marker cannot be specified without a key marker.',
'ArgumentValue' => version_id_marker,
'RequestId' => Fog::Mock.random_hex(16),
'HostId' => Fog::Mock.random_base64(65)
}
}
raise(Excon::Errors.status_error({:expects => 200}, response))
# Valid case.
# TODO: (nirvdrum 12/15/11) It's not clear to me how to actually use version-id-marker, so I didn't implement it below.
elsif bucket = self.data[:buckets][bucket_name]
# We need to order results by S3 key, but since our data store is key => [versions], we want to ensure the integrity
# of the versions as well. So, sort the keys, then fetch the versions, and then combine them all as a sorted list by
# flattening the results.
contents = bucket[:objects].keys.sort.map { |key| bucket[:objects][key] }.flatten.reject do |object|
(prefix && object['Key'][0...prefix.length] != prefix) ||
(key_marker && object['Key'] <= key_marker) ||
(delimiter && object['Key'][(prefix ? prefix.length : 0)..-1].include?(delimiter) \
&& common_prefixes << object['Key'].sub(/^(#{prefix}[^#{delimiter}]+.).*/, '\1'))
end.map do |object|
if object.key?(:delete_marker)
tag_name = 'DeleteMarker'
extracted_attrs = ['Key', 'VersionId']
else
tag_name = 'Version'
extracted_attrs = ['ETag', 'Key', 'StorageClass', 'VersionId']
end
data = {}
data[tag_name] = object.reject { |key, value| !extracted_attrs.include?(key) }
data[tag_name].merge!({
'LastModified' => Time.parse(object['Last-Modified']),
'Owner' => bucket['Owner'],
'IsLatest' => object == bucket[:objects][object['Key']].first
})
data[tag_name]['Size'] = object['Content-Length'].to_i if tag_name == 'Version'
data
end
max_keys = max_keys || 1000
size = [max_keys, 1000].min
truncated_contents = contents[0...size]
response.status = 200
response.body = {
'Versions' => truncated_contents,
'IsTruncated' => truncated_contents.size != contents.size,
'KeyMarker' => key_marker,
'VersionIdMarker' => version_id_marker,
'MaxKeys' => max_keys,
'Name' => bucket['Name'],
'Prefix' => prefix
}
if max_keys && max_keys < response.body['Versions'].length
response.body['IsTruncated'] = true
response.body['Versions'] = response.body['Versions'][0...max_keys]
end
# Missing bucket case.
else
response.status = 404
response.body = {
'Error' => {
'Code' => 'NoSuchBucket',
'Message' => 'The specified bucket does not exist',
'BucketName' => bucket_name,
'RequestId' => Fog::Mock.random_hex(16),
'HostId' => Fog::Mock.random_base64(65)
}
}
raise(Excon::Errors.status_error({:expects => 200}, response))
end
response
end
end
end
end
end
|