s33r 0.3.1 → 0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/examples/cli/acl_x.rb +41 -0
- data/examples/cli/logging_x.rb +20 -0
- data/{bin → examples/cli}/s3cli.rb +13 -20
- data/examples/fores33r/README +183 -0
- data/examples/fores33r/Rakefile +10 -0
- data/examples/fores33r/app/controllers/application.rb +4 -0
- data/examples/fores33r/app/controllers/browser_controller.rb +68 -0
- data/examples/fores33r/app/helpers/application_helper.rb +8 -0
- data/examples/fores33r/app/views/browser/index.rhtml +14 -0
- data/examples/fores33r/app/views/browser/show_bucket.rhtml +14 -0
- data/examples/fores33r/app/views/layouts/application.rhtml +29 -0
- data/examples/fores33r/config/boot.rb +44 -0
- data/examples/fores33r/config/database.yml +35 -0
- data/examples/fores33r/config/environment.rb +64 -0
- data/examples/fores33r/config/environments/development.rb +21 -0
- data/examples/fores33r/config/environments/production.rb +18 -0
- data/examples/fores33r/config/environments/test.rb +19 -0
- data/examples/fores33r/config/routes.rb +23 -0
- data/examples/fores33r/doc/README_FOR_APP +2 -0
- data/examples/fores33r/log/development.log +5507 -0
- data/examples/fores33r/log/production.log +0 -0
- data/examples/fores33r/log/server.log +0 -0
- data/examples/fores33r/log/test.log +0 -0
- data/examples/fores33r/public/404.html +8 -0
- data/examples/fores33r/public/500.html +8 -0
- data/examples/fores33r/public/dispatch.cgi +10 -0
- data/examples/fores33r/public/dispatch.fcgi +24 -0
- data/examples/fores33r/public/dispatch.rb +10 -0
- data/examples/fores33r/public/favicon.ico +0 -0
- data/examples/fores33r/public/images/rails.png +0 -0
- data/examples/fores33r/public/javascripts/application.js +2 -0
- data/examples/fores33r/public/javascripts/controls.js +815 -0
- data/examples/fores33r/public/javascripts/dragdrop.js +913 -0
- data/examples/fores33r/public/javascripts/effects.js +958 -0
- data/examples/fores33r/public/javascripts/prototype.js +2006 -0
- data/examples/fores33r/public/robots.txt +1 -0
- data/examples/fores33r/public/stylesheets/core.css +37 -0
- data/examples/fores33r/script/about +3 -0
- data/examples/fores33r/script/breakpointer +3 -0
- data/examples/fores33r/script/console +3 -0
- data/examples/fores33r/script/destroy +3 -0
- data/examples/fores33r/script/generate +3 -0
- data/examples/fores33r/script/performance/benchmarker +3 -0
- data/examples/fores33r/script/performance/profiler +3 -0
- data/examples/fores33r/script/plugin +3 -0
- data/examples/fores33r/script/process/reaper +3 -0
- data/examples/fores33r/script/process/spawner +3 -0
- data/examples/fores33r/script/runner +3 -0
- data/examples/fores33r/script/server +3 -0
- data/examples/fores33r/test/test_helper.rb +28 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.39d37e054d21d545 +0 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.acf71fc73aa74983 +0 -0
- data/examples/fores33r/tmp/sessions/ruby_sess.c1697b7d6670f3cd +0 -0
- data/examples/s3.yaml +11 -0
- data/html/classes/Net/HTTPGenericRequest.html +32 -32
- data/html/classes/Net/HTTPResponse.html +20 -19
- data/html/classes/S33r.html +422 -190
- data/html/classes/S33r/BucketListing.html +107 -70
- data/html/classes/S33r/Client.html +888 -414
- data/html/classes/S33r/LoggingResource.html +222 -0
- data/html/classes/S33r/NamedBucket.html +149 -150
- data/html/classes/S33r/OrderlyXmlMarkup.html +165 -0
- data/html/classes/S33r/S33rException.html +3 -0
- data/html/classes/S33r/S33rException/BucketNotLogTargetable.html +119 -0
- data/html/classes/S33r/S33rException/InvalidPermission.html +111 -0
- data/html/classes/S33r/S33rException/InvalidS3GroupType.html +111 -0
- data/html/classes/S33r/S3ACL.html +125 -0
- data/html/classes/S33r/S3ACL/ACLDoc.html +521 -0
- data/html/classes/S33r/{S3User.html → S3ACL/AmazonCustomer.html} +27 -30
- data/html/classes/S33r/S3ACL/CanonicalUser.html +212 -0
- data/html/classes/S33r/S3ACL/Grant.html +403 -0
- data/html/classes/S33r/S3ACL/Grantee.html +239 -0
- data/html/classes/S33r/S3ACL/Group.html +178 -0
- data/html/classes/S33r/S3Object.html +53 -50
- data/html/classes/S33r/Sync.html +6 -6
- data/html/classes/XML.html +4 -2
- data/html/created.rid +1 -1
- data/html/files/README_txt.html +82 -28
- data/html/files/lib/s33r/bucket_listing_rb.html +1 -8
- data/html/files/lib/s33r/builder_rb.html +108 -0
- data/html/files/lib/s33r/client_rb.html +2 -1
- data/html/files/lib/s33r/core_rb.html +2 -1
- data/html/files/lib/s33r/libxml_extensions_rb.html +1 -1
- data/html/files/lib/s33r/logging_rb.html +109 -0
- data/html/files/lib/s33r/named_bucket_rb.html +1 -1
- data/html/files/lib/s33r/s33r_exception_rb.html +1 -1
- data/html/files/lib/s33r/s33r_http_rb.html +1 -1
- data/html/files/lib/s33r/s3_acl_rb.html +109 -0
- data/html/fr_class_index.html +12 -1
- data/html/fr_file_index.html +3 -0
- data/html/fr_method_index.html +101 -57
- data/lib/s33r/bucket_listing.rb +21 -22
- data/lib/s33r/builder.rb +20 -0
- data/lib/s33r/client.rb +240 -42
- data/lib/s33r/core.rb +106 -36
- data/lib/s33r/libxml_extensions.rb +2 -2
- data/lib/s33r/logging.rb +43 -0
- data/lib/s33r/named_bucket.rb +16 -17
- data/lib/s33r/s33r_exception.rb +11 -0
- data/lib/s33r/s33r_http.rb +2 -1
- data/lib/s33r/s3_acl.rb +337 -0
- data/test/cases/spec_acl.rb +146 -0
- data/test/cases/spec_all_buckets.rb +28 -0
- data/test/cases/spec_bucket_listing.rb +2 -2
- data/test/cases/spec_client.rb +45 -18
- data/test/cases/spec_core.rb +0 -9
- data/test/cases/spec_namedbucket.rb +3 -3
- data/test/files/acl.xml +47 -0
- data/test/files/acl_grant1.xml +7 -0
- data/test/files/acl_grant2.xml +6 -0
- data/test/files/acl_grant3.xml +6 -0
- data/test/files/acl_grant4.xml +6 -0
- data/test/files/all_buckets.xml +21 -0
- data/test/files/bucket_listing.xml +138 -1
- data/test/files/client_config.yml +0 -1
- data/test/files/logging_acl.xml +34 -0
- data/test/files/namedbucket_config.yml +1 -5
- data/test/files/namedbucket_config2.yml +1 -5
- data/test/test_setup.rb +1 -0
- metadata +132 -7
data/lib/s33r/builder.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'builder'
|
|
2
|
+
|
|
3
|
+
module S33r
|
|
4
|
+
# Variant of XmlMarkup which explicitly orders attributes.
|
|
5
|
+
class OrderlyXmlMarkup < Builder::XmlMarkup
|
|
6
|
+
|
|
7
|
+
# Override Builder _insert_attributes so attributes are ordered.
|
|
8
|
+
def _insert_attributes(attrs, order=[])
|
|
9
|
+
return if attrs.nil?
|
|
10
|
+
order.each do |k|
|
|
11
|
+
v = attrs[k]
|
|
12
|
+
@target << %{ #{k}="#{_attr_value(v)}"} if v
|
|
13
|
+
end
|
|
14
|
+
attrs_sorted = attrs.sort { |x,y| x.to_s <=> y.to_s }
|
|
15
|
+
attrs_sorted.each do |k, v|
|
|
16
|
+
@target << %{ #{k}="#{_attr_value(v)}"} unless order.member?(k)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/s33r/client.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
require 'net/https'
|
|
2
2
|
require 'cgi'
|
|
3
|
+
require 'erb'
|
|
4
|
+
require 'yaml'
|
|
5
|
+
require File.join(File.dirname(__FILE__), 's3_acl')
|
|
6
|
+
require File.join(File.dirname(__FILE__), 's33r_exception')
|
|
3
7
|
|
|
4
8
|
module S33r
|
|
5
9
|
include Net
|
|
@@ -15,6 +19,7 @@ module S33r
|
|
|
15
19
|
class Client
|
|
16
20
|
include S33r
|
|
17
21
|
|
|
22
|
+
# S3 keys.
|
|
18
23
|
attr_accessor :aws_access_key, :aws_secret_access_key
|
|
19
24
|
|
|
20
25
|
# Size of data chunk to be sent per request when putting data.
|
|
@@ -22,6 +27,15 @@ module S33r
|
|
|
22
27
|
|
|
23
28
|
# Headers which should be sent with every request by default (unless overridden).
|
|
24
29
|
attr_accessor :client_headers
|
|
30
|
+
|
|
31
|
+
# Whether client should use SSL.
|
|
32
|
+
attr_accessor :use_ssl
|
|
33
|
+
|
|
34
|
+
# Whether client dumps headers from requests.
|
|
35
|
+
attr_accessor :dump_requests
|
|
36
|
+
|
|
37
|
+
# Default log bucket location.
|
|
38
|
+
attr_accessor :log_bucket
|
|
25
39
|
|
|
26
40
|
# Configure either an SSL-enabled or plain HTTP client.
|
|
27
41
|
# (If using SSL, no verification of server certificate is performed.)
|
|
@@ -30,20 +44,15 @@ module S33r
|
|
|
30
44
|
# * <tt>:use_ssl => false</tt>: only use plain HTTP for connections
|
|
31
45
|
# * <tt>:dump_requests => true</tt>: dump each request's initial line and headers to STDOUT
|
|
32
46
|
def initialize(aws_access_key, aws_secret_access_key, options={})
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@client.use_ssl = false
|
|
36
|
-
else
|
|
37
|
-
@client = HTTP.new(HOST, PORT)
|
|
38
|
-
# turn off SSL certificate verification
|
|
39
|
-
@client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
40
|
-
@client.use_ssl = true
|
|
41
|
-
end
|
|
47
|
+
@use_ssl = true
|
|
48
|
+
@use_ssl = false if (false == options[:use_ssl])
|
|
42
49
|
|
|
43
50
|
@dump_requests = (true == options[:dump_requests])
|
|
44
51
|
|
|
45
52
|
# set default chunk size for streaming request body
|
|
46
53
|
@chunk_size = DEFAULT_CHUNK_SIZE
|
|
54
|
+
|
|
55
|
+
@log_bucket = options[:log_bucket]
|
|
47
56
|
|
|
48
57
|
# Amazon S3 developer keys
|
|
49
58
|
@aws_access_key = aws_access_key
|
|
@@ -53,10 +62,29 @@ module S33r
|
|
|
53
62
|
@client_headers = {}
|
|
54
63
|
end
|
|
55
64
|
|
|
65
|
+
# Get an HTTP client instance.
|
|
66
|
+
#
|
|
67
|
+
# NB this has been moved here so that client instances are
|
|
68
|
+
# only instantiated when needed (so Client can be used
|
|
69
|
+
# as an empty shell when list_buckets is called).
|
|
70
|
+
def get_client
|
|
71
|
+
if @use_ssl
|
|
72
|
+
client = HTTP.new(HOST, PORT)
|
|
73
|
+
# turn off SSL certificate verification
|
|
74
|
+
client.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
75
|
+
client.use_ssl = true
|
|
76
|
+
else
|
|
77
|
+
client = HTTP.new(HOST, NON_SSL_PORT)
|
|
78
|
+
client.use_ssl = false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
client
|
|
82
|
+
end
|
|
83
|
+
|
|
56
84
|
# Initialise client from YAML configuration file
|
|
57
85
|
# (see load_config method for details of acceptable format).
|
|
58
86
|
def Client.init(config_file)
|
|
59
|
-
aws_access_key, aws_secret_access_key, options
|
|
87
|
+
aws_access_key, aws_secret_access_key, options = load_config(config_file)
|
|
60
88
|
Client.new(aws_access_key, aws_secret_access_key, options)
|
|
61
89
|
end
|
|
62
90
|
|
|
@@ -64,56 +92,56 @@ module S33r
|
|
|
64
92
|
#
|
|
65
93
|
# :include: test/files/namedbucket_config.yml
|
|
66
94
|
#
|
|
95
|
+
# Note that the loader also runs the config. file through ERB, so you can
|
|
96
|
+
# add dynamic blocks of ERB (Ruby) code into your files.
|
|
97
|
+
#
|
|
67
98
|
# The +options+ section contains settings specific to Client and NamedClient instances; +custom+
|
|
68
99
|
# contains extra settings specific to your application.
|
|
69
100
|
# +options+ and +custom+ sections can be omitted, but settings for AWS keys are required.
|
|
70
101
|
#
|
|
71
|
-
# Returns an array <tt>[aws_access_key, aws_secret_access_key, options
|
|
72
|
-
#
|
|
102
|
+
# Returns an array <tt>[aws_access_key, aws_secret_access_key, options]</tt>, where +options+
|
|
103
|
+
# is a hash.
|
|
73
104
|
def Client.load_config(config_file)
|
|
74
|
-
|
|
75
|
-
config = YAML::load_file(config_file)
|
|
105
|
+
config = YAML::load(ERB.new(IO.read(config_file)).result)
|
|
76
106
|
aws_access_key = config['aws_access_key']
|
|
77
107
|
aws_secret_access_key = config['aws_secret_access_key']
|
|
78
108
|
|
|
79
109
|
options = {}
|
|
80
110
|
options = S33r.keys_to_symbols(config['options']) if config['options']
|
|
81
111
|
|
|
82
|
-
|
|
83
|
-
custom = S33r.keys_to_symbols(config['custom']) if config['custom']
|
|
84
|
-
|
|
85
|
-
[aws_access_key, aws_secret_access_key, options, custom]
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Wrapper round embedded client +use_ssl+ accessor.
|
|
89
|
-
def use_ssl?
|
|
90
|
-
@client.use_ssl
|
|
112
|
+
[aws_access_key, aws_secret_access_key, options]
|
|
91
113
|
end
|
|
92
114
|
|
|
93
115
|
# Send a request over the wire.
|
|
94
116
|
#
|
|
95
117
|
# This method streams +data+ if it responds to the +stat+ method
|
|
96
118
|
# (as files do).
|
|
119
|
+
#
|
|
120
|
+
# Returns a Net::HTTPResponse instance.
|
|
97
121
|
def do_request(method, path, data=nil, headers={})
|
|
98
122
|
req = get_requester(method, path)
|
|
99
123
|
req.chunk_size = @chunk_size
|
|
100
124
|
|
|
101
|
-
#
|
|
125
|
+
# Add the S3 headers which are always required.
|
|
102
126
|
headers = add_default_headers(headers)
|
|
103
127
|
|
|
104
|
-
#
|
|
128
|
+
# Add any client-specific default headers.
|
|
105
129
|
headers = add_client_headers(headers)
|
|
106
130
|
|
|
131
|
+
# Generate the S3 authorization header.
|
|
107
132
|
headers['Authorization'] = generate_auth_header_value(method, path, headers,
|
|
108
133
|
@aws_access_key, @aws_secret_access_key)
|
|
109
134
|
|
|
135
|
+
# Insert the headers into the request object.
|
|
110
136
|
headers.each do |key, value|
|
|
111
137
|
req[key] = value
|
|
112
138
|
end
|
|
113
139
|
|
|
140
|
+
# Add data to the request as a stream.
|
|
114
141
|
if req.request_body_permitted?
|
|
115
|
-
#
|
|
116
|
-
# for character-based
|
|
142
|
+
# For streaming files; NB Content-Length will be set by Net::HTTP
|
|
143
|
+
# for character-based data: this section of code is only used
|
|
144
|
+
# when reading directly from a file.
|
|
117
145
|
if data.respond_to?(:stat)
|
|
118
146
|
req.body_stream = data
|
|
119
147
|
req['Content-Length'] = data.stat.size.to_s
|
|
@@ -127,9 +155,14 @@ module S33r
|
|
|
127
155
|
puts req.to_s
|
|
128
156
|
end
|
|
129
157
|
|
|
130
|
-
|
|
131
|
-
|
|
158
|
+
# Run the request.
|
|
159
|
+
client = get_client
|
|
160
|
+
client.start do
|
|
161
|
+
response = client.request(req, data)
|
|
162
|
+
|
|
163
|
+
# Check the response to see whether S3 is down.
|
|
132
164
|
response.check_s3_availability
|
|
165
|
+
|
|
133
166
|
response
|
|
134
167
|
end
|
|
135
168
|
end
|
|
@@ -141,8 +174,26 @@ module S33r
|
|
|
141
174
|
end
|
|
142
175
|
|
|
143
176
|
# List all buckets.
|
|
177
|
+
#
|
|
178
|
+
# Returns an Array of NamedBucket instances.
|
|
144
179
|
def list_buckets
|
|
145
|
-
do_get('/')
|
|
180
|
+
bucket_list_xml = do_get('/').body
|
|
181
|
+
doc = XML.get_xml_doc(S33r.remove_namespace(bucket_list_xml))
|
|
182
|
+
|
|
183
|
+
named_buckets = []
|
|
184
|
+
|
|
185
|
+
doc.find("//Bucket").to_a.each do |node|
|
|
186
|
+
bucket_name = node.xget('Name')
|
|
187
|
+
named_buckets << NamedBucket.new(@aws_access_key, @aws_secret_access_key,
|
|
188
|
+
{:default_bucket => bucket_name, :dump_request => self.dump_requests})
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
named_buckets
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# List just bucket names.
|
|
195
|
+
def list
|
|
196
|
+
list_buckets.map {|bucket| bucket.name}
|
|
146
197
|
end
|
|
147
198
|
|
|
148
199
|
# List entries in a bucket.
|
|
@@ -154,25 +205,42 @@ module S33r
|
|
|
154
205
|
# * <tt>:max_keys => 1000</tt>: return at most this number of keys (maximum possible value is 1000)
|
|
155
206
|
# * <tt>:delimiter => 'some_string'</tt>: keys containing the same string between prefix and the delimiter
|
|
156
207
|
# are rolled up into a CommonPrefixes element inside the response
|
|
208
|
+
#
|
|
209
|
+
# NB if you pass a :marker, this takes up one of your :max_keys; so if you are fetching page
|
|
210
|
+
# two from a bucket, and you want 10 items, you need to set :max_keys to 11.
|
|
211
|
+
#
|
|
212
|
+
# To page through a bucket 10 keys at a time, you can do:
|
|
213
|
+
#
|
|
214
|
+
# resp, listing = list_bucket('mybucket', :max_keys => 10)
|
|
215
|
+
# resp, listing = list_bucket('mybucket', :max_keys => 11, :marker => listing.last_key)
|
|
216
|
+
# resp, listing = list_bucket('mybucket', :max_keys => 11, :marker => listing.last_key)
|
|
217
|
+
# etc.
|
|
218
|
+
#
|
|
219
|
+
# Note in the example code, +listing+ is a BucketListing instance; call its contents method
|
|
220
|
+
# to get a hash of the keys in the bucket, along with associated objects.
|
|
221
|
+
#
|
|
222
|
+
# Returns [raw_response, BucketListing instance].
|
|
157
223
|
def list_bucket(bucket_name, query_params={})
|
|
158
224
|
if query_params[:max_keys]
|
|
159
225
|
max_keys = query_params[:max_keys].to_i
|
|
160
226
|
raise S33rException::BucketListingMaxKeysError, "max_keys option to list bucket cannot be > #{BUCKET_LIST_MAX_MAX_KEYS}" \
|
|
161
227
|
if max_keys > BUCKET_LIST_MAX_MAX_KEYS
|
|
162
228
|
|
|
163
|
-
#
|
|
229
|
+
# convert max_keys parameter to :max-keys parameter
|
|
164
230
|
query_params['max-keys'] = query_params.delete(:max_keys)
|
|
165
231
|
end
|
|
166
232
|
|
|
167
233
|
resp = do_get("/#{bucket_name}" + generate_querystring(query_params))
|
|
168
|
-
bucket_listing = BucketListing.new(resp.body)
|
|
169
234
|
|
|
170
|
-
[resp,
|
|
235
|
+
[resp, BucketListing.new(resp.body)]
|
|
171
236
|
end
|
|
172
237
|
|
|
173
238
|
# Create a bucket.
|
|
239
|
+
#
|
|
240
|
+
# Returns true if response returned a 200 code; false otherwise.
|
|
174
241
|
def create_bucket(bucket_name, headers={})
|
|
175
|
-
do_put("/#{bucket_name}", nil, headers)
|
|
242
|
+
resp = do_put("/#{bucket_name}", nil, headers)
|
|
243
|
+
resp.ok?
|
|
176
244
|
end
|
|
177
245
|
|
|
178
246
|
# Delete a bucket.
|
|
@@ -180,6 +248,7 @@ module S33r
|
|
|
180
248
|
# +options+ hash can contain the following:
|
|
181
249
|
# * <tt>:force => true</tt>: delete all keys within the bucket then delete the bucket itself
|
|
182
250
|
#-- TODO: maybe delete keys matching a partial path
|
|
251
|
+
#-- TODO: if multiple pages of keys in buckets, need to get them by page.
|
|
183
252
|
def delete_bucket(bucket_name, headers={}, options={})
|
|
184
253
|
if true == options[:force]
|
|
185
254
|
_, bucket_listing = list_bucket(bucket_name)
|
|
@@ -191,14 +260,11 @@ module S33r
|
|
|
191
260
|
do_delete("/#{bucket_name}", headers)
|
|
192
261
|
end
|
|
193
262
|
|
|
263
|
+
# Check whether a bucket exists or not.
|
|
264
|
+
#
|
|
194
265
|
# Returns true if bucket exists.
|
|
195
266
|
def bucket_exists?(bucket_name)
|
|
196
|
-
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
# Fetch head info for a key in a bucket.
|
|
200
|
-
def head_resource(bucket_name, resource_key, headers={})
|
|
201
|
-
do_head("/#{bucket_name}/#{resource_key}", headers)
|
|
267
|
+
resource_exists?(bucket_name)
|
|
202
268
|
end
|
|
203
269
|
|
|
204
270
|
# Fetch a resource.
|
|
@@ -206,10 +272,139 @@ module S33r
|
|
|
206
272
|
do_get("/#{bucket_name}/#{resource_key}", headers)
|
|
207
273
|
end
|
|
208
274
|
|
|
275
|
+
# Check whether a bucket contains a key.
|
|
276
|
+
#
|
|
277
|
+
# Returns true if resource_key exists inside bucket_name exists.
|
|
278
|
+
def resource_exists?(bucket_name, resource_key=nil)
|
|
279
|
+
path = "/#{bucket_name}"
|
|
280
|
+
path += "/#{resource_key}" unless resource_key.nil?
|
|
281
|
+
do_head(path).ok?
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Fetch an object.
|
|
285
|
+
#
|
|
209
286
|
# TODO: return S3Object
|
|
210
287
|
def get_object(bucket_name, resource_key, headers)
|
|
211
288
|
response = get_resource(bucket_name, resource_key, headers)
|
|
212
289
|
end
|
|
290
|
+
|
|
291
|
+
# Fetch the ACL document for a resource.
|
|
292
|
+
#
|
|
293
|
+
# Returns nil if there is a problem with the resource
|
|
294
|
+
# (e.g. it doesn't exist).
|
|
295
|
+
def get_acl(bucket_name, resource_key='')
|
|
296
|
+
path = s3_acl_path(bucket_name, resource_key)
|
|
297
|
+
response = do_get(path)
|
|
298
|
+
if response.ok?
|
|
299
|
+
S3ACL::ACLDoc.from_xml(response.body)
|
|
300
|
+
else
|
|
301
|
+
raise S33rException::MissingResource, "Tried to get an ACL from a non-existent resource [#{path}]"
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
# Put the ACL document for a resource.
|
|
306
|
+
#
|
|
307
|
+
# +acl_doc+ is an S33r::S3ACL::ACLDoc instance.
|
|
308
|
+
#
|
|
309
|
+
# Returns true if response had a 200 code, false otherwise.
|
|
310
|
+
# If you get a 400 Bad Request back, it means a CanonicalUser
|
|
311
|
+
# could not be identified from the email address.
|
|
312
|
+
def set_acl(acl_doc, bucket_name, resource_key='')
|
|
313
|
+
path = s3_acl_path(bucket_name, resource_key)
|
|
314
|
+
response = do_put(path, acl_doc.to_xml)
|
|
315
|
+
response.ok?
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Set up logging for a bucket and resource key.
|
|
319
|
+
#
|
|
320
|
+
# +logging_resource+ = a LoggingResource instance.
|
|
321
|
+
# +bucket_name+ = a bucket to log.
|
|
322
|
+
# +resource_key+ = a resource to log (if empty, logging
|
|
323
|
+
# gets added to the bucket).
|
|
324
|
+
def set_logging(logging_resource, bucket_name, resource_key='')
|
|
325
|
+
path = s3_logging_path(bucket_name, resource_key)
|
|
326
|
+
response = do_put(path, logging_resource.to_xml)
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Make a resource public (i.e. grant READ permissions
|
|
330
|
+
# to the AllUsers group type). NB separate method is used
|
|
331
|
+
# on buckets, to make all of their content public too.
|
|
332
|
+
#
|
|
333
|
+
# Returns nil if resource does not exist.
|
|
334
|
+
def make_public(bucket_name, resource_key='')
|
|
335
|
+
acl = get_acl(bucket_name, resource_key)
|
|
336
|
+
if !acl.nil? and acl.add_public_read_grants
|
|
337
|
+
set_acl(acl, bucket_name, resource_key)
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# TODO
|
|
342
|
+
def make_private
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
# Make a bucket capable of being a target for access logging.
|
|
346
|
+
#
|
|
347
|
+
# Returns true if the bucket is now a possible log target;
|
|
348
|
+
# false otherwise.
|
|
349
|
+
#
|
|
350
|
+
#-- TODO: tests
|
|
351
|
+
def enable_log_target(bucket_name)
|
|
352
|
+
acl = get_acl(bucket_name)
|
|
353
|
+
if acl.add_log_target_grants
|
|
354
|
+
set_acl(acl, bucket_name)
|
|
355
|
+
end
|
|
356
|
+
acl.log_targetable?
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Disable permissions for access logging into a bucket.
|
|
360
|
+
#
|
|
361
|
+
# Returns true if the bucket is no longer log targetable;
|
|
362
|
+
# false if it remains a log target.
|
|
363
|
+
#
|
|
364
|
+
#-- TODO: tests
|
|
365
|
+
def disable_log_target(bucket_name)
|
|
366
|
+
acl = get_acl(bucket_name)
|
|
367
|
+
acl.remove_log_target
|
|
368
|
+
set_acl(acl, bucket_name)
|
|
369
|
+
!acl.log_targetable?
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
# Enable logging for a resource (bucket or key).
|
|
373
|
+
#
|
|
374
|
+
# +log_prefix+ is the prefix for the logs.
|
|
375
|
+
# +bucket_name+ is the bucket to log.
|
|
376
|
+
# +log_bucket+ is the bucket to put logs into.
|
|
377
|
+
#
|
|
378
|
+
# options:
|
|
379
|
+
# +:for_key => 'key'+ is the (optional) resource to log in the bucket
|
|
380
|
+
# (NB this is not currently supported by S3).
|
|
381
|
+
# +:log_prefix => 'prefix'+ is the (optional) log file prefix
|
|
382
|
+
# (defaults to bucket_name + '-')
|
|
383
|
+
#
|
|
384
|
+
def enable_logging(bucket_name, log_bucket=nil, options={})
|
|
385
|
+
log_bucket ||= @log_bucket
|
|
386
|
+
|
|
387
|
+
resource_key = options[:for_key]
|
|
388
|
+
resource_key ||= ''
|
|
389
|
+
|
|
390
|
+
log_prefix = options[:prefix]
|
|
391
|
+
log_prefix ||= bucket_name + '-'
|
|
392
|
+
|
|
393
|
+
log_bucket_acl = get_acl(log_bucket)
|
|
394
|
+
if !(log_bucket_acl.log_targetable?)
|
|
395
|
+
raise BucketNotLogTargetable, "The bucket #{log_bucket} cannot be specified as a log target"
|
|
396
|
+
end
|
|
397
|
+
logging_resource = LoggingResource.new(log_bucket, log_prefix)
|
|
398
|
+
set_logging(logging_resource, bucket_name, resource_key)
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# TODO
|
|
402
|
+
def disable_logging
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# TODO
|
|
406
|
+
def get_logging
|
|
407
|
+
end
|
|
213
408
|
|
|
214
409
|
# Put some generic resource onto S3.
|
|
215
410
|
def put_resource(bucket_name, resource_key, data, headers={})
|
|
@@ -266,6 +461,10 @@ module S33r
|
|
|
266
461
|
end
|
|
267
462
|
|
|
268
463
|
# Delete a resource from S3.
|
|
464
|
+
#
|
|
465
|
+
# Note that S3 returns the same response code () regardless
|
|
466
|
+
# of whether the resource was successfully deleted, or didn't exist
|
|
467
|
+
# in the first place.
|
|
269
468
|
def delete_resource(bucket_name, resource_key, headers={})
|
|
270
469
|
do_delete("/#{bucket_name}/#{resource_key}", headers)
|
|
271
470
|
end
|
|
@@ -280,9 +479,8 @@ module S33r
|
|
|
280
479
|
headers.merge!(client_headers) { |key, arg, default| arg }
|
|
281
480
|
end
|
|
282
481
|
|
|
283
|
-
protected
|
|
284
482
|
def do_get(path='/', headers={})
|
|
285
|
-
do_request('GET', path, headers)
|
|
483
|
+
do_request('GET', path, nil, headers)
|
|
286
484
|
end
|
|
287
485
|
|
|
288
486
|
def do_head(path='/', headers={})
|