aws-s3 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +19 -0
- data/INSTALL +35 -0
- data/README +529 -0
- data/Rakefile +284 -0
- data/bin/s3sh +4 -0
- data/bin/setup.rb +10 -0
- data/lib/aws/s3.rb +64 -0
- data/lib/aws/s3/acl.rb +631 -0
- data/lib/aws/s3/authentication.rb +218 -0
- data/lib/aws/s3/base.rb +232 -0
- data/lib/aws/s3/bittorrent.rb +58 -0
- data/lib/aws/s3/bucket.rb +323 -0
- data/lib/aws/s3/connection.rb +212 -0
- data/lib/aws/s3/error.rb +69 -0
- data/lib/aws/s3/exceptions.rb +130 -0
- data/lib/aws/s3/extensions.rb +186 -0
- data/lib/aws/s3/logging.rb +163 -0
- data/lib/aws/s3/object.rb +565 -0
- data/lib/aws/s3/owner.rb +44 -0
- data/lib/aws/s3/parsing.rb +138 -0
- data/lib/aws/s3/response.rb +180 -0
- data/lib/aws/s3/service.rb +43 -0
- data/lib/aws/s3/version.rb +12 -0
- data/support/faster-xml-simple/lib/faster_xml_simple.rb +115 -0
- data/support/faster-xml-simple/test/regression_test.rb +16 -0
- data/support/faster-xml-simple/test/xml_simple_comparison_test.rb +22 -0
- data/support/rdoc/code_info.rb +211 -0
- data/test/acl_test.rb +243 -0
- data/test/authentication_test.rb +96 -0
- data/test/base_test.rb +143 -0
- data/test/bucket_test.rb +48 -0
- data/test/connection_test.rb +120 -0
- data/test/error_test.rb +75 -0
- data/test/extensions_test.rb +282 -0
- data/test/fixtures.rb +89 -0
- data/test/fixtures/buckets.yml +102 -0
- data/test/fixtures/errors.yml +34 -0
- data/test/fixtures/headers.yml +3 -0
- data/test/fixtures/logging.yml +15 -0
- data/test/fixtures/policies.yml +16 -0
- data/test/logging_test.rb +36 -0
- data/test/mocks/base.rb +89 -0
- data/test/object_test.rb +177 -0
- data/test/parsing_test.rb +82 -0
- data/test/remote/acl_test.rb +117 -0
- data/test/remote/bittorrent_test.rb +45 -0
- data/test/remote/bucket_test.rb +127 -0
- data/test/remote/logging_test.rb +82 -0
- data/test/remote/object_test.rb +267 -0
- data/test/remote/test_file.data +0 -0
- data/test/remote/test_helper.rb +30 -0
- data/test/response_test.rb +70 -0
- data/test/service_test.rb +26 -0
- data/test/test_helper.rb +82 -0
- metadata +125 -0
data/lib/aws/s3/error.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
module AWS
|
2
|
+
module S3
|
3
|
+
# Anything you do that makes a request to S3 could result in an error. If it does, the AWS::S3 library will raise an exception
|
4
|
+
# specific to the error. All exception that are raised as a result of a request returning an error response inherit from the
|
5
|
+
# ResponseError exception. So should you choose to rescue any such exception, you can simple rescue ResponseError.
|
6
|
+
#
|
7
|
+
# Say you go to delete a bucket, but the bucket turns out to not be empty. This results in a BucketNotEmpty error (one of the many
|
8
|
+
# errors listed at http://docs.amazonwebservices.com/AmazonS3/2006-03-01/ErrorCodeList.html):
|
9
|
+
#
|
10
|
+
# begin
|
11
|
+
# Bucket.delete('jukebox')
|
12
|
+
# rescue ResponseError => error
|
13
|
+
# # ...
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# Once you've captured the exception, you can extract the error message from S3, as well as the full error response, which includes
|
17
|
+
# things like the HTTP response code:
|
18
|
+
#
|
19
|
+
# error
|
20
|
+
# # => #<AWS::S3::BucketNotEmpty The bucket you tried to delete is not empty>
|
21
|
+
# error.message
|
22
|
+
# # => "The bucket you tried to delete is not empty"
|
23
|
+
# error.response.code
|
24
|
+
# # => 409
|
25
|
+
#
|
26
|
+
# You could use this information to redisplay the error in a way you see fit, or just to log the error and continue on.
|
27
|
+
class Error
|
28
|
+
#:stopdoc:
|
29
|
+
attr_accessor :response
|
30
|
+
def initialize(error, response = nil)
|
31
|
+
@error = error
|
32
|
+
@response = response
|
33
|
+
@container = AWS::S3
|
34
|
+
find_or_create_exception!
|
35
|
+
end
|
36
|
+
|
37
|
+
def raise
|
38
|
+
Kernel.raise exception.new(message, response)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
attr_reader :error, :exception, :container
|
43
|
+
|
44
|
+
def find_or_create_exception!
|
45
|
+
@exception = container.const_defined?(code) ? find_exception : create_exception
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_exception
|
49
|
+
exception_class = container.const_get(code)
|
50
|
+
Kernel.raise ExceptionClassClash.new(exception_class) unless exception_class.ancestors.include?(ResponseError)
|
51
|
+
exception_class
|
52
|
+
end
|
53
|
+
|
54
|
+
def create_exception
|
55
|
+
container.const_set(code, Class.new(ResponseError))
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(method, *args, &block)
|
59
|
+
# We actually want nil if the attribute is nil. So we use has_key? rather than [] + ||.
|
60
|
+
if error.has_key?(method.to_s)
|
61
|
+
error[method.to_s]
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
#:startdoc:
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module AWS
|
2
|
+
module S3
|
3
|
+
|
4
|
+
# Abstract super class of all AWS::S3 exceptions
|
5
|
+
class S3Exception < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# All responses with a code between 300 and 599 that contain an <Error></Error> body are wrapped in an
|
9
|
+
# ErrorResponse which contains an Error object. This Error class generates a custom exception with the name
|
10
|
+
# of the xml Error and its message. All such runtime generated exception classes descend from ResponseError
|
11
|
+
# and contain the ErrorResponse object so that all code that makes a request can rescue ResponseError and get
|
12
|
+
# access to the ErrorResponse.
|
13
|
+
class ResponseError < S3Exception
|
14
|
+
attr_reader :response
|
15
|
+
def initialize(message, response)
|
16
|
+
@response = response
|
17
|
+
super(message)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
#:stopdoc:
|
22
|
+
|
23
|
+
# Most ResponseError's are created just time on a need to have basis, but we explicitly define the
|
24
|
+
# InternalError exception because we want to explicitly rescue InternalError in some cases.
|
25
|
+
class InternalError < ResponseError
|
26
|
+
end
|
27
|
+
|
28
|
+
class NoSuchKey < ResponseError
|
29
|
+
end
|
30
|
+
|
31
|
+
# Abstract super class for all invalid options.
|
32
|
+
class InvalidOption < S3Exception
|
33
|
+
end
|
34
|
+
|
35
|
+
# Raised if an invalid value is passed to the <tt>:access</tt> option when creating a Bucket or an S3Object.
|
36
|
+
class InvalidAccessControlLevel < InvalidOption
|
37
|
+
def initialize(valid_levels, access_level)
|
38
|
+
super("Valid access control levels are #{valid_levels.inspect}. You specified `#{access_level}'.")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Raised if either the access key id or secret access key arguments are missing when establishing a connection.
|
43
|
+
class MissingAccessKey < InvalidOption
|
44
|
+
def initialize(missing_keys)
|
45
|
+
key_list = missing_keys.map {|key| key.to_s}.join(' and the ')
|
46
|
+
super("You did not provide both required access keys. Please provide the #{key_list}.")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Raised if a request is attempted before any connections have been established.
|
51
|
+
class NoConnectionEstablished < S3Exception
|
52
|
+
end
|
53
|
+
|
54
|
+
# Raised if an unrecognized option is passed when establishing a connection.
|
55
|
+
class InvalidConnectionOption < InvalidOption
|
56
|
+
def initialize(invalid_options)
|
57
|
+
message = "The following connection options are invalid: #{invalid_options.join(', ')}. " +
|
58
|
+
"The valid connection options are: #{Connection::Options.valid_options.join(', ')}."
|
59
|
+
super(message)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Raised if an invalid bucket name is passed when creating a new Bucket.
|
64
|
+
class InvalidBucketName < S3Exception
|
65
|
+
def initialize(invalid_name)
|
66
|
+
message = "`#{invalid_name}' is not a valid bucket name. " +
|
67
|
+
"Bucket names must be between 3 and 255 bytes and " +
|
68
|
+
"can contain letters, numbers, dashes and underscores."
|
69
|
+
super(message)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Raised if an invalid key name is passed when creating an S3Object.
|
74
|
+
class InvalidKeyName < S3Exception
|
75
|
+
def initialize(invalid_name)
|
76
|
+
message = "`#{invalid_name}' is not a valid key name. " +
|
77
|
+
"Key names must be no more than 1024 bytes long."
|
78
|
+
super(message)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Raised if an invalid value is assigned to an S3Object's specific metadata name.
|
83
|
+
class InvalidMetadataValue < S3Exception
|
84
|
+
def initialize(invalid_names)
|
85
|
+
message = "The following metadata names have invalid values: #{invalid_names.join(', ')}. " +
|
86
|
+
"Metadata can not be larger than 2kilobytes."
|
87
|
+
super(message)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Raised if the current bucket can not be infered when not explicitly specifying the target bucket in the calling
|
92
|
+
# method's arguments.
|
93
|
+
class CurrentBucketNotSpecified < S3Exception
|
94
|
+
def initialize(address)
|
95
|
+
message = "No bucket name can be inferred from your current connection's address (`#{address}')"
|
96
|
+
super(message)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Raised when an orphaned S3Object belonging to no bucket tries to access its (non-existant) bucket.
|
101
|
+
class NoBucketSpecified < S3Exception
|
102
|
+
def initialize
|
103
|
+
super('The current object must have its bucket set')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Raised if an attempt is made to save an S3Object that does not have a key set.
|
108
|
+
class NoKeySpecified < S3Exception
|
109
|
+
def initialize
|
110
|
+
super('The current object must have its key set')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Raised if you try to save a deleted object.
|
115
|
+
class DeletedObject < S3Exception
|
116
|
+
def initialize
|
117
|
+
super('You can not save a deleted object')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class ExceptionClassClash < S3Exception #:nodoc:
|
122
|
+
def initialize(klass)
|
123
|
+
message = "The exception class you tried to create (`#{klass}') exists and is not an exception"
|
124
|
+
super(message)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
#:startdoc:
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#:stopdoc:
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
def to_query_string(include_question_mark = true)
|
5
|
+
return '' if empty?
|
6
|
+
query_string = ''
|
7
|
+
query_string << '?' if include_question_mark
|
8
|
+
query_string << inject([]) do |parameters, (key, value)|
|
9
|
+
parameters << [key, value].map {|element| CGI.escape(element.to_s)}.join('=')
|
10
|
+
end.join('&')
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_normalized_options
|
14
|
+
# Convert all option names to downcased strings, and replace underscores with hyphens
|
15
|
+
inject({}) do |normalized_options, (name, value)|
|
16
|
+
normalized_options[name.to_header] = value.to_s
|
17
|
+
normalized_options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_normalized_options!
|
22
|
+
replace(to_normalized_options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class String
|
27
|
+
def previous!
|
28
|
+
self[-1] = self[-1] - 1
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def previous
|
33
|
+
dup.previous!
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_header
|
37
|
+
downcase.gsub('_', '-')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Symbol
|
42
|
+
def to_header
|
43
|
+
to_s.to_header
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Kernel
|
48
|
+
def __method__(depth = 0)
|
49
|
+
caller[depth][/`([^']+)'/, 1]
|
50
|
+
end if RUBY_VERSION < '1.9'
|
51
|
+
|
52
|
+
def memoize(reload = false, storage = nil)
|
53
|
+
storage = "@#{storage || __method__(1)}"
|
54
|
+
if reload
|
55
|
+
instance_variable_set(storage, nil)
|
56
|
+
else
|
57
|
+
if cache = instance_variable_get(storage)
|
58
|
+
return cache
|
59
|
+
end
|
60
|
+
end
|
61
|
+
instance_variable_set(storage, yield)
|
62
|
+
end
|
63
|
+
|
64
|
+
def require_library_or_gem(library)
|
65
|
+
require library
|
66
|
+
rescue LoadError => library_not_installed
|
67
|
+
begin
|
68
|
+
require 'rubygems'
|
69
|
+
require library
|
70
|
+
rescue LoadError
|
71
|
+
raise library_not_installed
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Module
|
77
|
+
def memoized(method_name)
|
78
|
+
original_method = "unmemoized_#{method_name}_#{Time.now.to_i}"
|
79
|
+
alias_method original_method, method_name
|
80
|
+
module_eval(<<-EVAL, __FILE__, __LINE__)
|
81
|
+
def #{method_name}(reload = false, *args, &block)
|
82
|
+
memoize(reload) do
|
83
|
+
send(:#{original_method}, *args, &block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
EVAL
|
87
|
+
end
|
88
|
+
|
89
|
+
def constant(name, value)
|
90
|
+
unless const_defined?(name)
|
91
|
+
const_set(name, value)
|
92
|
+
module_eval(<<-EVAL, __FILE__, __LINE__)
|
93
|
+
def self.#{name.to_s.downcase}
|
94
|
+
#{name.to_s}
|
95
|
+
end
|
96
|
+
EVAL
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Transforms MarcelBucket into
|
101
|
+
#
|
102
|
+
# class MarcelBucket < AWS::S3::Bucket
|
103
|
+
# set_current_bucket_to 'marcel'
|
104
|
+
# end
|
105
|
+
def const_missing_from_s3_library(sym)
|
106
|
+
if sym.to_s =~ /^(\w+)(Bucket|S3Object)$/
|
107
|
+
const = const_set(sym, Class.new(AWS::S3.const_get($2)))
|
108
|
+
const.current_bucket = $1.underscore
|
109
|
+
const
|
110
|
+
else
|
111
|
+
const_missing_not_from_s3_library(sym)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
alias_method :const_missing_not_from_s3_library, :const_missing
|
115
|
+
alias_method :const_missing, :const_missing_from_s3_library
|
116
|
+
end
|
117
|
+
|
118
|
+
module SelectiveAttributeProxy
|
119
|
+
def self.included(klass)
|
120
|
+
klass.extend(ClassMethods)
|
121
|
+
klass.class_eval(<<-EVAL, __FILE__, __LINE__)
|
122
|
+
# Default name for attribute storage
|
123
|
+
@@attribute_proxy = :attributes
|
124
|
+
@@attribute_proxy_options = {:exclusively => true}
|
125
|
+
|
126
|
+
def self.attribute_proxy
|
127
|
+
@@attribute_proxy
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.attribute_proxy_options
|
131
|
+
@@attribute_proxy_options
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
# By default proxy all attributes
|
136
|
+
def proxiable_attribute?(name)
|
137
|
+
return true unless self.class.attribute_proxy_options[:exclusively]
|
138
|
+
send(self.class.attribute_proxy).has_key?(name)
|
139
|
+
end
|
140
|
+
|
141
|
+
def method_missing(method, *args, &block)
|
142
|
+
# Autovivify attribute storage
|
143
|
+
if method == self.class.attribute_proxy
|
144
|
+
ivar = "@\#{method}"
|
145
|
+
instance_variable_set(ivar, {}) unless instance_variable_get(ivar).is_a?(Hash)
|
146
|
+
instance_variable_get(ivar)
|
147
|
+
# Delegate to attribute storage
|
148
|
+
elsif method.to_s =~ /^(\\w+)(=?)$/ && proxiable_attribute?($1)
|
149
|
+
attributes_hash_name = self.class.attribute_proxy
|
150
|
+
$2.empty? ? send(attributes_hash_name)[$1] : send(attributes_hash_name)[$1] = args.first
|
151
|
+
else
|
152
|
+
super
|
153
|
+
end
|
154
|
+
end
|
155
|
+
EVAL
|
156
|
+
end
|
157
|
+
|
158
|
+
module ClassMethods
|
159
|
+
def proxy_to(attribute_name, options = {})
|
160
|
+
if attribute_name.is_a?(Hash)
|
161
|
+
options = attribute_name
|
162
|
+
else
|
163
|
+
class_variable_set(:@@attribute_proxy, attribute_name)
|
164
|
+
end
|
165
|
+
class_variable_set(:@@attribute_proxy_options, options)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class String
|
171
|
+
def underscore
|
172
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
173
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
174
|
+
downcase
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
class XmlGenerator < String #:nodoc:
|
179
|
+
attr_reader :xml
|
180
|
+
def initialize
|
181
|
+
@xml = Builder::XmlMarkup.new(:indent => 2, :target => self)
|
182
|
+
super()
|
183
|
+
build
|
184
|
+
end
|
185
|
+
end
|
186
|
+
#:startdoc:
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module AWS
|
2
|
+
module S3
|
3
|
+
# A bucket can be set to log the requests made on it. By default logging is turned off. You can check if a bucket has logging enabled:
|
4
|
+
#
|
5
|
+
# Bucket.logging_enabled_for? 'jukebox'
|
6
|
+
# # => false
|
7
|
+
#
|
8
|
+
# Enabling it is easy:
|
9
|
+
#
|
10
|
+
# Bucket.enable_logging_for('jukebox')
|
11
|
+
#
|
12
|
+
# Unless you specify otherwise, logs will be written to the bucket you want to log. The logs are just like any other object. By default they will start with the prefix 'log-'. You can customize what bucket you want the logs to be delivered to, as well as customize what the log objects' key is prefixed with by setting the <tt>target_bucket</tt> and <tt>target_prefix</tt> option:
|
13
|
+
#
|
14
|
+
# Bucket.enable_logging_for(
|
15
|
+
# 'jukebox', 'target_bucket' => 'jukebox-logs'
|
16
|
+
# )
|
17
|
+
#
|
18
|
+
# Now instead of logging right into the jukebox bucket, the logs will go into the bucket called jukebox-logs.
|
19
|
+
#
|
20
|
+
# Once logs have accumulated, you can access them using the <tt>log</tt> method:
|
21
|
+
#
|
22
|
+
# pp Bucket.logs('jukebox')
|
23
|
+
# [#<AWS::S3::S3Object '/jukebox-logs/log-2006-11-14-07-15-24-2061C35880A310A1'>,
|
24
|
+
# #<AWS::S3::S3Object '/jukebox-logs/log-2006-11-14-08-15-27-D8EEF536EC09E6B3'>,
|
25
|
+
# #<AWS::S3::S3Object '/jukebox-logs/log-2006-11-14-08-15-29-355812B2B15BD789'>]
|
26
|
+
#
|
27
|
+
# Disabling logging is just as simple as enabling it:
|
28
|
+
#
|
29
|
+
# Bucket.disable_logging_for('jukebox')
|
30
|
+
module Logging
|
31
|
+
# Logging status captures information about the calling bucket's logging settings. If logging is enabled for the bucket
|
32
|
+
# the status object will indicate what bucket the logs are written to via the <tt>target_bucket</tt> method as well as
|
33
|
+
# the logging key prefix with via <tt>target_prefix</tt>.
|
34
|
+
#
|
35
|
+
# See the documentation for Logging::Management::ClassMethods for more information on how to get the logging status of a bucket.
|
36
|
+
class Status
|
37
|
+
include SelectiveAttributeProxy #:nodoc:
|
38
|
+
attr_reader :enabled
|
39
|
+
alias_method :logging_enabled?, :enabled
|
40
|
+
|
41
|
+
def initialize(attributes = {}) #:nodoc:
|
42
|
+
attributes = {'target_bucket' => nil, 'target_prefix' => nil}.merge(attributes)
|
43
|
+
@enabled = attributes.has_key?('logging_enabled')
|
44
|
+
@attributes = attributes.delete('logging_enabled') || attributes
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_xml #:nodoc:
|
48
|
+
Builder.new(self).to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
attr_reader :attributes
|
53
|
+
|
54
|
+
class Builder < XmlGenerator #:nodoc:
|
55
|
+
attr_reader :logging_status
|
56
|
+
def initialize(logging_status)
|
57
|
+
@logging_status = logging_status
|
58
|
+
super()
|
59
|
+
end
|
60
|
+
|
61
|
+
def build
|
62
|
+
xml.tag!('BucketLoggingStatus', 'xmlns' => 'http://s3.amazonaws.com/doc/2006-03-01/') do
|
63
|
+
if logging_status.target_bucket && logging_status.target_prefix
|
64
|
+
xml.LoggingEnabled do
|
65
|
+
xml.TargetBucket logging_status.target_bucket
|
66
|
+
xml.TargetPrefix logging_status.target_prefix
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
module Management #:nodoc:
|
75
|
+
def self.included(klass) #:nodoc:
|
76
|
+
klass.extend(ClassMethods)
|
77
|
+
klass.extend(LoggingGrants)
|
78
|
+
end
|
79
|
+
|
80
|
+
module ClassMethods
|
81
|
+
# Returns the logging status for the bucket named <tt>name</tt>. From the logging status you can determine the bucket logs are delivered to
|
82
|
+
# and what the bucket object's keys are prefixed with. For more information see the Logging::Status class.
|
83
|
+
#
|
84
|
+
# Bucket.logging_status_for 'marcel'
|
85
|
+
def logging_status_for(name = nil, status = nil)
|
86
|
+
if name.is_a?(Status)
|
87
|
+
status = name
|
88
|
+
name = nil
|
89
|
+
end
|
90
|
+
|
91
|
+
path = path(name) << '?logging'
|
92
|
+
status ? put(path, {}, status.to_xml) : Status.new(get(path).parsed)
|
93
|
+
end
|
94
|
+
alias_method :logging_status, :logging_status_for
|
95
|
+
|
96
|
+
# Enables logging for the bucket named <tt>name</tt>. You can specify what bucket to log to with the <tt>'target_bucket'</tt> option as well
|
97
|
+
# as what prefix to add to the log files with the <tt>'target_prefix'</tt> option. Unless you specify otherwise, logs will be delivered to
|
98
|
+
# the same bucket that is being logged and will be prefixed with <tt>log-</tt>.
|
99
|
+
def enable_logging_for(name = nil, options = {})
|
100
|
+
name = bucket_name(name)
|
101
|
+
default_options = {'target_bucket' => name, 'target_prefix' => 'log-'}
|
102
|
+
options = default_options.merge(options)
|
103
|
+
grant_logging_access_to_target_bucket(options['target_bucket'])
|
104
|
+
logging_status(name, Status.new(options))
|
105
|
+
end
|
106
|
+
alias_method :enable_logging, :enable_logging_for
|
107
|
+
|
108
|
+
# Disables logging for the bucket named <tt>name</tt>.
|
109
|
+
def disable_logging_for(name = nil)
|
110
|
+
logging_status(bucket_name(name), Status.new)
|
111
|
+
end
|
112
|
+
alias_method :disable_logging, :disable_logging_for
|
113
|
+
|
114
|
+
# Returns true if logging has been enabled for the bucket named <tt>name</tt>.
|
115
|
+
def logging_enabled_for?(name = nil)
|
116
|
+
logging_status(bucket_name(name)).logging_enabled?
|
117
|
+
end
|
118
|
+
alias_method :logging_enabled?, :logging_enabled_for?
|
119
|
+
|
120
|
+
# Returns the collection of logs for the bucket named <tt>name</tt>.
|
121
|
+
#
|
122
|
+
# Bucket.logs_for 'marcel'
|
123
|
+
def logs_for(name = nil)
|
124
|
+
name = bucket_name(name)
|
125
|
+
logging_status = logging_status_for(name)
|
126
|
+
return [] unless logging_status.logging_enabled?
|
127
|
+
objects(logging_status.target_bucket, :prefix => logging_status.target_prefix)
|
128
|
+
end
|
129
|
+
alias_method :logs, :logs_for
|
130
|
+
end
|
131
|
+
|
132
|
+
module LoggingGrants #:nodoc:
|
133
|
+
def grant_logging_access_to_target_bucket(target_bucket)
|
134
|
+
acl = acl(target_bucket)
|
135
|
+
acl.grants << ACL::Grant.grant(:logging_write)
|
136
|
+
acl.grants << ACL::Grant.grant(:logging_read_acp)
|
137
|
+
acl(target_bucket, acl)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def logging_status
|
142
|
+
self.class.logging_status_for(name)
|
143
|
+
end
|
144
|
+
|
145
|
+
def enable_logging(*args)
|
146
|
+
self.class.enable_logging_for(name, *args)
|
147
|
+
end
|
148
|
+
|
149
|
+
def disable_logging(*args)
|
150
|
+
self.class.disable_logging_for(name, *args)
|
151
|
+
end
|
152
|
+
|
153
|
+
def logging_enabled?
|
154
|
+
self.class.logging_enabled_for?(name)
|
155
|
+
end
|
156
|
+
|
157
|
+
def logs
|
158
|
+
self.class.logs_for(name)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|